# Solver Notes

## Formula Notes

- Training formulas are CBMC-style AES instances. All train rows in the
  provided baseline are expected UNSAT.
- Clause mixes are highly regular: many binary/ternary Tseitin clauses,
  8-bit equality-table clauses of length 9, 32-bit equality/table clauses of
  length 33, and miter clauses of length 16/56/184/257 depending on variant.
- Unit propagation alone assigns about 12k/38k vars on the r1 instance and
  about 113k/266k vars on r2-EE, but does not reach contradiction.
- Recovered table structure:
  - AES S-box table: first entries `63 7c 77 7b ...`.
  - AES T-table relations: 8-bit to 32-bit rows, first words such as
    `a56363c6`, `847c7cf8`, `997777ee`, `8d7b7bf6`.
  - Log-like tables: first entries `00 00 19 01 32 02 ...`.
- The `tools/` scripts profile clause distributions, unit propagation,
  contiguous gate blocks, and experimental table/circuit hashing.
- Failed-literal probing showed the 56/184-literal decryption miters reduce
  to 16 live literals after root propagation, but r2 decryption still does not
  finish inside the 585s internal cutoff with this CDCL engine.
- The ELE formulas have ten 257-literal miter clauses. Prioritizing those
  miter literals makes both train ELE variants solve with CDCL.

## Techniques Used

- Submitted solver is conservative and currently commits only for:
  - formulas with at most 60,000 variables, covering r1-sized AES decryption,
  - ELE-shaped formulas detected structurally by ten 257-literal miter
    clauses and no 16/56/184-literal miter clause.
- A lightweight shape scan counts variables and long miter clauses before the
  full clause database is allocated. Unsupported r2/r3 formulas return
  UNKNOWN from this scan path, which avoids worker OOMs on large gated shapes.
- The solving path is a from-scratch CDCL implementation:
  - watched literal propagation,
  - a same-order binary-clause propagation specialization inside the watcher
    loop,
  - first-UIP conflict analysis,
  - learnt-clause minimization,
  - VSIDS-like variable activity,
  - miter-literal branch priority for large ELE formulas,
  - dependency-trimmed VeriPB `rup` proof emission.
- Proofs are no longer streamed clause-by-clause. Each learnt clause records
  the learnt clauses used by its conflict analysis; at UNSAT the solver marks
  only the learnt clauses needed for the final root contradiction and emits
  those in chronological order. This keeps the ELE proofs checkable.
- SAT answers are independently checked against the loaded CNF before exit
  code 10. UNSAT answers are emitted only with a completed VeriPB proof.

## Local Results

- Current final local pass on the 2026-05-08 train directory:
  - `bd4d39...post-cbmc-aes-d-r1-noholes`: solved UNSAT in about 2.6s.
    VeriPB verified the dependency-trimmed 4.9MB proof in about 5.1s.
  - `d2ac39...post-cbmc-aes-ele-noholes`: solved UNSAT in about 92s.
    VeriPB verified the 37.7MB dependency-trimmed proof in about 72s.
  - `739da3...post-cbmc-aes-ele`: solved UNSAT in about 95s.
  - The remaining eight visible train formulas return UNKNOWN under the
    conservative detector, usually in 0.25-0.5s after the lightweight scan.
- `post-cbmc-aes-ee-r2-noholes`: returns UNKNOWN immediately after parsing
  due the large-instance gate. This avoids huge incomplete proof files.
- `post-cbmc-aes-d-r2-noholes`: with `LYMPHOSAT_TRY_ALL=1`, the trimmed-proof
  CDCL ran to its 585s internal cutoff and returned UNKNOWN, so r2 decryption
  remains gated off.
- Broker run `eval_20260508T191955Z_6768aa2d` solved 3/11 visible train
  instances (`437a...d-r1`, `bd4d...d-r1-noholes`, `d2ac...ele-noholes`) with
  no invalid/prover-timeout results. It matched the listed Kissat solved count
  but did not beat Kissat's PAR-2 because the ELE solve/proof is slower.

## Remaining Things To Try

- Finish the structural proof path for r2/r3:
  - compose 8-to-32 T-tables with the 32-to-8 log/antilog table constraints,
  - canonicalize T-table outputs as linear functions of S-box bytes,
  - generate byte/bit equivalence lemmas in topological order and verify them
    as RUP clauses.
