rogermt commited on
Commit
9b5600c
·
verified ·
1 Parent(s): e2ddfc5

Update LEARNING.md with lessons from σ=0 breakthrough

Browse files
Files changed (1) hide show
  1. 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 `experiments/postprocess_logs.py` to coerce gates and attach candidate snapshot.
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 a relaxed smoke beam (lock_coeff=0, max_fraction=1.0, beam_width≥6) and inspect `sigmas`.
 
 
 
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.