# Solver Notes

## Formula Notes

- Visible train instance: `sncf_model_ixl_bmc_depth_14`, `p cnf 1492852 5088844`.
- Clause distribution is strongly Tseitin/circuit-like: about 3.18M binary clauses, 1.62M ternary clauses, and only 825 unit clauses.
- Consecutive clauses grouped by the absolute value of their first literal recover the encoding. There is one non-unit definition per defined variable.
- Recovered depth-14 structure:
  - 1,438,407 accepted gate definitions plus one non-definitional residual final clause.
  - Mostly signed OR/NOR gates, with many 2-input XNOR/XOR/small LUT gates.
  - The definition graph is acyclic.
  - Watched-literal BCP from units assigns 368,334 variables.
- A complete model was found locally for depth 14 and verified against every original CNF clause before printing SAT.

## Techniques Used

- Parse DIMACS comments-free input and recover contiguous Tseitin definition groups structurally.
- Classify wide gates by the standard one-long-clause plus binary-implication pattern. Classify small definitions by truth-table extraction over up to two inputs.
- Build a circuit DAG and fanout graph.
- Run in-house watched-literal BCP and treat all BCP assignments as forced circuit targets.
- Run stochastic local search over free primary variables only. Each flip is propagated incrementally through the circuit fanout graph, and the objective is the number of forced gate targets plus residual clauses currently violated.
- Before returning SAT, evaluate the full DAG and independently check every original CNF clause. If verification fails, the solver does not commit.

## Remaining Things To Try

- Add restarts from the best saved state if a larger depth stalls near a small number of target mismatches.
- Tune the fanout cutoff and target-descent heuristic per recovered depth.
- Derive a compact UNSAT proof strategy if any generated variant is UNSAT; the current solver intentionally returns UNKNOWN rather than emitting an unproved UNSAT claim.
- Remove the older analysis-only justification code from `solver.cpp` after broker behavior is stable.

## Known Limitations

- Only SAT models are produced. BCP conflicts or unsupported structures return UNKNOWN because no VeriPB proof is generated.
- The detector expects the first-literal contiguous definition layout seen in the SNCF BMC formulas.
- Search is stochastic but deterministic for a fixed seed. It solved the visible depth-14 instance in about 57 seconds locally after stderr throttling, but larger depths may need more of the 600 second budget.

## Changelog

- Initial scaffold: trivial UNKNOWN solver.
- Added profiling tools under `tools/` for clause statistics, first-literal group signatures, primary-variable ranges, BCP statistics, SLS experiments, and circuit recovery.
- Recovered the acyclic signed-OR/XOR Tseitin encoding and identified one residual top-level clause.
- Implemented a watched-literal BCP engine.
- Implemented and tested a raw clause SLS prototype; it plateaued on tens of thousands of unsatisfied clauses and was not used for submission.
- Implemented circuit-DAG local search over free primary variables with incremental fanout propagation.
- Promoted the circuit-DAG SLS engine to `solver.cpp`, completed `meta.json`, and verified a SAT model locally on the visible depth-14 instance.
- Broker submission `eval_20260508T183902Z_ebf51fad`: all eight scored train depths returned UNKNOWN after the single 585s SLS walk. Changed `solver.cpp` to run multiple independent 115s circuit-SLS restarts within the same budget while preserving the verified SAT path on the visible depth-14 instance.
- Suppressed per-improvement and periodic search logging in `solver.cpp`; the local visible depth-14 run still returns a verified SAT model, now with much lower stderr overhead.
- Broker submission `eval_20260510T012949Z_ab84638e`: hidden train depths 7-13 and 15 all returned UNKNOWN with no invalids. Relaxed the goal-directed primary fanout cutoff from 6000 to 20000 while leaving random fallback at 6000, because the visible depth-14 earliest high-degree time variable has fanout 5762 and may cross the old cutoff at depth 15.
- Broker submission `eval_20260510T015033Z_1ca8dea9`: fanout relaxation alone still returned UNKNOWN on all hidden train depths. Added low-mismatch exact candidate scoring: below 1500 target violations, the search samples several descended primary flips, temporarily applies each, measures the objective, undoes it, and picks the best candidate with a small noise allowance.
- Broker submission `eval_20260510T020953Z_9f6a7f23`: scored SLS improved the visible depth-14 runtime to about 21 seconds but hidden train depths still returned UNKNOWN. Increased restart slice length from 115s to 285s so harder satisfiable bounds can continue a promising scored walk rather than resetting early.
- Broker submission `eval_20260510T022356Z_148b6f2b`: longer slices still returned UNKNOWN. A temporary timing diagnostic (`eval_20260510T024040Z_1334b4fa`) showed the hidden depths reach very low mismatch buckets in 90s, so the current bottleneck is late local minima. Restored normal timing and added best-state saving plus bounded perturbations around the best low-mismatch state after stagnation.
- Broker submission `eval_20260510T024727Z_bc57393c`: best-state perturbations alone still returned UNKNOWN. Added a bounded exact repair pass for saved states with at most 250 mismatches. First implementation used recursive cone collection and caused OOM on depth 8 and 15 (`eval_20260510T030240Z_7ba2f6a5`), so the repair candidate set now uses the existing bounded `descend_lit` sampler only, capped at 36 primaries, before scoring one- and two-flip repairs.
- Broker submission `eval_20260510T031646Z_306eb613`: sampled pair repair removed OOM but still returned UNKNOWN. Extended the bounded repair to score three-flip combinations when the saved residual is at most 120 mismatches, with the sampled candidate cap reduced to 32 primaries.
- Broker submission `eval_20260510T033126Z_d474256e`: triple repair still returned UNKNOWN. A second timing diagnostic (`eval_20260510T034524Z_f9aba18d`) measured exact 90s residuals: about 1 for depth 7, 3 for depth 8, 7 for depth 9, 25-27 for depths 11-12, 46 for depth 10, 56 for depth 15, and 69 for depth 13. Restored normal timing and added a macro repair that recursively forces an entire bad gate condition, allowing bounded worsening moves when they stay near the saved residual.
- Broker submission `eval_20260510T035227Z_1c3038f9`: macro repair still returned UNKNOWN. Added a low-memory raw-CNF scan repair fallback: keep the best circuit assignment, reserve the final 85s of the run, scan original clauses for unsatisfied clauses, and greedily flip non-BCP variables from those clauses when a full-clause rescan shows improvement.
- Broker submission `eval_20260510T040853Z_f7359b80`: raw-CNF scan repair still returned UNKNOWN on all hidden train depths. Updated `meta.json` to describe the scored/repair-based solver variant.
