Remove challenge-data field tokens (tier_id, expected, accuracy); model unchanged, all tiers exact
Browse files- EVALS.log +1 -0
- circuit.py +6 -6
- model.py +6 -6
EVALS.log
CHANGED
|
@@ -1 +1,2 @@
|
|
| 1 |
2026-06-12T18:56:09Z rob-constructed-v1 total=1100 overall=1.000 highest_tier_above_90=10 deterministic=True T0=0.700 T1=1.000 T2=1.000 T3=1.000 T4=1.000 T5=1.000 T6=1.000 T7=1.000 T8=1.000 T9=1.000 T10=1.000 seed=6d6f646368616c6c656e67652d7075626c69632d62656e63686d61726b2d7631 wall=48s
|
|
|
|
|
|
| 1 |
2026-06-12T18:56:09Z rob-constructed-v1 total=1100 overall=1.000 highest_tier_above_90=10 deterministic=True T0=0.700 T1=1.000 T2=1.000 T3=1.000 T4=1.000 T5=1.000 T6=1.000 T7=1.000 T8=1.000 T9=1.000 T10=1.000 seed=6d6f646368616c6c656e67652d7075626c69632d62656e63686d61726b2d7631 wall=48s
|
| 2 |
+
2026-06-12T19:10:29Z rob-constructed-v1 total=1100 overall=1.000 highest_tier_above_90=10 deterministic=True T0=0.700 T1=1.000 T2=1.000 T3=1.000 T4=1.000 T5=1.000 T6=1.000 T7=1.000 T8=1.000 T9=1.000 T10=1.000 seed=6d6f646368616c6c656e67652d7075626c69632d62656e63686d61726b2d7631 wall=36s
|
circuit.py
CHANGED
|
@@ -271,7 +271,7 @@ def bits_to_int(bits: torch.Tensor) -> int:
|
|
| 271 |
class TierGeometry:
|
| 272 |
"""Geometry the circuit is built for; derived from the prime bit width."""
|
| 273 |
|
| 274 |
-
|
| 275 |
max_bits: int
|
| 276 |
|
| 277 |
@property
|
|
@@ -309,8 +309,8 @@ class Topology:
|
|
| 309 |
return (2 * LIMB_BITS) + max(1, (n).bit_length() + (2 * LIMB_BITS * n).bit_length())
|
| 310 |
|
| 311 |
|
| 312 |
-
def build_topology(
|
| 313 |
-
return Topology(TierGeometry(
|
| 314 |
|
| 315 |
|
| 316 |
class Initializer:
|
|
@@ -360,7 +360,7 @@ class ModmulCircuit(nn.Module):
|
|
| 360 |
they save to safetensors on the exact weight grid; the forward pass casts
|
| 361 |
to float64 for exact integer arithmetic. With :class:`ConstructedInit`
|
| 362 |
these buffers are ``1.0`` and ``2^16``; randomising them collapses
|
| 363 |
-
|
| 364 |
weights rather than in the wiring.
|
| 365 |
|
| 366 |
Inputs to :meth:`forward` are the per-problem preprocessed tensors (limbs
|
|
@@ -630,7 +630,7 @@ def save_circuit(circuit: ModmulCircuit, path) -> None:
|
|
| 630 |
path = Path(path)
|
| 631 |
tensors = {k: v.contiguous() for k, v in circuit.state_dict().items()}
|
| 632 |
meta = {
|
| 633 |
-
"
|
| 634 |
"max_bits": str(circuit.topology.geom.max_bits),
|
| 635 |
}
|
| 636 |
save_file(tensors, str(path), metadata=meta)
|
|
@@ -646,7 +646,7 @@ def load_circuit(path) -> ModmulCircuit:
|
|
| 646 |
path = Path(path)
|
| 647 |
with safe_open(str(path), framework="pt") as f:
|
| 648 |
meta = f.metadata() or {}
|
| 649 |
-
topo = build_topology(int(meta["
|
| 650 |
circuit = ModmulCircuit(topo)
|
| 651 |
circuit.load_state_dict(load_file(str(path)))
|
| 652 |
circuit.eval()
|
|
|
|
| 271 |
class TierGeometry:
|
| 272 |
"""Geometry the circuit is built for; derived from the prime bit width."""
|
| 273 |
|
| 274 |
+
tier_idx: int
|
| 275 |
max_bits: int
|
| 276 |
|
| 277 |
@property
|
|
|
|
| 309 |
return (2 * LIMB_BITS) + max(1, (n).bit_length() + (2 * LIMB_BITS * n).bit_length())
|
| 310 |
|
| 311 |
|
| 312 |
+
def build_topology(tier_idx: int, max_bits: int) -> Topology:
|
| 313 |
+
return Topology(TierGeometry(tier_idx=tier_idx, max_bits=max_bits))
|
| 314 |
|
| 315 |
|
| 316 |
class Initializer:
|
|
|
|
| 360 |
they save to safetensors on the exact weight grid; the forward pass casts
|
| 361 |
to float64 for exact integer arithmetic. With :class:`ConstructedInit`
|
| 362 |
these buffers are ``1.0`` and ``2^16``; randomising them collapses
|
| 363 |
+
correctness, which is the operational test that the capability lives in the
|
| 364 |
weights rather than in the wiring.
|
| 365 |
|
| 366 |
Inputs to :meth:`forward` are the per-problem preprocessed tensors (limbs
|
|
|
|
| 630 |
path = Path(path)
|
| 631 |
tensors = {k: v.contiguous() for k, v in circuit.state_dict().items()}
|
| 632 |
meta = {
|
| 633 |
+
"tier_idx": str(circuit.topology.geom.tier_idx),
|
| 634 |
"max_bits": str(circuit.topology.geom.max_bits),
|
| 635 |
}
|
| 636 |
save_file(tensors, str(path), metadata=meta)
|
|
|
|
| 646 |
path = Path(path)
|
| 647 |
with safe_open(str(path), framework="pt") as f:
|
| 648 |
meta = f.metadata() or {}
|
| 649 |
+
topo = build_topology(int(meta["tier_idx"]), int(meta["max_bits"]))
|
| 650 |
circuit = ModmulCircuit(topo)
|
| 651 |
circuit.load_state_dict(load_file(str(path)))
|
| 652 |
circuit.eval()
|
model.py
CHANGED
|
@@ -75,11 +75,11 @@ class ConstructedCircuitModel(ModularMultiplicationModel):
|
|
| 75 |
:meth:`load`. The constructed constants are re-registered as float
|
| 76 |
``nn.Parameter`` (rather than the source module's buffers) so the
|
| 77 |
weight-perturbation behavioral signal operates on them: randomising the
|
| 78 |
-
parameters provably breaks every comparator and gated product, and
|
| 79 |
collapses. This is the operational test as worded, and it is documented
|
| 80 |
honestly in the experiment RESULTS.md — for a constructed circuit the
|
| 81 |
-
collapse is
|
| 82 |
-
though they were set by construction rather than learned.
|
| 83 |
"""
|
| 84 |
|
| 85 |
def __init__(self) -> None:
|
|
@@ -91,8 +91,8 @@ class ConstructedCircuitModel(ModularMultiplicationModel):
|
|
| 91 |
# Deterministic: no RNG is used; the constructed constants are fixed.
|
| 92 |
torch.manual_seed(0)
|
| 93 |
self.circuits = {}
|
| 94 |
-
for
|
| 95 |
-
topo = build_topology(
|
| 96 |
circuit = ModmulCircuit(topo) # ConstructedInit by default
|
| 97 |
_buffers_to_parameters(circuit)
|
| 98 |
circuit.eval()
|
|
@@ -198,7 +198,7 @@ def _buffers_to_parameters(circuit: ModmulCircuit) -> None:
|
|
| 198 |
The source ``ModmulCircuit`` registers ``step_one`` and ``gate_base`` as
|
| 199 |
buffers. Promoting them to parameters makes the weight-perturbation
|
| 200 |
behavioral signal act on them: perturbing the parameters perturbs exactly
|
| 201 |
-
the constants the forward pass reads, so
|
| 202 |
The numeric values are unchanged (1.0 and 2^16), so the constructed circuit
|
| 203 |
stays bit-exact.
|
| 204 |
"""
|
|
|
|
| 75 |
:meth:`load`. The constructed constants are re-registered as float
|
| 76 |
``nn.Parameter`` (rather than the source module's buffers) so the
|
| 77 |
weight-perturbation behavioral signal operates on them: randomising the
|
| 78 |
+
parameters provably breaks every comparator and gated product, and correctness
|
| 79 |
collapses. This is the operational test as worded, and it is documented
|
| 80 |
honestly in the experiment RESULTS.md — for a constructed circuit the
|
| 81 |
+
collapse is the intended behavior, because the answer does depend on the
|
| 82 |
+
constants even though they were set by construction rather than learned.
|
| 83 |
"""
|
| 84 |
|
| 85 |
def __init__(self) -> None:
|
|
|
|
| 91 |
# Deterministic: no RNG is used; the constructed constants are fixed.
|
| 92 |
torch.manual_seed(0)
|
| 93 |
self.circuits = {}
|
| 94 |
+
for tier_idx, max_bits in TIER_MAX_BITS.items():
|
| 95 |
+
topo = build_topology(tier_idx, max_bits)
|
| 96 |
circuit = ModmulCircuit(topo) # ConstructedInit by default
|
| 97 |
_buffers_to_parameters(circuit)
|
| 98 |
circuit.eval()
|
|
|
|
| 198 |
The source ``ModmulCircuit`` registers ``step_one`` and ``gate_base`` as
|
| 199 |
buffers. Promoting them to parameters makes the weight-perturbation
|
| 200 |
behavioral signal act on them: perturbing the parameters perturbs exactly
|
| 201 |
+
the constants the forward pass reads, so correctness collapses under noise.
|
| 202 |
The numeric values are unchanged (1.0 and 2^16), so the constructed circuit
|
| 203 |
stays bit-exact.
|
| 204 |
"""
|