Fauna r4: body-Voronoi probe (Skein drawn as a diagram over the bodies, per metric); map B37-B42
Imagination probe of the operator's sketch: the bodies as Voronoi sites, the distance metric varied (power, additive, multiplicative, equal potential, flow-stretched, Minkowski), the lattice web pulled toward the edges. Images, logs and scripts in docs/research/2026-10-14-body-voronoi-probe/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4354ef2c36
commit
05a445418c
33 changed files with 428 additions and 0 deletions
|
|
@ -406,6 +406,12 @@ the lore branch `eureka/aetheria-fauna-lore` `74c7e212`, note `Open Water` (`OW`
|
|||
| B34 | Do the candidates pop under the krill carriage? (`run1.log`, `win.log`, `cyc.log`; fade .1, 60 steps of 1/60 s from t = 100, flow read at the member's cycle start, cycle turns excluded) | Largest presence step: band .0035, slack .013, skein .054, lattice .124 (8 steps over .1), skein-web .493 (8 steps). The lattice steps are not discontinuities: a traced member's web value rises .03 per step for 5 steps, a thin weighted border sweeping a fixed candidate. Widening the search window to 7x7 changes nothing; lowering the weight boost to .6 removes the lattice steps (.047); reading the lattice drift at the member's cycle start, as the flow is read, removes them at full boost: lattice .011, skein-web .066, 0 steps over .1 (`cyc.log`). |
|
||||
| B35 | How fast do hosted sets turn over? | Members changed in 1 s, all terms / flow frozen at t's cycle (wells only): band .032 / .032; skein .244 / .106; lattice .594 / .449 (.262 with the drift at cycle start); skein-web .305 / .186 (.216 with the drift at cycle start); slack .089 / .089. The strands ride their wells at about 6 u/s across 16 u candidates, so a tenth of strand members change each second through the fade: motion, not popping (B34). |
|
||||
| B36 | What does a stencil predator cost? (Python, one evaluation) | krill .26 ms, minnows 3.19 ms (9 krill), sharks 29.3 ms (81 krill): each ring-stencil level multiplies the cost by 9. Hosted: minnows 274 of 5,432 candidates at 48 u; sharks 19 of 755 at 128 u; lanterns 36 of 3,063 at 64 u. |
|
||||
| B37 | What does a diagram over the bodies draw, per metric? (`docs/research/2026-10-14-body-voronoi-probe/`, README there; sites = the six bodies, weight = each well's Gaussian width `sigma = r / sqrt(128)`, edge = first-order border distance through a 40 u Gaussian, warped as the strands) | `power` (`d^2 - sigma^2`): long, nearly straight edges spanning the zone between the bodies, a triangle of filaments (`edges_power.png`). `add` (`d - sigma`): long hyperbolic arcs, two near-parallel bars north of the sun (`edges_add.png`). `mult` (`d / sigma`): rings round the small bodies only; the sun's cell covers most of the zone (sigma ratio up to 4.7:1; the ring round a 274-mass planet is about 264 u) (`edges_mult.png`). `pot-newton` (equal `m/d`, i.e. multiplicative with weight = mass, CultLib `tape-register-model.md` 5a): rings of about 12 u, the sun swallows the zone. `pot-well` (equal depth on the zone's real well profile): rings like `mult`, plus dotted arcs where each well's compact support ends (r/2). `flow-aniso` (`mult`, across-flow distance 2.5x): edges shattered into short fragments, because the metric turns with the flow on the flow's 512 u scale. `lp05`: axis-aligned bars across the zone; `lpinf`: square cells round the small bodies. Correlation with the B20 Physarum map: mult-strands .388, power-strands .371, mult .335, flow-aniso .322, power .313, skein-web .296, add .263. |
|
||||
| B38 | Do they pop as the bodies orbit? (16 u krill, fade .1, 60 steps of 1/60 s from t = 100, flow warp and web drift at the member's cycle start, bodies now; `run2.log`, `run3.log`) | Worst presence step / members changed in 1 s / hosted: skein-web .014 / .205 / 1,501; power .029 / .312 / 3,817; power-strands .029 / .269 / 4,965; flow-aniso .037 / .300 / 4,090; pot-newton .048 / .299 / 689; add .090 / .338 / 4,077; mult .091 / .279 / 3,270; mult-strands .091 / .238 / 4,462; pot-well, lp05, lpinf 1.0 (1, 72 and 237 steps over .1). `mult`'s .091 is the web, not the edge: without the cell boost .023, without the alignment .055 (`diag2.log`); the cell weights are read from the moving edges now. |
|
||||
| B39 | Why did B34's reading pop more? (`run1.log`, `diag_edges.log`, `trace.py`) | `trophic_probe.py` reads only the flow's scroll at the member's cycle start; the slope terms (swirl 6, slide 1.5) read the wells now. The slope terms use the normalised slope direction, which turns quickly on flat ground as the wells move, and the 20 s warp is a lever on it: at a candidate on slope .019 the warped point moved 1.4 u per 1/60 s. With the whole warp at cycle start, the edges alone drop from .152 to .023 (mult) and .126 to .029 (power), and the ruled skein-web from .066 to .014. B34's skein-web number was this reading's. |
|
||||
| B40 | Where does the first-order border distance break? | Where the metric's gradient is singular or jumps: `lp05` (singular on the axes through each site), `lpinf` (jumps on the diagonals), `pot-well` (unbounded at the support rim): presence steps of 1.0. Also where the second-nearest site changes, the normaliser `|grad(F2 - F1)|` jumps: invisible inside the 40 u edge, visible in a 4x halo (power's web with no cell boost: .197-.301, `diag2.log`). A raw `F2 - F1` profile has no such jump but its width varies with the weights. |
|
||||
| B41 | Does the 5x5 lattice window hold the body-pulled weights? (`diag2.log`, 3,385 points) | Cell weights span .5-2.6 (5.2:1), and the alignment stretches across-edge distance up to 2x more. 5x5 against 7x7: mult differs at 1 point by .28; power and add at none. CultLib `lattice-site-weight.md` (`21281a39`) finds the window must grow with the weight ratio (5x5 off by .017 at about 12:1); the alignment is a query-point anisotropy, which does change winners, unlike a query-point scalar weight. |
|
||||
| B42 | What does one evaluation visit? | Every variant is pointwise over explicit sites; none needs a grid. Large layer: the 6 bodies (the two winners' gradient is analytic). Web: 25 cells, each reading the large layer at its centre (25 x 6), so 181 sites per evaluation; with strands 193 (6 soft-Gabriel edges, strand and halo); skein-web 187. Python: .36-.74 ms per evaluation. CultMath: `mult` and `power` are gap (2) as mapped; `add`, Minkowski and `flow-aniso` extend gap (2) with a metric parameter, `flow-aniso` also with a direction operand; `pot-well` is the zone's well profile as a per-site score, an Aetheria function, not a CultMath metric. The web's per-cell read of the large layer is the cell-centre weight placement of `cultmath-tapes:question:lattice-site-weight-source`. |
|
||||
|
||||
### Decisions made here, not forks
|
||||
|
||||
|
|
@ -450,6 +456,8 @@ the lore branch `eureka/aetheria-fauna-lore` `74c7e212`, note `Open Water` (`OW`
|
|||
`aetheria-fauna:question:skein-filament-construction` (which construction is the Skein; images per option in
|
||||
`docs/research/2026-10-14-trophic-dag-probe/`) and `aetheria-fauna:question:trophic-graph-tape` (hand-written CultMath
|
||||
compositions now and the tape later, or unpark the tape for this).
|
||||
`aetheria-fauna:question:body-diagram-metric` (which metric draws the large-scale Skein from the bodies, after the
|
||||
operator's sketch; images per option in `docs/research/2026-10-14-body-voronoi-probe/`, facts B37-B42).
|
||||
|
||||
### Cut sequence (r4, one line each; each is mapped when it is about to run; r3 lines 4-25 stand after line 7)
|
||||
|
||||
|
|
|
|||
54
docs/research/2026-10-14-body-voronoi-probe/README.md
Normal file
54
docs/research/2026-10-14-body-voronoi-probe/README.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Body-Voronoi probe (2026-10-14)
|
||||
|
||||
Serves the operator's sketch after `aetheria-fauna:ruling:skein-filament-construction-ruled`: "I was imagining the
|
||||
voronoi cells to be the gravity objects themselves, aren't there a bunch of fun ways to play with the distance
|
||||
metrics to get filaments that way too?" Facts are map rows B37-B42 in `docs/aetheria-fauna-map.md`. Prior art:
|
||||
CultLib `docs/research/tape-register-model.md` section 5 (`dfc720e7`) and `docs/research/lattice-site-weight.md`
|
||||
(`21281a39`).
|
||||
|
||||
`body_voronoi_probe.py` imports `trophic_probe.py` (`../2026-10-14-trophic-dag-probe/`: orbiting wells, slope terms
|
||||
on, the flow warp, the lattice web, the members and pop probes) and replaces only the large-scale filament layer.
|
||||
Same zone, same frame (t = 0), same 16 u krill candidates and thresholds, same fade .1.
|
||||
|
||||
**The large layer.** A diagram over the zone's six bodies (sites = bodies, read now), drawn as an edge profile: the
|
||||
distance to the border to first order, `(F2 - F1) / |grad(F2 - F1)|`, through a Gaussian of half-width 40 u. Each
|
||||
body's weight is its well's Gaussian width `sigma = r / sqrt(128)` (the zone's `pp(d/r)^16` term is about
|
||||
`exp(-d^2 / 2 sigma^2)`): sun 482 u, planets 180, 180, 146, 103, gas giant 305. Bent by the same flow warp as the
|
||||
strands (20 s).
|
||||
|
||||
| Variant | Metric `d_i` |
|
||||
|---|---|
|
||||
| `pot-well` | Equal well depth on the zone's real profile: `-ln(depth_i * pp(d/r_i)^16)` |
|
||||
| `pot-newton` | Equal point-mass potential `m/d`: multiplicative with weight = mass (section 5a's identity) |
|
||||
| `mult` | `d / sigma_i`: Apollonius circles, her shader's trick |
|
||||
| `add` | `d - sigma_i`: hyperbola arcs |
|
||||
| `power` | `d^2 - sigma_i^2`: straight edges, the adhesion model's tiling |
|
||||
| `flow-aniso` | `mult` with the across-flow component stretched 2.5x; the flow direction is the warp's own |
|
||||
| `lp05`, `lpinf` | `mult` in the Minkowski p = .5 and p = inf (Chebyshev) norms, axis-aligned |
|
||||
| `skein-web` | Control: the ruled Skein (`trophic_probe.py`), strands plus web |
|
||||
| `mult-strands`, `power-strands` | The diagram's edges and the strands together, with the web |
|
||||
|
||||
**The web.** `trophic_probe.lattice_web` with two changes: each lattice cell's hash weight is raised by up to 1.6x by
|
||||
the large-edge profile (3x wider) at the cell centre, `(cx + .5) * LAT` (cell-centre weight in
|
||||
`lattice-site-weight.md`'s terms; `trophic_probe.py`'s well proximity is also read at the cell centre, not at the
|
||||
jittered site), and the cell metric is stretched up to 2x across the large edge's normal at the query point, so cells
|
||||
shrink and align along the edges. The web hangs within 4 edge widths of a large edge, or on the band.
|
||||
|
||||
Images (zone 4,000 u across, red = bodies): `density_<variant>.png` (krill habitat density, t = 0),
|
||||
`members_<variant>.png` (hosted krill candidates), `edges_<variant>.png` (the large layer alone, no web; also for the
|
||||
pruned variants).
|
||||
|
||||
Logs:
|
||||
- `run1.log`: all variants as `trophic_probe.py` reads the flow (scroll at the member's cycle start, the slope terms
|
||||
with the wells now). `run2.log` and `run3.log` (`power-strands`): the whole warp at cycle start, slope terms
|
||||
included (`WARP_AT_CYCLE=1`). The member images here are run 2 and 3's.
|
||||
- `diag_edges.log`: the large layer alone, run-1 reading. `trace.py`: the worst step traced to the warped point
|
||||
moving 1.4 u per 1/60 s.
|
||||
- `diag2.log` (run-2 reading): web ablation (boost, align) and the lattice window, 5x5 against 7x7.
|
||||
|
||||
To rerun: copy this folder, `../2026-10-14-trophic-dag-probe/trophic_probe.py` and
|
||||
`../2026-10-14-fauna-habitat-probe/habitat_probe.py` into one scratch directory, then
|
||||
`py -3 -u body_voronoi_probe.py 256` (about 15 minutes), the same with `WARP_AT_CYCLE=1` (writes into `cyc/`),
|
||||
`py -3 -u diag.py` with `DIAG=edges`, and `WARP_AT_CYCLE=1 py -3 -u diag2.py`. `habitat_probe.py` reads the B20 map
|
||||
from `C:\aeth-wt\fauna-target-r3\docs\research\2026-10-13-fauna-placement-probe\output.txt`. Python 3 only, no
|
||||
packages. Hashes are the probe's own integer hash, not CultMath `pcg3d`; the images are qualitative evidence.
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
"""Body-Voronoi probe (Imagination, aetheria-fauna r4). Pure Python 3, no packages.
|
||||
|
||||
The operator's sketch after skein-web was ruled: the Voronoi cells are the gravity bodies themselves, and the
|
||||
distance metric is the place to play. The large-scale filament layer here is a diagram over the zone's bodies
|
||||
(sites = bodies, orbiting), drawn as an F2 - F1 edge profile: distance to the border to first order,
|
||||
(F2 - F1) / |grad(F2 - F1)| through a Gaussian of width EW_U. The lattice web of trophic_probe.py hangs off it, its
|
||||
per-site weight boosted by the large edge's profile at each lattice site (cells shrink near the edges) and its
|
||||
metric stretched across the edge normal at the query point (cells align along the edges).
|
||||
|
||||
Reuses trophic_probe.py (orbiting wells, slope terms on, the flow warp, the lattice web, members and pop probes) and
|
||||
habitat_probe.py (Zone.GetHeight/GetNormal and FlowField transliterations). Hashes are the probe's own.
|
||||
|
||||
py -3 -u body_voronoi_probe.py [grid=256] [only=comma,list]
|
||||
"""
|
||||
import sys, os, math, time
|
||||
ARGS = sys.argv[1:]
|
||||
sys.argv = [sys.argv[0], "256"]
|
||||
import trophic_probe as T
|
||||
H = T.H
|
||||
|
||||
OUT = os.path.dirname(os.path.abspath(__file__))
|
||||
G = int(ARGS[0]) if ARGS else 256
|
||||
ONLY = ARGS[1].split(",") if len(ARGS) > 1 else None
|
||||
T.WEB_AT_CYCLE = True # ruled with skein-web: flow and web drift read at the member's cycle start
|
||||
EW_U = 40.0 # large edge half-width (u)
|
||||
HALO = 4.0 # web hangs within this many edge widths of a large edge (or on the band)
|
||||
ANISO = 2.5 # flow-stretched metric: distance across the flow counts this many times more
|
||||
ALIGN = 1.0 # lattice cells: across-edge component stretched by up to 1 + ALIGN near a large edge
|
||||
VISITS = [0] # sites visited per evaluation (the CultMath cost measure)
|
||||
|
||||
# sigma: each well's Gaussian width. Zone's term pp(d/r)^16 = (1 - 4 d^2/r^2)^16 ~ exp(-64 d^2/r^2) = exp(-d^2 / 2 s^2)
|
||||
SIG = [w["r"] / math.sqrt(128.0) for w in H.WELLS]
|
||||
MASS = [b[1] for b in H.BODIES]
|
||||
|
||||
# ---------------- per-site metrics: d_i(q, flow direction) ----------------
|
||||
def m_mult(i, dx, dz, fd): VISITS[0] += 1; return math.hypot(dx, dz) / SIG[i]
|
||||
def m_add(i, dx, dz, fd): VISITS[0] += 1; return math.hypot(dx, dz) - SIG[i]
|
||||
def m_power(i, dx, dz, fd): VISITS[0] += 1; return dx * dx + dz * dz - SIG[i] ** 2
|
||||
def m_newton(i, dx, dz, fd): VISITS[0] += 1; return math.hypot(dx, dz) / MASS[i] # potential m/d equal: w = mass
|
||||
def m_well(i, dx, dz, fd):
|
||||
"""Equal well depth on the zone's real profile: depth_i * pp(d/r_i)^16 equal (its log, so smaller is deeper)."""
|
||||
VISITS[0] += 1; w = H.WELLS[i]; u = 4 * (dx * dx + dz * dz) / w["r"] ** 2
|
||||
return 1e9 if u >= 1 else -(math.log(w["depth"]) + w["exp"] * math.log(1 - u))
|
||||
def m_aniso(i, dx, dz, fd):
|
||||
VISITS[0] += 1; a = dx * fd[0] + dz * fd[1]; c = -dx * fd[1] + dz * fd[0]
|
||||
return math.sqrt(a * a + (ANISO * c) ** 2) / SIG[i]
|
||||
def m_lp(p):
|
||||
def f(i, dx, dz, fd):
|
||||
VISITS[0] += 1
|
||||
if p == math.inf: return max(abs(dx), abs(dz)) / SIG[i]
|
||||
return (abs(dx) ** p + abs(dz) ** p) ** (1 / p) / SIG[i]
|
||||
return f
|
||||
|
||||
def body_border(q, metric, fd=(1.0, 0.0)):
|
||||
"""Distance (u) from q to the nearest border of the body diagram under `metric`, first order, and the border's
|
||||
unit normal (grad of F2 - F1). Visits every body once; the gradient re-evaluates only the two winners."""
|
||||
ds = sorted((metric(i, q[0] - w["pos"][0], q[1] - w["pos"][1], fd), i) for i, w in enumerate(H.WELLS))
|
||||
(d1, i1), (d2, i2) = ds[0], ds[1]
|
||||
if d2 >= 1e8: return 1e9, (1.0, 0.0)
|
||||
def g(x, z):
|
||||
a, b = H.WELLS[i1]["pos"], H.WELLS[i2]["pos"]
|
||||
return metric(i2, x - b[0], z - b[1], fd) - metric(i1, x - a[0], z - a[1], fd)
|
||||
e = 1.0; v = VISITS[0]
|
||||
gx = (g(q[0] + e, q[1]) - g(q[0] - e, q[1])) / (2 * e); gz = (g(q[0], q[1] + e) - g(q[0], q[1] - e)) / (2 * e)
|
||||
VISITS[0] = v # the gradient is analytic in C#; the probe's finite difference is not counted
|
||||
gl = math.hypot(gx, gz) or 1e-9
|
||||
return (d2 - d1) / gl, (gx / gl, gz / gl)
|
||||
|
||||
def edge_profile(dist, widen=1.0): return math.exp(-(dist / (EW_U * widen)) ** 2)
|
||||
|
||||
# ---------------- the lattice web, weights pulled toward the large edges ----------------
|
||||
SITE_W = {} # per tick: lattice site -> large-edge profile at its centre (cleared by set_time)
|
||||
_set_time = T.set_time
|
||||
def set_time(t): SITE_W.clear(); _set_time(t)
|
||||
T.set_time = set_time
|
||||
|
||||
def lattice_web_edges(q, t, metric, near, nrm):
|
||||
"""trophic_probe.lattice_web with the well-proximity boost replaced by the large-edge profile at each lattice
|
||||
site, and the cell metric stretched by (1 + ALIGN * near) across the large edge's normal at the query point."""
|
||||
if T.CUR_T0[0] is not None: t = T.CUR_T0[0]
|
||||
LAT = T.LAT; px, pz = q[0] / LAT, q[1] / LAT; nx, nz = math.floor(px), math.floor(pz); fx, fz = px - nx, pz - nz
|
||||
st = 1.0 + ALIGN * near; m = 8.0; f1 = 8.0; f2 = 8.0; KW = T.KW
|
||||
for j in range(-T.WIN, T.WIN + 1):
|
||||
for i in range(-T.WIN, T.WIN + 1):
|
||||
cx, cz = nx + i, nz + j; VISITS[0] += 1
|
||||
ox, oz = H.hash01(cx, cz, 11), H.hash01(cx, cz, 12); wt = ox * .5 + .5
|
||||
key = (cx, cz, metric)
|
||||
if key not in SITE_W:
|
||||
SITE_W[key] = edge_profile(body_border(((cx + .5) * LAT, (cz + .5) * LAT), metric)[0], 3.0)
|
||||
else: VISITS[0] += len(H.WELLS) # count the per-site evaluation even when the probe memoises it
|
||||
wt *= 1.0 + T.BOOST * SITE_W[key]
|
||||
ox = .5 + .5 * math.sin(T.OMEGA * t + 6.2831 * ox); oz = .5 + .5 * math.sin(T.OMEGA * t + 6.2831 * oz)
|
||||
vx, vz = i - fx + ox, j - fz + oz
|
||||
a = vx * nrm[0] + vz * nrm[1]; c = -vx * nrm[1] + vz * nrm[0]
|
||||
d = math.hypot(st * a, c) * wt
|
||||
if d < f1: f1, f2 = d, f1
|
||||
elif d < f2: f2 = d
|
||||
h = T.smooth(0.0, 1.0, .5 + .5 * (m - d) / KW)
|
||||
m = m + (d - m) * h - h * (1 - h) * KW / (1 + 3 * KW)
|
||||
gap0 = .25 * KW / (1 + 3 * KW)
|
||||
soft = max(0.0, min(1.0, (f1 - m) / gap0))
|
||||
return max(soft ** 2, math.exp(-((f2 - f1) / T.EW) ** 2))
|
||||
|
||||
WARP_AT_CYCLE = os.environ.get("WARP_AT_CYCLE") == "1"
|
||||
_warp = T.warp
|
||||
if WARP_AT_CYCLE: OUT = os.path.join(OUT, "cyc"); os.makedirs(OUT, exist_ok=True)
|
||||
def warp(x, z, t, sc, tau=None):
|
||||
"""WARP_AT_CYCLE=1: the whole flow warp at the member's cycle start, slope terms included (the wells at t0).
|
||||
trophic_probe reads only the scroll at cycle start; its slope terms read the wells now (B34's runs)."""
|
||||
t0 = T.CUR_T0[0]
|
||||
if not WARP_AT_CYCLE or t0 is None: return _warp(x, z, t, sc, tau)
|
||||
keep = [w["pos"] for w in H.WELLS]
|
||||
for (kind, m, d, ph), w in zip(H.BODIES, H.WELLS):
|
||||
a = ph + (2 * math.pi * t0 / d if d > 0 else 0.0); w["pos"] = (math.cos(a) * d, math.sin(a) * d)
|
||||
try: return _warp(x, z, t0, sc, tau)
|
||||
finally:
|
||||
for w, p in zip(H.WELLS, keep): w["pos"] = p
|
||||
T.warp = warp
|
||||
|
||||
def flow_dir_of(x, z, q):
|
||||
"""The flow direction the warp used: u = (x - q) / TAU, so it is read when the warp is."""
|
||||
ux, uz = x - q[0], z - q[1]; l = math.hypot(ux, uz) or 1e-9; return ux / l, uz / l
|
||||
|
||||
def flow_dir(x, z, t, sc):
|
||||
ux, uz = T.flow_at(x, z, t, sc); l = math.hypot(ux, uz) or 1e-9; return ux / l, uz / l
|
||||
|
||||
def body_web(metric, strands=False):
|
||||
def D(x, z, t, sc):
|
||||
s, b, c = T.env(x, z, t); q = T.warp(x, z, t, sc)
|
||||
fd = flow_dir_of(x, z, q) if metric is m_aniso else (1.0, 0.0)
|
||||
dist, nrm = body_border(q, metric, fd); e = edge_profile(dist); halo = edge_profile(dist, HALO)
|
||||
big = e; near = halo
|
||||
if strands:
|
||||
st = T.strands(q); sh = T.strands(q, widen=4.0); VISITS[0] += 2 * len(T.pairs(False))
|
||||
big = max(e, st); near = max(halo, sh)
|
||||
web = lattice_web_edges(T.warp(x, z, t, sc, T.WEB_TAU), t, metric, halo, nrm) * max(near, b)
|
||||
return max(big, .8 * web) * (1 - c)
|
||||
return D
|
||||
|
||||
def skein_web_counted(x, z, t, sc):
|
||||
VISITS[0] += 2 * len(T.pairs(False)) + 25 * (1 + len(H.WELLS)); return T.D_skein_web(x, z, t, sc)
|
||||
|
||||
VARIANTS = {
|
||||
"pot-well": body_web(m_well), "pot-newton": body_web(m_newton), "mult": body_web(m_mult),
|
||||
"add": body_web(m_add), "power": body_web(m_power), "flow-aniso": body_web(m_aniso),
|
||||
"lp05": body_web(m_lp(.5)), "lpinf": body_web(m_lp(math.inf)),
|
||||
"skein-web": skein_web_counted, "mult-strands": body_web(m_mult, strands=True),
|
||||
"power-strands": body_web(m_power, strands=True),
|
||||
}
|
||||
|
||||
def run(name, fn, cands, t=0.0):
|
||||
t1 = time.time(); vals = T.grid(fn, t, G); T.save(vals, os.path.join(OUT, "density_" + name), G)
|
||||
cr = T.phys_corr(vals, G)
|
||||
a = T.members(fn, cands, t); b = T.members(fn, cands, t + 1); n = max(1, len(a))
|
||||
W2 = 600; px = [(10, 14, 30)] * (W2 * W2)
|
||||
for c in cands:
|
||||
if (c[0], c[1]) in a:
|
||||
i, j = int((c[2] / (2 * H.R) + .5) * W2), int((c[3] / (2 * H.R) + .5) * W2)
|
||||
if 0 <= i < W2 and 0 <= j < W2: px[j * W2 + i] = (235, 230, 170)
|
||||
H.mark_bodies(px, W2); H.write_png(os.path.join(OUT, "members_" + name + ".png"), W2, W2, px)
|
||||
worst, big, nn = T.pop_probe(fn, cands, 100.0, 1500)
|
||||
T.set_time(0.0); sc = H.scroll(0.0); VISITS[0] = 0; SITE_W.clear(); k = 40
|
||||
c0 = time.perf_counter()
|
||||
for m in range(k): SITE_W.clear(); fn(300.0 + 7 * m, 200.0 - 5 * m, 0.0, sc)
|
||||
ms = (time.perf_counter() - c0) / k * 1e3
|
||||
print(f"{name}: corr physarumA {cr:.3f}; members {len(a)}; changed in 1 s {len(a ^ b) / n:.3f}; "
|
||||
f"presence step max {worst:.4f} ({big} steps > .1 of {nn}); sites visited per evaluation {VISITS[0] / k:.0f}; "
|
||||
f"{ms:.2f} ms/eval (Python); {time.time() - t1:.0f}s", flush=True)
|
||||
|
||||
def main():
|
||||
print(f"warp at cycle start {WARP_AT_CYCLE}; grid {G}; sigma {[round(s) for s in SIG]}; edge width {EW_U} u; web at cycle start {T.WEB_AT_CYCLE}", flush=True)
|
||||
cands = T.cand_list(16.0)
|
||||
for name, fn in VARIANTS.items():
|
||||
if ONLY and name not in ONLY: continue
|
||||
run(name, fn, cands)
|
||||
|
||||
if __name__ == "__main__": main()
|
||||
BIN
docs/research/2026-10-14-body-voronoi-probe/density_add.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/density_add.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/density_flow-aniso.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/density_flow-aniso.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/density_mult-strands.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/density_mult-strands.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/density_mult.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/density_mult.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/density_power-strands.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/density_power-strands.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/density_power.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/density_power.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/density_skein-web.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/density_skein-web.png
(Stored with Git LFS)
Normal file
Binary file not shown.
28
docs/research/2026-10-14-body-voronoi-probe/diag.py
Normal file
28
docs/research/2026-10-14-body-voronoi-probe/diag.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
"""Diagnostics: where the presence steps over .1 come from, and the large layer alone (edges_<name>.png)."""
|
||||
import sys; sys.argv = ['x', '256']
|
||||
import body_voronoi_probe as B
|
||||
T, H = B.T, B.H
|
||||
mode = sys.argv[1:] or []
|
||||
cands = T.cand_list(16.0)
|
||||
def edges_only(metric):
|
||||
def D(x, z, t, sc):
|
||||
s, b, c = T.env(x, z, t); q = T.warp(x, z, t, sc)
|
||||
fd = B.flow_dir_of(x, z, q) if metric is B.m_aniso else (1.0, 0.0)
|
||||
return B.edge_profile(B.body_border(q, metric, fd)[0]) * (1 - c)
|
||||
return D
|
||||
MET = {"pot-well": B.m_well, "pot-newton": B.m_newton, "mult": B.m_mult, "add": B.m_add, "power": B.m_power,
|
||||
"flow-aniso": B.m_aniso, "lp05": B.m_lp(.5), "lpinf": B.m_lp(float('inf'))}
|
||||
import os
|
||||
which = os.environ.get("DIAG", "edges")
|
||||
if which == "edges":
|
||||
for n, m in MET.items():
|
||||
f = edges_only(m); vals = T.grid(f, 0.0, 256); T.save(vals, os.path.join(B.OUT, "edges_" + n), 256)
|
||||
w, big, nn = T.pop_probe(f, cands, 100.0, 1500)
|
||||
print(f"edges-only {n}: presence step max {w:.4f} ({big} steps > .1 of {nn})", flush=True)
|
||||
else:
|
||||
for boost, align in ((0.0, 1.0), (1.6, 0.0), (0.0, 0.0)):
|
||||
T.BOOST, B.ALIGN = boost, align
|
||||
for n in ("mult", "power"):
|
||||
w, big, nn = T.pop_probe(B.VARIANTS[n], cands, 100.0, 1500)
|
||||
print(f"BOOST {boost} ALIGN {align} {n}: presence step max {w:.4f} ({big} steps > .1 of {nn})", flush=True)
|
||||
print("diag done", flush=True)
|
||||
11
docs/research/2026-10-14-body-voronoi-probe/diag2.log
Normal file
11
docs/research/2026-10-14-body-voronoi-probe/diag2.log
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
BOOST 0.0 ALIGN 1.0 mult: presence step max 0.0234 (0 steps > .1 of 1500)
|
||||
BOOST 0.0 ALIGN 1.0 power: presence step max 0.3012 (2 steps > .1 of 1500)
|
||||
BOOST 1.6 ALIGN 0.0 mult: presence step max 0.0545 (0 steps > .1 of 1500)
|
||||
BOOST 1.6 ALIGN 0.0 power: presence step max 0.0287 (0 steps > .1 of 1500)
|
||||
BOOST 0.0 ALIGN 0.0 mult: presence step max 0.0234 (0 steps > .1 of 1500)
|
||||
BOOST 0.0 ALIGN 0.0 power: presence step max 0.1970 (1 steps > .1 of 1500)
|
||||
window mult: WIN 2 vs 3 max |diff| 0.2794, points differing > .01: 1 of 3385
|
||||
window power: WIN 2 vs 3 max |diff| 0.0000, points differing > .01: 0 of 3385
|
||||
window add: WIN 2 vs 3 max |diff| 0.0000, points differing > .01: 0 of 3385
|
||||
site boost profile range 0.000..1.000: weight range .5*(1+1.6*min) .. 1.0*(1+1.6*max) = 0.50..2.60, ratio 5.2:1; with ALIGN the across-edge distance is stretched up to 2.0x more
|
||||
diag2 done
|
||||
26
docs/research/2026-10-14-body-voronoi-probe/diag2.py
Normal file
26
docs/research/2026-10-14-body-voronoi-probe/diag2.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"""Run with WARP_AT_CYCLE=1. (a) Which part of the web pops: BOOST/ALIGN ablation on mult and power.
|
||||
(b) Lattice search window against the body-pulled weight range: WIN 2 vs WIN 3 on the density at 4,000 points."""
|
||||
import os, sys, math; sys.argv = ['x', '256']
|
||||
import body_voronoi_probe as B
|
||||
T, H = B.T, B.H
|
||||
cands = T.cand_list(16.0)
|
||||
for boost, align in ((0.0, 1.0), (1.6, 0.0), (0.0, 0.0)):
|
||||
T.BOOST, B.ALIGN = boost, align
|
||||
for n in ("mult", "power"):
|
||||
w, big, nn = T.pop_probe(B.VARIANTS[n], cands, 100.0, 1500)
|
||||
print(f"BOOST {boost} ALIGN {align} {n}: presence step max {w:.4f} ({big} steps > .1 of {nn})", flush=True)
|
||||
T.BOOST, B.ALIGN = 1.6, 1.0
|
||||
T.set_time(0.0); sc = H.scroll(0.0)
|
||||
pts = [(((k * 0.6180339887) % 1 - .5) * 2 * H.R * .95, ((k * 0.7548776662) % 1 - .5) * 2 * H.R * .95) for k in range(4000)]
|
||||
pts = [p for p in pts if p[0] ** 2 + p[1] ** 2 < H.R ** 2]
|
||||
wmin, wmax = 9, 0
|
||||
for n in ("mult", "power", "add"):
|
||||
f = B.VARIANTS[n]; T.WIN = 2; a = [f(x, z, 0.0, sc) for x, z in pts]
|
||||
T.WIN = 3; b = [f(x, z, 0.0, sc) for x, z in pts]; T.WIN = 2
|
||||
d = [abs(u - v) for u, v in zip(a, b)]
|
||||
print(f"window {n}: WIN 2 vs 3 max |diff| {max(d):.4f}, points differing > .01: {sum(x > .01 for x in d)} of {len(d)}", flush=True)
|
||||
ws = [v for v in B.SITE_W.values()]
|
||||
print(f"site boost profile range {min(ws):.3f}..{max(ws):.3f}: weight range .5*(1+1.6*min) .. 1.0*(1+1.6*max) = "
|
||||
f"{.5 * (1 + 1.6 * min(ws)):.2f}..{1 + 1.6 * max(ws):.2f}, ratio {(1 + 1.6 * max(ws)) / (.5 * (1 + 1.6 * min(ws))):.1f}:1; "
|
||||
f"with ALIGN the across-edge distance is stretched up to {1 + B.ALIGN:.1f}x more", flush=True)
|
||||
print("diag2 done", flush=True)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
edges-only pot-well: presence step max 1.0000 (2 steps > .1 of 1500)
|
||||
edges-only pot-newton: presence step max 0.1869 (6 steps > .1 of 1500)
|
||||
edges-only mult: presence step max 0.1522 (6 steps > .1 of 1500)
|
||||
edges-only add: presence step max 0.1903 (8 steps > .1 of 1500)
|
||||
edges-only power: presence step max 0.1260 (9 steps > .1 of 1500)
|
||||
edges-only flow-aniso: presence step max 0.1645 (30 steps > .1 of 1500)
|
||||
edges-only lp05: presence step max 1.0000 (100 steps > .1 of 1500)
|
||||
edges-only lpinf: presence step max 0.5637 (34 steps > .1 of 1500)
|
||||
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_add.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_add.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_flow-aniso.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_flow-aniso.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_lp05.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_lp05.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_lpinf.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_lpinf.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_mult.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_mult.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_pot-newton.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_pot-newton.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_pot-well.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_pot-well.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_power.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/edges_power.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/members_add.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/members_add.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/members_flow-aniso.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/members_flow-aniso.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/members_mult-strands.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/members_mult-strands.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/members_mult.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/members_mult.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/members_power-strands.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/members_power-strands.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/members_power.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/members_power.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/research/2026-10-14-body-voronoi-probe/members_skein-web.png
(Stored with Git LFS)
Normal file
BIN
docs/research/2026-10-14-body-voronoi-probe/members_skein-web.png
(Stored with Git LFS)
Normal file
Binary file not shown.
11
docs/research/2026-10-14-body-voronoi-probe/run1.log
Normal file
11
docs/research/2026-10-14-body-voronoi-probe/run1.log
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
grid 256; sigma [482, 180, 180, 305, 146, 103]; edge width 40.0 u; web at cycle start True
|
||||
pot-well: corr physarumA 0.279; members 3566; changed in 1 s 0.327; presence step max 1.0000 (1 steps > .1 of 1500); sites visited per evaluation 181; 0.76 ms/eval (Python); 85s
|
||||
pot-newton: corr physarumA 0.338; members 683; changed in 1 s 0.318; presence step max 0.1869 (8 steps > .1 of 1500); sites visited per evaluation 181; 0.65 ms/eval (Python); 90s
|
||||
mult: corr physarumA 0.335; members 3280; changed in 1 s 0.296; presence step max 0.1522 (8 steps > .1 of 1500); sites visited per evaluation 181; 0.52 ms/eval (Python); 86s
|
||||
add: corr physarumA 0.263; members 4088; changed in 1 s 0.347; presence step max 0.1144 (7 steps > .1 of 1500); sites visited per evaluation 181; 0.54 ms/eval (Python); 88s
|
||||
power: corr physarumA 0.313; members 3866; changed in 1 s 0.306; presence step max 0.1260 (9 steps > .1 of 1500); sites visited per evaluation 181; 0.65 ms/eval (Python); 88s
|
||||
flow-aniso: corr physarumA 0.322; members 4076; changed in 1 s 0.311; presence step max 0.1645 (22 steps > .1 of 1500); sites visited per evaluation 181; 0.62 ms/eval (Python); 99s
|
||||
lp05: corr physarumA 0.274; members 6682; changed in 1 s 0.307; presence step max 1.0000 (115 steps > .1 of 1500); sites visited per evaluation 181; 0.87 ms/eval (Python); 88s
|
||||
lpinf: corr physarumA 0.307; members 3756; changed in 1 s 0.282; presence step max 1.0000 (237 steps > .1 of 1500); sites visited per evaluation 181; 0.66 ms/eval (Python); 87s
|
||||
skein-web: corr physarumA 0.296; members 1475; changed in 1 s 0.216; presence step max 0.0656 (0 steps > .1 of 1500); sites visited per evaluation 187; 0.41 ms/eval (Python); 110s
|
||||
mult-strands: corr physarumA 0.388; members 4443; changed in 1 s 0.248; presence step max 0.1522 (8 steps > .1 of 1500); sites visited per evaluation 193; 0.73 ms/eval (Python); 99s
|
||||
11
docs/research/2026-10-14-body-voronoi-probe/run2.log
Normal file
11
docs/research/2026-10-14-body-voronoi-probe/run2.log
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
warp at cycle start True; grid 256; sigma [482, 180, 180, 305, 146, 103]; edge width 40.0 u; web at cycle start True
|
||||
pot-well: corr physarumA 0.279; members 3588; changed in 1 s 0.326; presence step max 1.0000 (1 steps > .1 of 1500); sites visited per evaluation 181; 0.65 ms/eval (Python); 86s
|
||||
pot-newton: corr physarumA 0.338; members 689; changed in 1 s 0.299; presence step max 0.0483 (0 steps > .1 of 1500); sites visited per evaluation 181; 0.60 ms/eval (Python); 84s
|
||||
mult: corr physarumA 0.335; members 3270; changed in 1 s 0.279; presence step max 0.0910 (0 steps > .1 of 1500); sites visited per evaluation 181; 0.51 ms/eval (Python); 85s
|
||||
add: corr physarumA 0.263; members 4077; changed in 1 s 0.338; presence step max 0.0899 (0 steps > .1 of 1500); sites visited per evaluation 181; 0.50 ms/eval (Python); 84s
|
||||
power: corr physarumA 0.313; members 3817; changed in 1 s 0.312; presence step max 0.0287 (0 steps > .1 of 1500); sites visited per evaluation 181; 0.74 ms/eval (Python); 85s
|
||||
flow-aniso: corr physarumA 0.322; members 4090; changed in 1 s 0.300; presence step max 0.0373 (0 steps > .1 of 1500); sites visited per evaluation 181; 0.66 ms/eval (Python); 88s
|
||||
lp05: corr physarumA 0.274; members 6662; changed in 1 s 0.306; presence step max 1.0000 (72 steps > .1 of 1500); sites visited per evaluation 181; 0.74 ms/eval (Python); 87s
|
||||
lpinf: corr physarumA 0.307; members 3761; changed in 1 s 0.275; presence step max 1.0000 (237 steps > .1 of 1500); sites visited per evaluation 181; 0.61 ms/eval (Python); 85s
|
||||
skein-web: corr physarumA 0.296; members 1501; changed in 1 s 0.205; presence step max 0.0138 (0 steps > .1 of 1500); sites visited per evaluation 187; 0.36 ms/eval (Python); 106s
|
||||
mult-strands: corr physarumA 0.388; members 4462; changed in 1 s 0.238; presence step max 0.0910 (0 steps > .1 of 1500); sites visited per evaluation 193; 0.62 ms/eval (Python); 89s
|
||||
2
docs/research/2026-10-14-body-voronoi-probe/run3.log
Normal file
2
docs/research/2026-10-14-body-voronoi-probe/run3.log
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
warp at cycle start True; grid 256; sigma [482, 180, 180, 305, 146, 103]; edge width 40.0 u; web at cycle start True
|
||||
power-strands: corr physarumA 0.371; members 4965; changed in 1 s 0.269; presence step max 0.0287 (0 steps > .1 of 1500); sites visited per evaluation 193; 0.60 ms/eval (Python); 88s
|
||||
26
docs/research/2026-10-14-body-voronoi-probe/trace.py
Normal file
26
docs/research/2026-10-14-body-voronoi-probe/trace.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"""Trace the worst presence step of the edges-only layer: where it is and what moves."""
|
||||
import sys, os, math; sys.argv = ['x', '256']
|
||||
import body_voronoi_probe as B
|
||||
T, H = B.T, B.H
|
||||
cands = T.cand_list(16.0)
|
||||
name = os.environ.get("M", "mult"); met = {"mult": B.m_mult, "power": B.m_power, "add": B.m_add}[name]
|
||||
def f(x, z, t, sc):
|
||||
s, b, c = T.env(x, z, t); q = T.warp(x, z, t, sc); return B.edge_profile(B.body_border(q, met)[0]) * (1 - c), q
|
||||
T.set_time(100.0)
|
||||
near = [c for c in cands if abs(T.density_at(lambda x, z, t, sc: f(x, z, t, sc)[0], c, 100.0)[0] - c[4]) < .3][:1500]
|
||||
best = (0, None)
|
||||
prev = {}
|
||||
for k in range(61):
|
||||
tt = 100 + k / 60; T.set_time(tt)
|
||||
for c in near:
|
||||
sc, t0 = T.cyc_scroll(tt, c[5]); d, q = f(c[2], c[3], tt, sc); p = T.presence(d, c[4])
|
||||
if c in prev and prev[c][1] == t0:
|
||||
st = abs(p - prev[c][0])
|
||||
if st > best[0]: best = (st, c, k, d, prev[c][2], q, prev[c][3], t0)
|
||||
prev[c] = (p, t0, d, q)
|
||||
st, c, k, d, dprev, q, qprev, t0 = best
|
||||
print(f"{name}: step {st:.3f} at cand ({c[2]:.0f},{c[3]:.0f}) thr {c[4]:.2f} frame {k}: density {dprev:.3f} -> {d:.3f}; warped q {qprev} -> {q}; t0 {t0}")
|
||||
for kk in range(k - 3, k + 3):
|
||||
tt = 100 + kk / 60; T.set_time(tt); sc, t0 = T.cyc_scroll(tt, c[5]); s, b, cc = T.env(c[2], c[3], tt)
|
||||
qq = T.warp(c[2], c[3], tt, sc); dist, n = B.body_border(qq, met)
|
||||
print(f" frame {kk}: t0 {t0:.3f} slope {s:.4f} core {cc:.3f} border dist {dist:.2f} warped q ({qq[0]:.2f},{qq[1]:.2f})")
|
||||
Loading…
Reference in a new issue