# Solver Notes

## Formula Notes

- The family is a PEQNP subset-sum encoding. Training comments expose
  `universe`, `t`, and `bits`, but the solver does not read comments.
- The sanitized formulas still have a distinctive structure:
  - one long all-negative selector-domain clause;
  - selector variables followed by sparse mux copy runs, one run per item;
  - a sequential ripple-carry adder chain for `sum(selected_items) == target`.
- Selector truth means the item is included. The long negative selector clause
  rejects the all-selected vector.
- The largest training instances use about 70k to 94k variables and 300k to
  402k clauses. Smaller instances use about 7k to 10k variables.

## Techniques Used

- Structural detector:
  - finds the unique long all-negative selector clause;
  - parses each selector's direct-copy run and the subsequent mux-output copy
    run;
  - locates adder-chain use sites for the sparse item outputs.
- Boundary recovery:
  - searches for a late split where the suffix has only a few items and unit
    propagation forces every boundary variable for each suffix assignment;
  - validates the prefix by checking that zero and singleton selector
    assignments are consistent.
- Solving:
  - propagates singleton prefix assignments to recover item values as
    boundary bit-vectors;
  - propagates every small suffix assignment to recover the required prefix
    sum;
  - solves the prefix subset-sum with a custom fixed-width meet-in-the-middle
    search;
  - runs full CNF propagation and a complete clause check before printing SAT.

## Local Results

Sanitized local runs, with comments stripped:

- `7fcc...ssp-0.0346`: SAT in about 0.9s.
- `90d6...ssp-0.0461`: SAT in about 1.8s.
- `da7d...ssp-0.3463`: SAT in about 0.04s.
- `fe606...ssp-0.4617`: SAT in about 0.08s.

An independent Python checker confirmed complete assignments and no
unsatisfied clauses for all four local models.

## Remaining Things To Try

- Replace occurrence-list propagation with watched literals if a future hidden
  split needs many more propagation runs.
- Parse exact adder boundaries instead of using the conservative late-split
  search; this would make the detector less dependent on suffix propagation
  strength.
- Add an UNSAT proof strategy only if unsatisfiable PEQNP subset-sum instances
  appear. The current solver deliberately returns UNKNOWN rather than making
  unsupported UNSAT claims.

## Known Limitations

- This is specialized to the observed PEQNP sequential subset-sum encoding.
  It returns UNKNOWN for unrelated CNFs or for PEQNP variants where the late
  suffix does not force a clean boundary.
- The solver only reports SAT. It never emits VeriPB proofs.
- Big integers are fixed to the recovered boundary width; candidate models are
  always checked against the original CNF to guard against extraction mistakes.

## Changelog

- Added `tools/analyze_cnf.py` to summarize clause sizes, selectors, and
  binary-equivalence classes.
- Added `tools/mitm_probe.py` to prototype the adder-boundary split and
  propagation-based recovery.
- Replaced the C++ UNKNOWN stub with a specialized PEQNP subset-sum solver.
- Updated `meta.json` with the final approach and techniques.
- Broadened late-split detection after the first broker run exposed a
  commentless train instance not present in local `/data/train`.
- Made mux-block recovery search past optional PEQNP prelude clauses such as
  cardinality constraints before the actual subset-value muxes.
