February 20, 2026
Ilario Bonacina
ilario.bonacina@upc.edu
Office: \Omega-223
Groups: 11L and 22L
Meeting times: Wed 11:00-13:00 (book here)
Course Info
6 practical assignments (2 labs on each one):
You need to understand the practical assignments and also do them!
Pràctica 1 – SAT solver
Pràctica 2 – Introduction to Prolog
Pràctica 3 – SAT encoding
Examen Laboratori 1 April 07, 15:30h (Pràctiques 1–3)
Pràctica 4 – SAT optimization
Pràctica 5 – Advanced Prolog
Pràctica 6 – Constrained Logic Programming
Examen Laboratori 2 June 02, 15:00h (Pràctiques 4–6)
X set of propositional variables (e.g., p, q, r, etc.)
F is a propositional formula (over the set of variables X) if
it is built from the variables in X and logical connectives
A propositional formula F is a CNF, if
Is the formula in CNF?
Any function I: X \to \{0, 1\} is an interpretation.
1 means true, and 0 means false.
How many distinct interpretations are there when |X|=n?
I: X \to \{0, 1\} can be extended to a function I: \text{Formulas} \to \{0, 1\} in the natural way.
What is I(p \land (q \lor \lnot r)) if
I(p) = 1
I(q) = 0
I(r) = 1?
I: X \to \{0, 1\} interpretation
F propositional formula
I\models F means
F evaluates to true (1) under the interpretation I.
F is satisfiable means
there is at least one interpretation I that makes the formula true. Otherwise F is unsatisfiable.
How many models have
SAT
Input: a propositional formula F
Output: Yes/No, Yes if F is satisfiable.
CNF-SAT
Input: a propositional formula F in Conjunctive Normal Form (CNF) Output: Yes/No, Yes if F is satisfiable.
k-SAT
Input: a propositional formula F in CNF where each clause has exactly k literals
Output: Yes/No, Yes if F is satisfiable.
What do you remember about SAT / CNF-SAT / k-SAT?
Sudoku, graph coloring, and many other combinatorial problems can be encoded as CNF-SAT problems.
How could you encode Sudoku as a CNF-SAT problem?
In this course we will:
.cnf DIMACS CNF format.cnf file as inputThis first practical assignment has the following objectives:
To achieve this, you will need to improve the efficiency of a SAT solver that is provided to you.
https://www.cs.upc.edu/~li/practica1.html
Deadline: 08/03/2026 23:59
SAT-alumnes.cpp, i temps.txt with the output of the script
Each clause is a sequence of integers ending with 0:
k represents the literal x_k
-k represents the literal \lnot x_k
SAT-alumnes.cppSAT-alumnes.cpp from the course webpage, the Makefile and compile with make.misat on some simple .cnf example.All set?
Install Kissat, unless it is already installed on your system.
Kissat is a state-of-the-art CDCL SAT solver.
How fast is Kissat on the files in random3SAT.tar.gz?
How bad is misat compared to Kissat?
Important
Your improved version of SAT-alumnes.cpp should be able to solve the files in random3SAT.tar.gz in a reasonable time (< 20 times slower than Kissat).
(chmod +x file.sh to misat executable) time ./misat < vars-100-01.cnf
e.g. to see how fast it is time kissat vars-100-01.cnf | egrep "^s|^v"
You’ll test your SAT-solver on random 3-CNFs with up to 300 variables
i.e., formulas in CNF where each clause has exactly 3 literals generated by the following random process:
Why this benchmark and not others?
All SAT-solvers struggle with random 3-CNFs with a certain ratio \Delta=m/n, and this is a well-known benchmark in the SAT community. What is the \Delta for the formulas in random3SAT.tar.gz?
CNFgen produces benchmark propositional formulas in DIMACS format, ready to be fed to SAT solvers. Many of these formulas encode structured combinatorial problems well known to be challenging for certain SAT solvers.
pip3 install [--user] cnfgen
for example cnfgen php 10 7 gives the Pigeonhole Principle from 10 pigeons and 7 holes.
Important
You are not required to compare your SAT-solver and kissat against CNFgen benchmarks. But it might be fun to see how they compare on some of them.
SAT-alumnes.cppint main(){
readClauses(); // reads numVars, numClauses and clauses
model.resize(numVars+1,UNDEF);
indexOfNextLitToPropagate = 0;
decisionLevel = 0;
// Take care of initial unit clauses, if any
for (uint i = 0; i < numClauses; ++i)
if (clauses[i].size() == 1) {
int lit = clauses[i][0];
int val = currentValueInModel(lit);
if (val == FALSE) {cout << "UNSATISFIABLE" << endl; return 10;}
else if (val == UNDEF) setLiteralToTrue(lit);
}
// DPLL algorithm
while (true) {
while ( propagateGivesConflict() ) { #<1>
if ( decisionLevel == 0) { cout << "UNSATISFIABLE" << endl; return 10; }
backtrack();
}
int decisionLit = getNextDecisionLiteral();
if (decisionLit == 0) { checkmodel(); cout << "SATISFIABLE" << endl; return 20; }
// start new decision level:
modelStack.push_back(0); // push mark indicating new DL
++indexOfNextLitToPropagate;
++decisionLevel;
setLiteralToTrue(decisionLit); // now push decisionLit on top of the mark
}
} propagateGivesConflict() function unit propagates until it is no longer possible, and returns true if a conflict is found, i.e., if some clause is falsified by the current model.propagateGivesConflict()getNextDecisionLiteral()propagateGivesConflict()bool propagateGivesConflict ( ) {
while ( indexOfNextLitToPropagate < modelStack.size() ) {
++indexOfNextLitToPropagate;
for (uint i = 0; i < numClauses; ++i) { # <1>
bool someLitTrue = false;
int numUndefs = 0;
int lastLitUndef = 0;
for (uint k = 0; not someLitTrue and k < clauses[i].size(); ++k){
int val = currentValueInModel(clauses[i][k]);
if (val == TRUE) someLitTrue = true;
else if (val == UNDEF){ ++numUndefs; lastLitUndef = clauses[i][k]; }
}
if (not someLitTrue and numUndefs == 0) return true; // conflict! all lits false
else if (not someLitTrue and numUndefs == 1) setLiteralToTrue(lastLitUndef);
}
}
return false;
}OccurLists to keep track of the clauses relevant to the current propagation step.getNextDecisionLiteral()// Heuristic for finding the next decision literal:
int getNextDecisionLiteral(){
for (uint i = 1; i <= numVars; ++i) // stupid heuristic: #<1>
if (model[i] == UNDEF) return i; // returns first UNDEF var, positively
return 0; // reurns 0 when all literals are defined
}SAT-alumnes.cpp