Skip to content

[Model] OneInThreeSatisfiability #861

@isPANN

Description

@isPANN

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:

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?

**Canonical name:** One-in-Three 3-Satisfiability (also known as 1-in-3 SAT, Positive 1-in-3 SAT when no negated literals)

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 Literal type 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" (for declare_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

No one assigned

    Labels

    GoodAn issue passed all checks.modelA model problem to be implemented.

    Type

    No type

    Projects

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions