Skip to content

ctde_v0.compass_ceiling

compass_ceiling

Scripted-compass ceiling probe — the locality falsification test (LOCALITY_DESIGN §5).

A hand-coded Voronoi + in-cell-frontier controller (god-view ORACLE): each agent heads to the nearest uncovered free cell in ITS OWN Voronoi cell. Measures, across the density-pinned ladder, whether LOCALITY alone (perfect partitioning) reaches the coverage target within the 100-step budget, and whether redundancy inverts toward 1 (disjoint coverage).

The diagnostic this settles: if even this oracle can't hit ~90% @32²/100-steps, then ~45% is a decentralized INFO/architecture CEILING (no teacher — human teleop or scripted — can exceed it), not a training failure. If it sails past 90%, the gap is a training/exploration failure (a warm-start / better objective CAN help). Gates the distillation + coordination direction.

PYTHONPATH=. <zymera_lab venv>/bin/python ctde_v0/compass_ceiling.py

voronoi_targets

voronoi_targets(pos, covered, wall)

(N,2) target cell per agent: nearest UNCOVERED free cell in its Voronoi cell (Manhattan). Falls back to the global nearest uncovered cell when the agent's own cell is fully covered.

Source code in experiments/ctde_v0/compass_ceiling.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def voronoi_targets(pos, covered, wall):
    """(N,2) target cell per agent: nearest UNCOVERED free cell in its Voronoi cell (Manhattan).
    Falls back to the global nearest uncovered cell when the agent's own cell is fully covered."""
    h, w = wall.shape
    n = pos.shape[0]
    yy, xx = np.mgrid[0:h, 0:w]
    d = np.abs(pos[:, 0][:, None, None] - yy[None]) + np.abs(pos[:, 1][:, None, None] - xx[None])
    assign = np.argmin(d, axis=0)                  # (H,W) nearest-agent id
    uncov = (~wall) & (~covered)                   # (H,W) free & uncovered
    targets = pos.copy()
    for i in range(n):
        mine = uncov & (assign == i)
        cand = mine if mine.any() else uncov
        if not cand.any():
            continue                               # nothing left -> stay
        di = np.where(cand, np.abs(yy - pos[i, 0]) + np.abs(xx - pos[i, 1]), BIG)
        idx = int(np.argmin(di))
        targets[i] = (idx // w, idx % w)
    return targets

greedy_actions

greedy_actions(pos, targets, wall)

(N,) action per agent: the move that most reduces Manhattan distance to target, never stepping into a wall or off-grid (STAY if no move helps).

Source code in experiments/ctde_v0/compass_ceiling.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def greedy_actions(pos, targets, wall):
    """(N,) action per agent: the move that most reduces Manhattan distance to target,
    never stepping into a wall or off-grid (STAY if no move helps)."""
    h, w = wall.shape
    n = pos.shape[0]
    acts = np.zeros(n, np.int32)
    for i in range(n):
        best_a = 0
        best_d = abs(pos[i, 0] - targets[i, 0]) + abs(pos[i, 1] - targets[i, 1])
        for a in range(DELTAS.shape[0]):
            nr, nc = int(pos[i, 0] + DELTAS[a, 0]), int(pos[i, 1] + DELTAS[a, 1])
            if 0 <= nr < h and 0 <= nc < w and not wall[nr, nc]:
                dd = abs(nr - targets[i, 0]) + abs(nc - targets[i, 1])
                if dd < best_d:
                    best_d, best_a = dd, a
        acts[i] = best_a
    return acts

lambda2

lambda2(pos, comm_r)

Algebraic connectivity of the Chebyshev disk comm graph.

Source code in experiments/ctde_v0/compass_ceiling.py
67
68
69
70
71
72
73
74
75
76
def lambda2(pos, comm_r):
    """Algebraic connectivity of the Chebyshev disk comm graph."""
    n = pos.shape[0]
    if n < 2:
        return 0.0
    dist = np.max(np.abs(pos[:, None, :] - pos[None, :, :]), axis=-1)
    a = (dist <= comm_r).astype(float)
    np.fill_diagonal(a, 0.0)
    lap = np.diag(a.sum(1)) - a
    return float(np.sort(np.linalg.eigvalsh(lap))[1])

neighbor_voronoi_targets

neighbor_voronoi_targets(pos, beliefs, comm_r)

DECENTRALIZED compass target per agent: nearest cell the agent does NOT yet believe it knows, inside its Voronoi cell among only its IN-RANGE neighbours. beliefs[i] = agent i's own post-gossip belief (covered-free ∪ sensed walls); so ~beliefs[i] = unknown/uncovered ground, and known walls are excluded for free.

Source code in experiments/ctde_v0/compass_ceiling.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
def neighbor_voronoi_targets(pos, beliefs, comm_r):
    """DECENTRALIZED compass target per agent: nearest cell the agent does NOT yet
    believe it knows, inside its Voronoi cell among only its IN-RANGE neighbours.
    ``beliefs[i]`` = agent i's own post-gossip belief (covered-free ∪ sensed walls);
    so ``~beliefs[i]`` = unknown/uncovered ground, and known walls are excluded for free."""
    n = pos.shape[0]
    h, w = beliefs.shape[1], beliefs.shape[2]
    yy, xx = np.mgrid[0:h, 0:w]
    cheb = np.max(np.abs(pos[:, None, :] - pos[None, :, :]), axis=-1)   # (N,N)
    targets = pos.copy()
    for i in range(n):
        d_self = np.abs(yy - pos[i, 0]) + np.abs(xx - pos[i, 1])
        owned = np.ones((h, w), bool)
        for j in range(n):
            if j == i or cheb[i, j] > comm_r:                          # only in-range neighbours
                continue
            owned &= d_self <= (np.abs(yy - pos[j, 0]) + np.abs(xx - pos[j, 1]))
        unknown = ~beliefs[i]
        cand = owned & unknown
        if not cand.any():
            cand = unknown                                             # my cell fully known -> help globally
        if not cand.any():
            continue
        idx = int(np.argmin(np.where(cand, d_self, BIG)))
        targets[i] = (idx // w, idx % w)
    return targets

run_decentralized

run_decentralized(grid, n, comm_r=5, horizon=100, seed=0, cover_r=0)

The DECENTRALIZED scripted compass — belief-only + in-range-neighbour Voronoi (no god view, no connectivity enforcement). The realistic ceiling for compass-as-feature.

Source code in experiments/ctde_v0/compass_ceiling.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def run_decentralized(grid, n, comm_r=5, horizon=100, seed=0, cover_r=0):
    """The DECENTRALIZED scripted compass — belief-only + in-range-neighbour Voronoi
    (no god view, no connectivity enforcement). The realistic ceiling for compass-as-feature."""
    env = zymera.make("comm-coverage", grid=grid, n_agents=n, comm_r=comm_r,
                      sense_walls=True, spawn_radius=2, cover_r=cover_r)
    key = jax.random.PRNGKey(seed)
    _obs, world = env.reset(key)
    l2s = []
    for _ in range(horizon):
        pos = np.asarray(world.body.position)
        beliefs = np.asarray(world.channel.shared)        # (N,H,W) per-agent belief
        wall = np.asarray(world.wall)
        tgt = neighbor_voronoi_targets(pos, beliefs, comm_r)
        acts = greedy_actions(pos, tgt, wall)
        key, sk = jax.random.split(key)
        _obs, world, _r, _d, _i = env.step(world, jnp.asarray(acts), sk)
        l2s.append(lambda2(np.asarray(world.body.position), comm_r))
    covered = np.asarray(world.covered)
    wall = np.asarray(world.wall)
    seen_by = np.asarray(world.seen_by)
    cov = covered.sum() / max((~wall).sum(), 1)
    redund = seen_by.sum() / max(covered.sum(), 1)
    return cov, redund, float(np.mean(l2s)), float(np.mean([x > 0.5 for x in l2s]))