Update LEARNING.md with lessons from σ=0 breakthrough
Browse files- LEARNING.md +36 -7
LEARNING.md
CHANGED
|
@@ -7,14 +7,43 @@
|
|
| 7 |
- **Coerce logged gate values to booleans.** Strings like `"True"` break automated gate analysis and mislead debugging.
|
| 8 |
- **Quantize and resize consistently.** Residue must be computed on the same quantized and tiled array the beam evaluates (use `np.rint` and `tile_transform`).
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
## Debugging checklist
|
| 11 |
-
1. Confirm `experiments/` contains `*_phi_best.npy` and `*_logs.json`.
|
| 12 |
-
2. Run `
|
| 13 |
-
3. Inspect `logs[0]` for `candidate_array` and recomputed residue.
|
| 14 |
-
4. Run `itt_solver.tests.run_atomic_effects()` to verify transforms change the input.
|
| 15 |
-
5. Run
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
## Practical tips
|
| 18 |
-
- After editing package files, **clear Python module cache** or restart the interpreter.
|
| 19 |
-
- Keep `candidate_array` optional in logs to avoid huge files; include it for debugging runs.
|
| 20 |
- Use small, deterministic transforms for initial debugging (Rotate, Reflect, ShiftedTile).
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
- **Coerce logged gate values to booleans.** Strings like `"True"` break automated gate analysis and mislead debugging.
|
| 8 |
- **Quantize and resize consistently.** Residue must be computed on the same quantized and tiled array the beam evaluates (use `np.rint` and `tile_transform`).
|
| 9 |
|
| 10 |
+
## Lessons from the σ=0 breakthrough
|
| 11 |
+
|
| 12 |
+
### Verify your ground truth first
|
| 13 |
+
The example1 target had **4 wrong cells** in row 7. Every experiment showed σ=98 not because the solver was broken, but because the target was wrong. Cross‑reference task data against the **canonical source** (e.g. `fchollet/ARC-AGI` on GitHub). A wrong target makes every downstream analysis meaningless.
|
| 14 |
+
|
| 15 |
+
### Shape‑changing transforms need the original input
|
| 16 |
+
The beam was resizing `phi_in` (3×3) to the target shape (9×9) before applying transforms. This meant Kronecker (3×3 → 9×9) was applied to a 9×9 field, producing 81×81, which was then tiled back — garbage. The fix: a **dual‑strategy beam** that tries each transform on both the resized field AND the original input. Any solver that composes shape‑changing primitives needs this.
|
| 17 |
+
|
| 18 |
+
### The Kronecker self‑similar pattern
|
| 19 |
+
ARC task 007bbfb7 has one of the cleanest rules in the dataset: `output = np.kron((input != 0), input)`. The input's own nonzero mask becomes the meta‑layout for placing copies of itself. This is a **single depth‑1 transform** — but it was unreachable because (a) the transform didn't exist in the library, and (b) the beam couldn't feed it the right input shape.
|
| 20 |
+
|
| 21 |
+
### Lambda closures capture by reference, not value
|
| 22 |
+
`lambda p: tile_transform(p, (task['target_shape'][0], ...))` captures `task` by reference. In a sweep loop where `task` changes, all previously‑created lambdas silently point to the new task. Fix: bind with default args — `lambda p, _h=h, _w=w: ...`.
|
| 23 |
+
|
| 24 |
+
### Idempotent transforms are invisible to the beam
|
| 25 |
+
`tile_to_target ∘ tile_to_target` = `tile_to_target`. When the only accepted transform is idempotent, σ flatlines across all depths. The symptom is a constant sigma trace like `[98, 98, 98, 98]`. When you see this, the library is too limited — not the search.
|
| 26 |
+
|
| 27 |
+
### Duplicate class definitions cause subtle bugs
|
| 28 |
+
`solver_core.py` defined `Transform` with `.compose()` and `params`. `transforms.py` defined its own `Transform` without those. Both had `.apply()`, so things ran — but composed transforms could silently lose parameters. Rule: **one canonical class, import everywhere else**.
|
| 29 |
+
|
| 30 |
+
### Don't commit `.pyc` files
|
| 31 |
+
They cause stale‑import bugs when the source changes. Add `__pycache__/` and `*.pyc` to `.gitignore` from day one.
|
| 32 |
+
|
| 33 |
## Debugging checklist
|
| 34 |
+
1. Confirm `experiments/` contains `*_phi_best.npy` and `*_logs.json`.
|
| 35 |
+
2. Run `scripts/fix_and_inspect_logs.py` to coerce gates and attach candidate snapshot.
|
| 36 |
+
3. Inspect `logs[0]` for `candidate_array` and recomputed residue.
|
| 37 |
+
4. Run `itt_solver.tests.run_atomic_effects()` to verify transforms change the input.
|
| 38 |
+
5. Run `tests/test_transforms.py` to verify all 40 transform unit tests pass.
|
| 39 |
+
6. Run a relaxed smoke beam (lock_coeff=0, max_fraction=1.0, beam_width≥6) and inspect `sigmas`.
|
| 40 |
+
7. **If σ flatlines:** check whether transforms are idempotent on the input the beam feeds them. Print the shape of the field each transform receives.
|
| 41 |
+
8. **If σ is nonzero but close:** diff `phi_best` against target cell by cell. The pattern of mismatches usually reveals the missing transform.
|
| 42 |
|
| 43 |
## Practical tips
|
| 44 |
+
- After editing package files, **clear Python module cache** or restart the interpreter.
|
| 45 |
+
- Keep `candidate_array` optional in logs to avoid huge files; include it for debugging runs.
|
| 46 |
- Use small, deterministic transforms for initial debugging (Rotate, Reflect, ShiftedTile).
|
| 47 |
+
- **Always cross‑check targets** against the original ARC dataset before concluding the solver is wrong.
|
| 48 |
+
- When adding a new transform, write a unit test immediately — transforms that silently return the input waste hours of debugging.
|
| 49 |
+
- The `default_atomic_factory` is just a starting point. For new ARC task families, inspect the input→output mapping manually (decompose into sub‑blocks, check symmetries, test Kronecker/mirror/upscale) and add targeted transforms.
|