This guide shows how to create a solver, add clauses, and check satisfiability.
Simple SAT problem
Here’s a complete example that solves a simple SAT problem:
#include "minisat/core/Solver.h"
#include <iostream>
using namespace Minisat;
int main() {
// Create solver instance
Solver solver;
// Create three boolean variables
Var x = solver.newVar();
Var y = solver.newVar();
Var z = solver.newVar();
// Add clause: (x OR y)
solver.addClause(mkLit(x), mkLit(y));
// Add clause: (NOT x OR NOT y OR z)
solver.addClause(~mkLit(x), ~mkLit(y), mkLit(z));
// Add clause: (NOT z)
solver.addClause(~mkLit(z));
// Solve the formula
bool sat = solver.solve();
if (sat) {
std::cout << "SAT" << std::endl;
std::cout << "x = " << (solver.modelValue(x) == l_True ? "true" : "false") << std::endl;
std::cout << "y = " << (solver.modelValue(y) == l_True ? "true" : "false") << std::endl;
std::cout << "z = " << (solver.modelValue(z) == l_True ? "true" : "false") << std::endl;
} else {
std::cout << "UNSAT" << std::endl;
}
return 0;
}
Instantiate the Solver class:
Use newVar() to create boolean variables. Variables are represented as integers:
Var x = solver.newVar();
Var y = solver.newVar();
Literals are created using mkLit(). Use ~ for negation:
Lit pos_x = mkLit(x); // positive literal
Lit neg_x = ~mkLit(x); // negative literal (NOT x)
Clauses can be added in several ways:
// Unit clause
solver.addClause(mkLit(x));
// Binary clause
solver.addClause(mkLit(x), mkLit(y));
// Ternary clause
solver.addClause(mkLit(x), mkLit(y), mkLit(z));
// Quaternary clause
solver.addClause(mkLit(x), mkLit(y), mkLit(z), mkLit(w));
// Arbitrary length using vec<Lit>
vec<Lit> clause;
clause.push(mkLit(x));
clause.push(~mkLit(y));
solver.addClause(clause);
Call solve() to check satisfiability:
bool sat = solver.solve();
if (sat) {
// Formula is satisfiable
} else {
// Formula is unsatisfiable
}
If satisfiable, extract variable assignments:
if (sat) {
lbool val_x = solver.modelValue(x);
if (val_x == l_True) {
std::cout << "x is true" << std::endl;
} else if (val_x == l_False) {
std::cout << "x is false" << std::endl;
}
}
Checking solver state
You can check if the solver is in a consistent state:
if (!solver.okay()) {
// Solver detected a conflict during clause addition
std::cout << "Formula is trivially UNSAT" << std::endl;
}
The okay() method returns false if the solver has detected that the formula is unsatisfiable during clause addition or simplification.
Getting solver statistics
Access solver statistics after solving:
std::cout << "Variables: " << solver.nVars() << std::endl;
std::cout << "Clauses: " << solver.nClauses() << std::endl;
std::cout << "Decisions: " << solver.decisions << std::endl;
std::cout << "Conflicts: " << solver.conflicts << std::endl;
std::cout << "Propagations: " << solver.propagations << std::endl;
// Or print all statistics
solver.printStats();
Simplification
Call simplify() to perform unit propagation and remove satisfied clauses:
if (!solver.simplify()) {
std::cout << "UNSAT by simplification" << std::endl;
return;
}
bool sat = solver.solve();
Simplification is automatically performed during solving, but you can call it explicitly to detect unsatisfiability early.