Fluoddity CA

A physarum-like particle system rebuilt as a cellular automaton: mass and velocity per cell, no particles.

Five presets, particles above, the CA below
The same five presets after 400 steps: Fluoddity's particles on top, the CA below.

Fluoddity primer

Fluoddity, by aphid91, generalises Sage Jenson's physarum model. Particles never sense each other. They only read a trail that everyone writes, and that trail holds velocity, not density, so opposite flows cancel. How a particle reacts to what it reads is decided by a small Fourier "brain" with 80 parameters, shared by its cohort.

The model as pseudocode
Grid:      float[H, W, 2]     # trail: net flow (x, y) per pixel, faded and blurred

Particle:
    pos: vec2                 # state
    vel: vec2                 # state; its direction is the heading
    brain: Brain              # shared by its cohort: 4 numbers in, 4 out

Globals: drag, strafe_power, sensor_angle, sensor_dist, sensor_gain, persistence, diffusion

step():
    for p in particles:
        fwd = normalize(p.vel)
        L = local(sample(grid, p.pos + rot(+angle)·fwd·dist), fwd)   # (along, across)
        R = local(sample(grid, p.pos + rot(-angle)·fwd·dist), fwd)
        out = brain(L, R) + mirror(brain(mirror(R), mirror(L)))     # no left/right bias
        force, strafe = to_world(out[0:2]), to_world(out[2:4])
        p.vel = p.vel * drag + force
        p.pos = p.pos + p.vel + strafe * strafe_power               # strafe: a hop, never stored

    grid = blur(grid) * persistence
    for p in particles:
        grid[p.pos] += p.vel * (1 - persistence)                    # a sharp 1-4 pixel splat
How one particle deposits into the trail
The deposit: a sharp bell, about 0.18 px wide, so a particle on a pixel centre gives that pixel almost all of its velocity.

Fluoddity as a CA

Each step of the conversion kept Fluoddity's constants, so the two run the same presets.

  1. Grids. Each cohort is its own channel of the CA. Cohorts never see each other directly; they interact only through the trail, which every cohort writes its momentum into and reads with its eyes.
  2. Brain. Fluoddity's, unchanged, with the mirror trick. There is one per cohort, its own mutated row of the rule table.
  3. Perception. Two eye kernels at Fluoddity's defaults: 2.56 × sensor_distance cells out, at ±sensor_angle·π from the cell's velocity. Each is one bilinear tap, which is close to a σ ≈ 0.4 Gaussian. Projected onto the velocity and its perpendicular, they give the brain's four inputs.
    The two eye kernels
    The two eyes at the defaults: Fluoddity's exact bilinear reading on top, the matching Gaussian below.
  4. Force. Not scaled by mass, as in Fluoddity. An empty cell computes a force but carries nothing, so it behaves like an empty pixel.
  5. Velocity. vel = vel·drag + force.
  6. Move. Each cell sends its mass, momentum and colour to cell + vel + strafe·strafe_power, split by overlap over the cells there. The new velocity is momentum ÷ mass. This is advection by reintegration tracking, and it conserves mass exactly.
  7. Deposit. trail += mass · vel · (1 − persistence) · 7.07, where 7.07 is Fluoddity's average splat per particle.

What Fluoddity doesn't have

Spread: the box that carries the mass can be wider than one cell. Wider means softer and more liquid.

Spread 1, 2 and 3
The default preset at spread 1, 2 and 3.

Pressure: mass above a rest level pushes down its own gradient. At 0 it is exactly the original model.

Pressure 0, 0.3 and 1
Bubbles at pressure 0, 0.3 and 1.

Species: a cohort can be its own field, with its own mass, velocity and brain. Species never see each other directly. They meet in the shared trail, which all of them write to and read from, and, with pressure on, in the crowding.

1, 3 and 2 species
The default preset with 1 and 3 species, and Bubbles with 2.

A family of its own

A novelty search started from Fluoddity's presets with random spread, pressure and brain choice, and mutated them slowly. It scored candidates on 13 measured features and threw out dead, static and exploding runs. 24 of its 194 candidates are the CA family in the simulator.

24 CA presets
The CA family, after 300 steps at world size 0.05.

Growing a gecko

The CA's step written in PyTorch is differentiable, so it can be trained by gradient descent: a disc of mass on a 256² grid is fitted to grow the gecko at its native 128 px. The faithful 80-number brain reaches the silhouette. Letting the eyes see mass holds the shape longer, and six hidden channels give the cleanest fit.

variantlosswhat grows
faithful brain0.140a gecko at steps 48–80 that blurs afterwards
+ sees mass0.133a clear gecko that holds to step 160
+ 6 hidden channels0.098a clean silhouette, stable to step 160
launch velocity frozen0.443an 8-armed star
The gecko growing
The best fit growing from its seed (trained on steps 48–96).

Neither part draws the gecko alone. The brain with a symmetric launch grows a star, and the learned launch without the brain smears into a blob. The rule is symmetric, so the launch velocity is the hint that gives the animal a front.

Ablation
Full model, brain off, launch reset to radial, and both.