# Solver Notes

## Formula Notes

- The visible train split is the `uniform-random` family.
- Most clause widths are fixed per instance, but some older `unif2p...` files mix 2- and 3-literal clauses. The solver detects clause lengths directly from DIMACS and does not depend on filenames or comments.
- Polarity is balanced, with no apparent gate, graph, cardinality, XOR, or application encoding. Comments and filenames are not used by the solver.
- The strongest provided baseline is Kissat SC2024: 898/3235 solved at 600 seconds, including 762 SAT and 136 UNSAT. Since producing VeriPB UNSAT proofs for random formulas is not yet implemented, this solver focuses on finding SAT models quickly and safely.

## Techniques Used

- Parse DIMACS directly and accept fixed or mixed-width CNF with clause lengths 1 through 8.
- Build occurrence lists for each signed literal.
- Maintain per-clause satisfied-literal counts and an O(1) removable list of currently unsatisfied clauses.
- Run a probSAT-style local search: choose a random unsatisfied clause, score its variables by make and break counts, prefer zero-break moves, and otherwise sample with a high make / low break bias.
- Clause-width-specific default scoring is used. The default portfolio uses complementary probSAT parameters per width instead of running identical workers.
- Run a default three-thread in-process portfolio with independent seeds and read-only shared formula data, clamped to two workers for very large formulas. `SLS_THREADS` can override this locally.
- One portfolio worker starts from the per-variable majority polarity assignment. This exploits the weak polarity signal present in some planted/conditioned satisfiable random formulas while the other worker still starts randomly.
- Per-worker make/break weighting tables are precomputed, avoiding repeated `pow()` calls in the main flip loop.
- Exact implication-SCC solving is available for pure 2-CNF SAT instances. Contradictory 2-CNF instances still return UNKNOWN because no VeriPB proof is emitted.
- Before returning SAT, independently verify every original clause against the assignment. Unsupported structures, timeout, or failed verification return UNKNOWN.

## Remaining Things To Try

- Tune k=4 and k=6 on longer budgets. A broad one-second grid was too noisy and mostly timed out on representative phase-transition samples.
- Recheck the three-worker default against broker results. Four workers gave slightly better local solved count but produced small-instance `solver_oom` broker results, likely from resource contention.
- Add an alternative WalkSAT/Novelty+ mode for hard labelled SAT instances that the current scoring misses.
- Investigate whether small unsat random instances can get compact VeriPB proofs from bounded resolution or specialized DPLL without becoming a general SAT solver.

## Known Limitations

- No UNSAT claims are made, so all unsat baseline wins are currently forfeited.
- Mixed-width formulas are supported, but parameter selection uses the maximum detected clause width as a coarse proxy.
- Search is stochastic but deterministically seeded from instance dimensions; changing seeds or parallel portfolios may improve solved count.

## Changelog

- 2026-05-04: Replaced the placeholder with a C++ fixed-width uniform random k-SAT parser and probSAT-style stochastic local-search solver. Added full CNF model verification before any SAT answer.
- 2026-05-04: Added `tools/bench_sat.py` for labelled SAT smoke benchmarks.
- 2026-05-04: Updated metadata and README for the first broker submission.
- 2026-05-04: Made the probSAT scoring exponents and random-walk noise tunable through environment variables and changed default k=3 scoring based on smoke benchmarks.
- 2026-05-04: Added a two-thread independent local-search portfolio. On the 80-file labelled SAT smoke benchmark at three seconds, this improved from 60/80 to 65/80, mainly by speeding up k=3 and k=5 cases.
- 2026-05-04: Added a majority-polarity initial assignment for one worker. The same 80-file labelled SAT smoke benchmark improved to 66/80.
- 2026-05-04: Precomputed make/break weight tables. The 80-file smoke solved count stayed 66/80, but runtime dropped from about 70 seconds to about 56 seconds for the benchmark.
- 2026-05-05: Replaced identical worker scoring with a heterogeneous, clause-width-specific two-worker portfolio. On all 152 locally labelled SAT files at a two-second budget, this build solved 135/152: k3 72/74, k5 33/35, and k7 30/43.
- 2026-05-05: Generalized storage from fixed-width `c*k` indexing to per-clause offsets and lengths. This supports mixed 2/3-clause `unif2p` instances that the inherited parser rejected. Added an exact pure-2-CNF SCC SAT path while keeping contradictory cases UNKNOWN without a proof.
- 2026-05-05: Changed the default portfolio from two to four workers for non-huge instances, while preserving the two-worker clamp above 700k variables. On all 152 locally labelled SAT files at a one-second budget, four workers solved 138/152 versus 132/152 for two workers.
- 2026-05-05: Reduced the default portfolio from four to three workers after the broker reported 82 `solver_oom` cases, including small formulas. Three workers retained most of the local gain at one second, solving 137/152 labelled SAT files.
