-
Notifications
You must be signed in to change notification settings - Fork 3
[Model] OneInThreeSatisfiability #861
Description
Motivation
ONE-IN-THREE 3SAT (P256) from Garey & Johnson, A9 LO4. Given a 3-CNF formula, determine whether there is a truth assignment such that each clause has exactly one true literal. NP-complete even without negated literals (Schaefer, 1978). A key problem in Schaefer's dichotomy theorem framework for generalized satisfiability, and widely used as a source for reductions to graph coloring, partition, and geometric problems.
Associated rules:
- [Rule] 3SAT to ONE-IN-THREE 3SAT #862: 3SAT → OneInThreeSatisfiability (classical NP-completeness proof from G&J)
Definition
Name: OneInThreeSatisfiability
Reference: Garey & Johnson, Computers and Intractability, A9 LO4
Mathematical definition:
INSTANCE: Set U of variables, collection C of clauses over U such that each clause c ∈ C has |c| = 3.
QUESTION: Is there a truth assignment for U such that each clause in C has exactly one true literal?
Variables
- Count: n = |U| (one variable per Boolean variable)
- Per-variable domain: binary {0, 1} (false/true)
- Meaning: x_i = 1 if variable u_i is assigned true. A clause is satisfied iff exactly one of its three literals evaluates to true.
Schema (data type)
Type name: OneInThreeSatisfiability
Variants: none (clause size is always 3)
| Field | Type | Description |
|---|---|---|
num_vars |
usize |
Number of Boolean variables |
clauses |
Vec<[Literal; 3]> |
Clauses each with exactly 3 literals |
Notes:
- This is a feasibility (decision) problem:
Value = Or. - Structurally identical to
KSatisfiability<K3>, but the evaluation criterion differs — each clause requires exactly one true literal instead of at least one. - Key getter methods:
num_vars(),num_clauses()(= clauses.len()). - The
Literaltype encodes a variable index and its polarity (positive or negated).
Complexity
- Decision complexity: NP-complete (Schaefer, 1978; transformation from 3SAT). Remains NP-complete even if no clause contains a negated literal (Positive 1-in-3 SAT).
- Best known exact algorithm: Any 3-SAT exact algorithm can solve 1-in-3 SAT by modifying the acceptance criterion. The best known 3-SAT algorithm runs in O*(1.307^n) (Scheder & Steinberger, 2017). No dedicated 1-in-3 SAT algorithm with a provably better worst-case bound has been established in the literature.
- Concrete complexity expression:
"1.307^num_vars"(fordeclare_variants!; conservative upper bound via 3-SAT reduction) - References:
- T.J. Schaefer (1978). "The Complexity of Satisfiability Problems." STOC 1978, pp. 216-226.
- D. Scheder, J.P. Steinberger (2017). "PPSZ for General k-SAT — Making Hertli's Analysis Simpler and 3-SAT Faster." CCC 2017.
Specialization
- This is a special case of: Generalized Satisfiability (Schaefer's framework — the one-in-three constraint is a specific relation R)
- Known special cases: Positive One-in-Three 3SAT (no negated literals — still NP-complete)
- Restriction: Each clause has exactly 3 literals and exactly one must be true (vs. at-least-one for standard SAT, or not-all-equal for NAE-SAT)
- Relationship to NAE-SAT: If σ satisfies a One-in-Three instance, then both σ and ¬σ satisfy the corresponding NAE-SAT instance (one true and two false in each clause means not-all-equal holds)
Extra Remark
Full book text:
INSTANCE: Set U of variables, collection C of clauses over U such that each clause c∈C has |c|=3.
QUESTION: Is there a truth assignment for U such that each clause in C has exactly one true literal?
Reference: [Schaefer, 1978b]. Transformation from 3SAT.
Comment: Remains NP-complete even if no c∈C contains a negated literal.
How to solve
- It can be solved by (existing) bruteforce. (Enumerate all 2^n truth assignments; check if each clause has exactly one true literal.)
- It can be solved by reducing to integer programming. (Binary variable per Boolean variable; for each clause with literals l_1, l_2, l_3, add constraint l_1 + l_2 + l_3 = 1 where negated literals use 1 − x_i. Companion rule issue to be filed separately.)
- Other:
Example Instance
Input:
n = 6 variables: x_1, x_2, x_3, x_4, x_5, x_6
m = 4 clauses (each requires exactly one true literal):
- C_1 = R(x_1, x_2, x_3)
- C_2 = R(x_4, x_5, x_6)
- C_3 = R(x_1, x_5, x_3)
- C_4 = R(x_2, x_4, x_6)
Satisfying assignment: x_1=T, x_2=F, x_3=F, x_4=F, x_5=F, x_6=T
- C_1: T, F, F → exactly 1 true ✓
- C_2: F, F, T → exactly 1 true ✓
- C_3: T, F, F → exactly 1 true ✓
- C_4: F, F, T → exactly 1 true ✓
Answer: YES — 5 out of 64 assignments satisfy all clauses.
Non-trivial structure: A greedy approach setting x_1=T and x_4=T would fail C_4 (needing x_2=F and x_6=F, but then C_2 has x_4=T, x_5=?, x_6=F requiring x_5=F, which gives C_3: x_1=T, x_5=F, x_3=? requiring x_3=F, so C_1: T,F,F ✓ — actually this also works with (1,0,0,1,0,0)). The 5 valid assignments are: (1,0,0,1,0,0), (0,0,1,1,0,0), (0,1,0,0,1,0), (1,0,0,0,0,1), (0,0,1,0,0,1).
Negative modification: Add clause C_5 = R(x_1, x_4, x_5). This forces exactly one of x_1, x_4, x_5 to be true. Of the 5 satisfying assignments above, only (0,1,0,0,1,0) satisfies C_5 (x_1=F, x_4=F, x_5=T → exactly 1). Now change C_5 to R(x_1, x_2, x_4). This requires exactly one of x_1, x_2, x_4 true. Checking: (1,0,0,1,0,0) has x_1=T, x_2=F, x_4=T → 2 true ✗. (0,0,1,1,0,0): x_1=F, x_2=F, x_4=T → 1 true ✓. (0,1,0,0,1,0): x_1=F, x_2=T, x_4=F → 1 true ✓. (1,0,0,0,0,1): x_1=T → 1 true ✓. (0,0,1,0,0,1): 0 true ✗. Down to 3. Adding C_6 = R(x_3, x_4, x_5): (0,0,1,1,0,0) has x_3=T, x_4=T → 2 ✗. (0,1,0,0,1,0) has x_3=F, x_4=F, x_5=T → 1 ✓. (1,0,0,0,0,1) has 0 ✗. Down to 1: (0,1,0,0,1,0). Adding C_7 = R(x_1, x_6, x_5): (0,1,0,0,1,0) has x_5=T → 1 ✓. Still satisfiable. Adding C_8 = R(x_2, x_5, x_6): (0,1,0,0,1,0) has x_2=T, x_5=T → 2 ✗. Answer: NO — no assignment satisfies all 8 clauses.
Python validation script
# Positive example (4 clauses)
def one_in_three(x, clause):
return sum(x[i] for i in clause) == 1
solutions = []
for bits in range(64):
x = {i+1: (bits >> i) & 1 for i in range(6)}
clauses = [[1,2,3], [4,5,6], [1,5,3], [2,4,6]]
if all(one_in_three(x, c) for c in clauses):
solutions.append(tuple(x[i] for i in range(1,7)))
assert len(solutions) == 5
assert (1,0,0,0,0,1) in solutions
print(f"Positive: {len(solutions)}/64 satisfying")
# Negative: add clauses until unsatisfiable
extra = [[1,2,4], [3,4,5], [1,6,5], [2,5,6]]
all_clauses = [[1,2,3], [4,5,6], [1,5,3], [2,4,6]] + extra
neg_count = 0
for bits in range(64):
x = {i+1: (bits >> i) & 1 for i in range(6)}
if all(one_in_three(x, c) for c in all_clauses):
neg_count += 1
assert neg_count == 0
print(f"Negative (8 clauses): {neg_count}/64 satisfying (correct)")Metadata
Metadata
Assignees
Labels
Type
Projects
Status