- Add a proof-oriented equivalence generator for S-box applications: if two
  input byte bundles are equivalent, derive output-byte equality clauses using
  the 256 table rows.
- Improve CDCL only if structural proof stalls: LBD-style learnt deletion and
  better branching on decryption miter cones may help. A simple proof-deletion
  experiment made ELE proofs larger/slower and was not kept active.

## Known Limitations

- Current submitted behavior solves r1-sized formulas and the detected ELE
  shape. r2/r3 encryption/equivalence/decryption formulas are intentionally
  UNKNOWN until their table/circuit equivalence proof can be generated soundly.
- ELE proofs have verified locally but use about 1.15GB of VeriPB memory.
- The analysis scripts may use comments/filenames for human reporting, but the
  solver itself does not depend on comments, hashes, or filenames.

## Changelog

- Initial scaffold replaced with a C++ proof-producing CDCL solver.
- Added `tools/cnf_profile.py`, `tools/unit_prop.py`, `tools/block_defs.py`,
  and `tools/hash_analyze.py` for repeatable structural analysis.
- Added learnt-clause minimization, reducing the r1 proof from roughly 34MB to
  roughly 12MB and improving local VeriPB time.
- Added a large-instance UNKNOWN gate to prevent unsound or impractical partial
  proofs on r2/r3 formulas.
- Updated metadata with the current conservative strategy.
- Added `tools/failed_probe.py` and miter-inspection support in
  `tools/hash_analyze.py` to study final assertion clauses.
- Added structural detection for ELE formulas with ten 257-literal miter
  clauses and miter-priority branching for that shape.
- Replaced streaming RUP output with dependency-trimmed proof emission,
  reducing the r1 proof from about 12MB to 4.7MB and the ELE proof from about
  221MB to 36MB.
- Confirmed full-budget r2 decryption CDCL still returns UNKNOWN; kept it
  gated off for submitted behavior.
- Submitted broker candidate `eval_20260508T191955Z_6768aa2d`: result was
  `unsat=3`, `unknown=8`, with no invalid answers. Added this result and kept
  the conservative gate.
- Tried frequent restarts plus solver-only learnt deletion for large formulas.
  It did not solve r2 decryption and caused ELE to miss a 220s local cap, so
  the stable restart policy was restored.
- Added a `TRUTH_VARS` mode to `tools/hash_analyze.py`; the 16 live r2
  decryption miter gates have 58-122 symbolic support variables under the
  current decoder, so they are not immediate small-tautology proof targets.
- 2026-05-08 current run: tested a direct binary implication graph. It did not
  solve r2 and made ELE slower/larger, so it was reverted.
- 2026-05-08 current run: kept a smaller same-order binary-clause fast path in
  the watcher loop; it preserves the known conflict counts and proofs.
- 2026-05-08 current run: tested branch-priority variants for ELE. Reverse and
  activity-desc order missed a 180s cap; activity-asc matched the same 278,234
  conflict proof but was not faster, so default clause order remains active.
- 2026-05-08 current run: added a non-default miter-AND expansion experiment
  for `LYMPHOSAT_TRY_ALL` r2 debugging. It reached the 585s cutoff on both
  r2 encryption-equivalence and r2 decryption, so submitted detection still
  returns UNKNOWN for those shapes.
- 2026-05-08 current run: tried narrower final proof marking and then
  level-0 dependency repair. r1 could be made valid, but ELE proof checking
  failed, so the conservative final root-trail marking was restored.
- 2026-05-08 current run: tested ThinLTO/LLD build flags; local runtime was
  worse, so the original `clang++ -O3 -march=icelake-server` build was kept.
- 2026-05-08 current run: broker candidate
  `eval_20260508T221622Z_51a5b5f2` regressed to `unsat=2`, `unknown=7`,
  `solver_oom=2`. The OOMs happened on a large gated decryption shape and a
  r1-with-holes instance in the same run.
- 2026-05-08 current run: added a lightweight pre-scan so unsupported large
  formulas return UNKNOWN without allocating all clauses. Local unsupported
  r2/r3 times dropped from roughly 0.5-1.3s with full allocation to about
  0.25-0.5s with scan-only allocation.
