"""Canonical finite transport memory: evidence is a value, not a frame.""" import numpy as np class WorldMemory: """Fixed-capacity receiver x emitter visibility table for the reference. A scene namespace owns stable receiver and emitter IDs. Reusing an integer ID for a different surface requires a new namespace/reset. Each entry is deterministic visibility evidence at an exact point/emitter, not an independent noisy training sample. Geometry epochs revoke trust while retaining the old value as a fallible control variate. """ def __init__(self, receivers, terms, namespace="scene"): if receivers < 1 or terms < 1 or not namespace: raise ValueError("Need a nonempty namespace and positive capacity") self.namespace = str(namespace) self.values = np.full((receivers, terms), np.nan, np.float32) self.epochs = np.full((receivers, terms), -1, np.int32) self.epoch = 0 self.tick = 0 @property def nbytes(self): return self.values.nbytes + self.epochs.nbytes def _receiver_ids(self, receivers): rows = np.asarray(receivers) if rows.size == 0 and rows.ndim == 1: return rows.astype(np.int64) if (rows.ndim != 1 or not np.issubdtype(rows.dtype, np.integer) or (rows < 0).any() or (rows >= len(self.values)).any()): raise ValueError("Canonical receiver IDs must be valid nonnegative integers") return rows def predict(self, receivers, prior): v = self.values[self._receiver_ids(receivers)] prior = np.asarray(prior, float) if prior.shape != v.shape or not np.isfinite(prior).all() or ((prior < 0)|(prior > 1)).any(): raise ValueError("Visibility prior must have matching shape in [0,1]") return np.where(np.isnan(v), prior, v).astype(np.float64) def trusted(self, receivers): return self.epochs[self._receiver_ids(receivers)] == self.epoch def commit(self, receivers, indices, visibility, revise_on_conflict=False): rows = np.asarray(receivers) j = np.asarray(indices) v = np.asarray(visibility) if (rows.ndim != 1 or j.ndim != 2 or len(rows) != len(j) or j.shape != v.shape or not np.issubdtype(rows.dtype, np.integer) or not np.issubdtype(j.dtype, np.integer) or (rows < 0).any() or (rows >= len(self.values)).any() or (j < 0).any() or (j >= self.values.shape[1]).any() or not np.isfinite(v).all() or ((v != 0)&(v != 1)).any()): raise ValueError("Expected valid exact binary visibility observations") old = self.values[rows[:, None], j] was_trusted = self.epochs[rows[:, None], j] == self.epoch conflicts = int(np.count_nonzero(was_trusted & np.isfinite(old) & (old != v))) if revise_on_conflict and conflicts: self.notify_geometry_change() # Duplicate deterministic rays overwrite the same evidence. They do not # accumulate fictitious statistical precision. self.values[rows[:, None], j] = v self.epochs[rows[:, None], j] = self.epoch return conflicts def notify_geometry_change(self): if self.epoch == np.iinfo(np.int32).max: self.epochs.fill(-1) self.values.fill(np.nan) self.epoch = 0 else: self.epoch += 1 def retain_only(self, receivers): keep = np.zeros(len(self.values), bool) keep[self._receiver_ids(receivers)] = True self.values[~keep] = np.nan self.epochs[~keep] = -1 def advance(self, ticks=1): if not isinstance(ticks, (int, np.integer)) or ticks < 0: raise ValueError("ticks must be a nonnegative integer") self.tick += int(ticks) def save(self, path): np.savez_compressed(path, values=self.values, epochs=self.epochs, epoch=np.int64(self.epoch), tick=np.int64(self.tick), namespace=np.array(self.namespace)) @classmethod def load(cls, path, namespace): with np.load(path, allow_pickle=False) as data: if str(data["namespace"]) != str(namespace): raise ValueError("Scene namespace mismatch: refusing stale identity alias") values = np.array(data["values"], copy=True) epochs = np.array(data["epochs"], copy=True) if values.ndim != 2 or epochs.shape != values.shape or values.dtype != np.float32 or epochs.dtype != np.int32: raise ValueError("Malformed memory arrays") finite = values[np.isfinite(values)] if np.isinf(values).any() or ((finite != 0)&(finite != 1)).any(): raise ValueError("Memory must contain binary observations or NaN") epoch, tick = int(data["epoch"]), int(data["tick"]) if epoch < 0 or epoch > np.iinfo(np.int32).max or tick < 0 or (epochs < -1).any() or (epochs > epoch).any(): raise ValueError("Malformed memory time/epoch") if (np.isnan(values) != (epochs == -1)).any(): raise ValueError("Missing evidence and provenance disagree") obj = cls(*values.shape, namespace=namespace) obj.values, obj.epochs, obj.epoch, obj.tick = values, epochs, epoch, tick return obj