SEED. The only operator that reads the CNF. From clause $(l_1 \vee \cdots \vee l_k)$:
$$\{-l_j : j \neq i\} \;\to\; \{-l_j : j \neq i\} \cup \{l_i\} \quad \forall\, l_i \in C$$CHAIN. Composition: $D[A]=B,\; D[C]=E,\; C \subseteq B \;\Longrightarrow\; D[A] := B \cup E$
CONFLICT. $D[A] \supseteq \{l, -l\} \;\Longrightarrow\;$ learn clause $(\neg a_1 \vee \cdots \vee \neg a_{|A|})$, SEED it.
RESOLVE. Pivot elimination on shared variable.
Deduce. Propagation fixpoint:
$$\text{deduce}(D, P) = \text{lfp}\Bigl(\lambda T.\; T \cup \bigcup_{A \to B \in D,\; A \subseteq T} B\Bigr)$$Extend. Tense the surface: deduce $\to$ chain $\to$ conflict $\to$ repeat until fixpoint. Free, no search.
UPHILL. The key novel operator. For entry $A \to B$ with $|A| \geq 2$:
$$\text{deduce}(D, A\setminus\{l\} \cup \{l\}) \supseteq B\setminus A \;\wedge\; \text{deduce}(D, A\setminus\{l\} \cup \{-l\}) \supseteq B\setminus A \;\Longrightarrow\; D[A\setminus\{l\}] := (A\setminus\{l\}) \cup (B\setminus A)$$PROBE. For each variable $v$: if $\text{deduce}(\{v\})$ contradicts, then $-v$ is a backbone.
Near-miss scoring:
$$\text{score}(l) = |\{A \to B \in D : A \setminus \text{trail} = \{l\}\}| \times \sum |B \setminus A|$$Budget $= \lceil n^a \rceil$ decisions. Every step reads from and writes to $D$:
deduce() reads $D$Key difference from standard CDCL: the dictionary gets smarter between searches. No SAT solver does this. CDCL learns clauses but propagation starts from scratch each time. Here, propagation gets compiled into single $O(1)$ lookups.
prove(left, right) — verify $\text{left} \Rightarrow \text{right}$ using bounded CDCL under assumptions.
Shows $\text{left} \wedge \neg\text{right}$ is UNSAT. Each literal in right is proved independently.
extend(left) — free propagation fixpoint. No search. Tensed surface = maximum
deduction achievable from $D$ alone. Documented as $\text{left} \to \text{result}$.
| $n$ | Entries | Max gain | Depth compiled |
|---|---|---|---|
| 10 | 20 | 9 | 9/9 (full) |
| 50 | 100 | 49 | 49/49 (full) |
| 200 | 400 | 199 | 199/199 (full) |
| $n$ | Seed | Random assigned | Guided assigned | $\Delta$ |
|---|---|---|---|---|
| 50 | 99 | 11 | 50 | +39 |
| 75 | 7 | 13 | 75 | +62 |
| 100 | 7 | 11 | 100 | +89 |
143 = 11 × 13, encoded as 8-bit multiplication circuit (711 vars, 2185 clauses):
| Metric | Value |
|---|---|
| Solved in | 19,849 evals — $O(n^{1.51})$ |
| Backbones found | 401/711 (56%) |
| Max leverage | 543× |
| PROBE alone found | 343 backbones |
Given a total budget (in deduce evals), the supervisor allocates compute across phases:
The supervisor adapts: cheap ops first, targeted search as $D$ saturates.
A key application of the dictionary is exporting its accumulated knowledge as a reduced, equisatisfiable CNF. The dictionary compiles propagation chains into single lookups internally; the export translates that compiled knowledge back into a smaller clause set that any external solver can consume.
We define the tension $\tau(D)$ of a dictionary as the fraction of the problem it has resolved:
$$\tau(D) = \frac{|\text{backbones}(D)| + \sum_{A \to B \in D} |B \setminus A|}{n \cdot (n + 1)}$$A dictionary with $\tau = 0$ knows nothing. A dictionary with $\tau = 1$ has compiled
the complete propagation table. The extend() operation brings $D$ to its
tension fixpoint — the maximum $\tau$ achievable without search:
Each enrichment operation (CHAIN, PROBE, LEARN, UPHILL) strictly increases $\tau$. The tension is a monotonic measure of how much the dictionary has learned.
Backbones live in $D[\emptyset]$. Let $\mathcal{B} = D[\emptyset]$ be the backbone set. Define:
$$C_{\text{sat}} = \{C \in \mathcal{F} : C \cap \mathcal{B} \neq \emptyset\}$$ $$C_{\text{short}} = \{C \setminus \{\neg l : l \in \mathcal{B}\} : C \in \mathcal{F} \setminus C_{\text{sat}}\}$$$C_{\text{sat}}$ are clauses satisfied by backbones (removed entirely). $C_{\text{short}}$ are clauses shortened by removing false backbone literals. The result after Step 1:
$$\mathcal{F}_1 = C_{\text{short}}, \quad |\mathcal{F}_1| = |\mathcal{F}| - |C_{\text{sat}}|$$An entry $A \to B$ subsumes a clause $C$ when the entry guarantees $C$ under weaker conditions:
Interpretation: if every literal in the entry's key is the negation of some clause literal (the "false" side triggers the entry), and the entry's gain contains at least one clause literal (the entry forces it true), then the clause is always satisfied — either some key literal is false (clause satisfied directly) or all key literals are true and the entry fires, satisfying the clause via its gain.
$$\mathcal{F}_2 = \{C \in \mathcal{F}_1 : \nexists\, (A \to B) \in D \text{ that subsumes } C\}$$Beyond entry-level subsumption, the full deduction fixpoint from $D[\emptyset]$ may satisfy additional clauses through chained implications:
$$T^* = \text{deduce}(D, \emptyset) \supseteq \mathcal{B}$$Any clause $C$ with $C \cap T^* \neq \emptyset$ is satisfied by the baseline deduction and can be removed. This catches clauses that no single entry subsumes but that the chained propagation covers:
$$\mathcal{F}_3 = \{C \in \mathcal{F}_2 : C \cap T^* = \emptyset\}$$Backbone variables have fixed truth values. After propagation, they can be removed from the variable set entirely. Let $V_{\text{bb}} = \{|l| : l \in \mathcal{B}\}$:
$$n_{\text{reduced}} = n - |V_{\text{bb}}|, \quad \mathcal{F}_{\text{final}} = \mathcal{F}_3$$This is the key insight: the optimal CNF doesn't just remove clauses — it adds new ones derived from the dictionary's compiled implications.
Each entry $A \to B$ in the dictionary encodes a set of implications. These can be exported as clauses:
These clauses are sound (they are implied by the original CNF, proved by the dictionary) and provide structure that helps external solvers:
| Entry $|A|$ | Emitted clause width | Value for BCP |
|---|---|---|
| 1 | 2 (binary) | Highest — binary clauses propagate in $O(1)$ |
| 2 | 3 (ternary) | High — fire as soon as 2 lits are set |
| 3 | 4 | Medium — still useful for propagation |
| $k$ | $k+1$ | Decreasing — long clauses provide less BCP value |
An entry $\{x_1\} \to \{x_1, x_5, x_9, x_{12}\}$ (a single-literal entry with gain 3) produces three binary clauses:
$$( \neg x_1 \vee x_5 ), \quad ( \neg x_1 \vee x_9 ), \quad ( \neg x_1 \vee x_{12} )$$These encode a propagation chain that might have required 10 BCP steps in the original CNF. The external solver gets it as three binary clauses — three $O(1)$ propagation steps.
The full optimal CNF $\mathcal{F}^*$ combines all three sources:
$$\mathcal{F}^* = \underbrace{\{(l) : l \in \mathcal{B}\}}_{\text{backbone units}} \;\cup\; \underbrace{\mathcal{F}_3}_{\text{surviving originals}} \;\cup\; \underbrace{\bigcup_{A \to B \in D} \{(\neg A \vee g) : g \in B \setminus A\}}_{\text{learned implications}}$$The optimal CNF is not just smaller — it is structurally enriched. The dictionary has discovered the problem's internal implication structure and exported it as explicit clauses that any solver can exploit without rediscovering it.
This creates a feedback cycle:
The tension gap $1 - \tau(D_k)$ measures how much room remains for improvement. The gap monotonically shrinks with each enrichment round.
The tension gap $1 - \tau(D_k)$ measures how much room remains for improvement. At $\tau = 1$ the dictionary has fully compiled the problem; at $\tau = 0$ it has learned nothing. The supervisor allocates compute budget to maximize $\Delta\tau$ per eval.
In practice, structured instances (circuit SAT, graph coloring) reach high tension quickly because their constraint structure creates long implication chains that CHAIN compiles into single lookups. Random instances at the phase transition have low backbone density and plateau at moderate tension — their knowledge is conditional (high-leverage entries with $|A| \geq 2$) rather than unconditional (backbones).
We measure whether LogicSpace's polynomial-time preprocessing (SEED + CHAIN, no solver calls) produces clauses that reduce an industrial solver's work. The protocol:
Binary multiplication circuit encoding $N = p \times q$ with $k$-bit factors. The circuit structure creates long carry chains that CHAIN compiles into implication entries. Backbones arise from fixed output bits propagating through the circuit.
| $N$ | $k$ | vars | $T_{\text{orig}}$ | $C_{\text{orig}}$ | $T_{\text{opt}}$ | $C_{\text{opt}}$ | BB | Speedup | $C$ reduction |
|---|---|---|---|---|---|---|---|---|---|
| 323 | 9 | 908 | 0.6ms | 124 | 0.1ms | 8 | 270 | 4.2× | 94% |
| 3,599 | 12 | 1,643 | 4.4ms | 354 | 1.7ms | 142 | 414 | 2.5× | 60% |
| 10,403 | 14 | 2,253 | 11.9ms | 854 | 6.2ms | 440 | 525 | 1.9× | 48% |
| 46,657 | 16 | 2,959 | 21.8ms | 1,480 | 1.5ms | 200 | 648 | 14.6× | 86% |
The speedup increases with instance size: 4.2× at 9-bit, 14.6× at 16-bit. Larger circuits have longer carry chains — CHAIN compiles deeper propagation paths into single entries, which export as binary clauses that give Glucose free BCP. The 648 backbones at 16-bit mean 22% of variables are resolved by preprocessing alone.
The conflict reduction formula:
$$\text{reduction} = 1 - \frac{C_{\text{opt}}}{C_{\text{orig}}} = 1 - \frac{200}{1480} = 86\%$$Uniform random 3-SAT at clause/variable ratio 4.26 (phase transition).
| $n$ | $T_{\text{orig}}$ | $C_{\text{orig}}$ | $T_{\text{opt}}$ | $C_{\text{opt}}$ | Solve speedup | $C$ reduction |
|---|---|---|---|---|---|---|
| 100 | 0.3ms | 141 | 0.2ms | 82 | 1.5× | 42% |
| 150 | 16.5ms | 4,604 | 10.6ms | 3,068 | 1.6× | 33% |
| 175 | 15.3ms | 3,834 | 6.5ms | 1,868 | 2.3× | 51% |
| 250 | 3.0s | 177,315 | 2.6s | 164,727 | 1.1× | 7% |
| 300 | 12.6s | 476,984 | 11.7s | 448,306 | 1.1× | 6% |
The critical question: does the preprocessing pay for itself? Is the total time (preprocessing + solving the optimal CNF) less than solving the original?
On hard random 3-SAT instances ($n \geq 250$, where Glucose takes seconds):
| $n$ | seed | $T_{\text{raw}}$ | $C_{\text{raw}}$ | $T_{\text{pre}}$ | $T_{\text{opt}}$ | $T_{\text{total}}$ | $C_{\text{opt}}$ | Total speedup |
|---|---|---|---|---|---|---|---|---|
| 250 | 42 | 3,027ms | 177,315 | 21ms | 2,584ms | 2,606ms | 164,727 | 1.16× |
| 250 | 123 | 1,941ms | 124,801 | 22ms | 1,823ms | 1,845ms | 118,469 | 1.05× |
| 275 | 77 | 2,720ms | 167,080 | 20ms | 2,333ms | 2,352ms | 151,333 | 1.16× |
| 300 | 42 | 12,878ms | 476,984 | 22ms | 11,960ms | 11,982ms | 448,306 | 1.07× |
| 300 | 123 | 2,031ms | 119,180 | 26ms | 286ms | 312ms | 28,241 | 6.5× |
The preprocessing is essentially free compared to the solve: $T_{\text{pre}} \approx 20\text{ms}$ while $T_{\text{raw}} \in [2\text{s}, 13\text{s}]$. The learned clauses from CHAIN reduce Glucose's conflict count, which translates directly to wall-clock savings. The effect is strongest on instances where Glucose takes many conflicts — exactly the hard instances where preprocessing matters most.
The key mechanism: CHAIN compiles multi-step propagation paths into single dictionary entries. When exported as binary/ternary clauses, these give the industrial solver pre-compiled BCP — propagation steps it would otherwise discover through conflict analysis. The preprocessing cost is polynomial ($O(|D|^2 \cdot \bar{k})$ per CHAIN round) and instance-independent: ~20ms for $n=300$.
What is new. The dictionary is not a clause database. A clause $(a \vee b \vee c)$ is a single constraint. An entry $\{-a\} \to \{-a, b, c, d, e, f\}$ is a compiled propagation chain — it replaces 5 BCP steps with a single $O(1)$ lookup. When exported as clauses, these compiled chains give industrial solvers pre-computed propagation that reduces conflicts by up to 94%.
LogicSpace as a SAT solving hub. The dictionary is a coordination layer between solver calls. Every operation (prove, extend, prune) maps to a SAT call dispatched to an industrial solver. The dictionary stores results permanently. The optimal CNF is the dictionary's knowledge exported as clauses — a one-way ratchet that makes each subsequent solve faster.
Parallelism. Since $D$ grows monotonically, multiple workers can enrich it concurrently with zero conflicts. Worker 1 extends from entry $A$, Worker 2 prunes entry $B$, both write to $D$. This brings parallelism to SAT preprocessing.
Architecture: complementing industrial solvers. LogicSpace is not a solver — it is a knowledge manager that makes industrial solvers smarter. The architecture on a processing machine:
CNF instance
|
v
+-----------------+
| LogicSpace | SEED + CHAIN (polynomial)
| Dictionary D | -> backbones, implications, entries
+-----------------+
|
| export optimal CNF
| (original - subsumed + backbone units + learned clauses)
|
v
+-----------------+
| Industrial | Glucose / CaDiCaL / Kissat
| SAT Solver | -> SAT/UNSAT in reduced search space
+-----------------+
|
| learned clauses flow back
v
+-----------------+
| Dictionary D | prove(), extend(), prune()
| (enriched) | each = one solver.solve(assumptions=...)
+-----------------+
|
v
next query (incremental) or export
For large instances (millions of clauses, e.g. SHA-256 circuit SAT), the dictionary
identifies which assumptions are worth probing via the achilles heuristic, and
dispatches targeted solver.solve(assumptions=[...]) calls. Each result enriches $D$,
which identifies the next probe target. Multiple solver threads can work different
assumptions concurrently, all writing to the same dictionary. The dictionary is the
shared knowledge base; the solvers are the compute muscle.
Limitations. The current Python implementation is 1000× slower than C-based solvers on raw solving. The value is not in competing with Glucose/CaDiCaL on single-shot solving, but in knowledge compilation: building a reusable dictionary that makes multiple related queries faster. The preprocessing overhead (684ms for 2,959 vars) is acceptable when amortized over multiple solves or incremental settings.
Connection to AUMA. LogicSpace is the SAT-domain specialization of AUMA's universal maximization framework. The Dana Theorem guarantees polynomial SAT encoding; LogicSpace exploits the structure for fast inference. The dictionary's implication entries are the SAT analogue of AUMA's Fourier coefficients — both compile a function's structure into a lookup table.
© 2026 Charles Dana. LogicSpace is open research.