Splitting clauses into width three with the same number of models #
Cslib.Logic.PL.CNF.to3CNF splits a long clause with auxiliary variables that a satisfying
assignment may choose freely, so it preserves satisfiability but not the number of satisfying
assignments. Here a clause l₁ ∨ l₂ ∨ ⋯ ∨ lₘ with m > 3 is instead computed by a chain of
binary OR gates. The gate z ↔ u ∨ v is imposed by the three clauses
(¬u ∨ z) ∧ (¬v ∨ z) ∧ (u ∨ v ∨ ¬z),
with z₀ ↔ l₁ ∨ l₂ and zⱼ ↔ zⱼ₋₁ ∨ lⱼ₊₂, and the chain ends in the clause
zₘ₋₄ ∨ lₘ₋₁ ∨ lₘ [OpenAI2026ETH, §2.8]. Every gate is the disjunction of a prefix of the clause,
so a satisfying assignment of the original variables has exactly one satisfying extension, and the
number of satisfying assignments is unchanged (Cslib.Logic.PL.CNF.modelCount_toExact3CNF).
Clauses of width at most three are kept, and the empty clause stays empty.
Together with the count-preserving occurrence splitting
Cslib.Logic.PL.CNF.modelCount_toThreeOccurrence, this reduces counting the models of a CNF
formula to counting those of a formula of width three in which every variable occurs at most three
times.
Main definitions #
Cslib.Logic.PL.Clause.orChainAux,Cslib.Logic.PL.Clause.orSplit3: the OR-gate chain for one clause.Cslib.Logic.PL.CNF.toExact3CNF: every clause split, over the variablesV ⊕ (ℕ × ℕ).
Main results #
Cslib.Logic.PL.Clause.eval_orSplit3_iff: an assignment satisfies the chain exactly when it satisfies the clause and gives every gate the value of its prefix.Cslib.Logic.PL.CNF.eval_toExact3CNF_iff: the same for a whole formula, with gate(i, k)belonging to clausei.Cslib.Logic.PL.CNF.length_le_three_of_mem_toExact3CNF: every clause has at most three literals.Cslib.Logic.PL.CNF.modelCount_toExact3CNF: splitting preserves the number of satisfying assignments.Cslib.Logic.PL.CNF.satisfiable_toExact3CNF: hence it preserves satisfiability.Cslib.Logic.PL.CNF.length_toExact3CNF,Cslib.Logic.PL.CNF.length_vars_toExact3CNF,Cslib.Logic.PL.CNF.length_vars_toExact3CNF_le: the size, linear in the number of literal occurrences.
References #
One clause #
The OR-gate chain for the clause carry :: rest, with gate variables fresh j, fresh (j + 1), …: the gate fresh j is constrained to equal carry ∨ b, where b is the head of
rest, and then carries the remaining disjunction. Once at most two literals remain, the chain
ends in the clause carry :: rest.
Instances For
The OR-gate chain of a clause: an assignment satisfies Clause.orSplit3 fresh j c exactly
when it satisfies c and gives the gate fresh (j + i) the value of the first i + 2 literals of
c, for every gate i < c.length - 3.
Every clause in Clause.orSplit3 fresh j c has at most three literals.
The chain of a clause of width w has 3 (w - 3) + 1 clauses: three per gate and one more.
The chain of a clause of width w has w + 6 (w - 3) literal occurrences: seven per gate,
and the three of the last clause.
Formulas #
Every clause of CNF.toExact3CNF φ has at most three literals.
An assignment satisfies CNF.toExact3CNF φ exactly when its restriction satisfies φ and
every gate (i, k) of clause c = φ[i] has the value of the first k + 2 literals of c.
The variables of CNF.toExact3CNF φ: the variables of φ, and gate variables (i, k) with
k < c.length - 3 for the clause c = φ[i].
Every variable of φ is a variable of CNF.toExact3CNF φ.
Splitting into OR gates preserves the number of satisfying assignments
[OpenAI2026ETH, §2.8]: every satisfying assignment of φ has exactly one extension to the gate
variables satisfying CNF.toExact3CNF φ. This holds for every formula, including empty formulas,
empty clauses and repeated literals.
Splitting into OR gates preserves satisfiability.
The number of clauses after splitting: 3 (w - 3) + 1 for a clause of width w.
The number of literal occurrences after splitting: w + 6 (w - 3) for a clause of width
w.