Satisfiability problem

Note

It is highly recommended to read the Independent set problem chapter before reading this one.

Problem definition

In logic and computer science, the boolean satisfiability problem is the problem of determining if there exists an interpretation that satisfies a given boolean formula. One can specify a satisfiable problem in the conjunctive normal form. In boolean logic, a formula is in conjunctive normal form (CNF) if it is a conjunction (∧) of one or more clauses, where a clause is a disjunction (∨) of literals.

using GenericTensorNetworks

@bools a b c d e f g

cnf = ∧(∨(a, b, ¬d, ¬e), ∨(¬a, d, e, ¬f), ∨(f, g), ∨(¬b, c))
(a ∨ b ∨ ¬d ∨ ¬e) ∧ (¬a ∨ d ∨ e ∨ ¬f) ∧ (f ∨ g) ∧ (¬b ∨ c)

To goal is to find an assignment to satisfy the above CNF. For a satisfiability problem at this size, we can find the following assignment to satisfy this assignment manually.

assignment = Dict([:a=>true, :b=>false, :c=>false, :d=>true, :e=>false, :f=>false, :g=>true])

satisfiable(cnf, assignment)
true

Generic tensor network representation

We can use Satisfiability to construct the tensor network for solving the satisfiability problem as

sat = Satisfiability(cnf)
Satisfiability{Symbol, UnitWeight}((a ∨ b ∨ ¬d ∨ ¬e) ∧ (¬a ∨ d ∨ e ∨ ¬f) ∧ (f ∨ g) ∧ (¬b ∨ c), UnitWeight())

The tensor network representation of the satisfiability problem can be obtained by

problem = GenericTensorNetwork(sat)
GenericTensorNetwork{Satisfiability{Symbol, UnitWeight}, OMEinsum.DynamicNestedEinsum{Symbol}, Symbol}(Satisfiability{Symbol, UnitWeight}((a ∨ b ∨ ¬d ∨ ¬e) ∧ (¬a ∨ d ∨ e ∨ ¬f) ∧ (f ∨ g) ∧ (¬b ∨ c), UnitWeight()), f, f-g -> 
├─ b-f, b-c -> f
│  ├─ a-b-d-e, a-d-e-f -> b-f
│  │  ├─ a-b-d-e
│  │  └─ a-d-e-f
│  └─ b-c
└─ f-g
, Dict{Symbol, Int64}())

Theory (can skip)

We can construct a Satisfiability problem to solve the above problem. To generate a tensor network, we map a boolean variable $x$ and its negation $\neg x$ to a degree of freedom (label) $s_x \in \{0, 1\}$, where 0 stands for variable $x$ having value false while 1 stands for having value true. Then we map a clause to a tensor. For example, a clause $¬x ∨ y ∨ ¬z$ can be mapped to a tensor labeled by $(s_x, s_y, s_z)$.

\[C = \left(\begin{matrix} \left(\begin{matrix} x & x \\ x & x \end{matrix}\right) \\ \left(\begin{matrix} x & x \\ 1 & x \end{matrix}\right) \end{matrix}\right).\]

There is only one entry $(s_x, s_y, s_z) = (1, 0, 1)$ that makes this clause unsatisfied.

Solving properties

Satisfiability and its counting

The size of a satisfiability problem is defined by the number of satisfiable clauses.

num_satisfiable = solve(problem, SizeMax())[]
4.0ₜ

The GraphPolynomial of a satisfiability problem counts the number of solutions that k clauses satisfied.

num_satisfiable_count = read_size_count(solve(problem, GraphPolynomial())[])
5-element Vector{Pair{Int64, BigInt}}:
 0 => 0
 1 => 0
 2 => 12
 3 => 56
 4 => 60

Find one of the solutions

single_config = read_config(solve(problem, SingleConfigMax())[])
1111111

One will see a bit vector printed. One can create an assignment and check the validity with the following statement:

satisfiable(cnf, Dict(zip(labels(problem), single_config)))
true

This page was generated using Literate.jl.