\(%\usepackage{color}\)
\(%\usepackage{tcolorbox}\)
\(%\tcbuselibrary{skins}\)
\(\usepackage{pifont}\)
\(\)
\(\definecolor{fakeaaltobluel}{RGB}{00,141,229} % 0065BD\)
\(\definecolor{aaltoblue}{RGB}{00,101,189} % 0065BD\)
\(\definecolor{aaltored}{RGB}{237,41,57} % ED2939\)
\(\)
\(\definecolor{MyBoxBackground}{rgb}{0.98,0.98,1.0}\)
\(\definecolor{MyBoxBorder}{rgb}{0.90,0.90,1.0}\)
\(\definecolor{backgroundred}{rgb}{1.0,0.98,0.98}\)
\(\definecolor{shadowred}{rgb}{1.0,0.90,0.90}\)
\(\)
\(%\newcommand{\subheading}[1]{\textbf{\large\color{fakeaaltobluel}#1}}\)
\(\newcommand{\subheading}[1]{\large{\usebeamercolor[fg]{frametitle} #1}}\)
\(\)
\(\)
\(%\newtcbox{\mybox}[1][red]{on line,arc=0pt,outer arc=0pt,colback=#1!10!white,colframe=#1!50!black,boxsep=0pt,left=1pt,right=1pt,top=2pt,bottom=2pt,boxrule=0pt,bottomrule=1pt,toprule=1pt}\)
\(%\newtcbox{\mybox}[1][MyBoxBackground]{on line,arc=0pt,outer arc=0pt,colback=#1!10!white,colframe=#1!50!black,boxsep=0pt,left=1pt,right=1pt,top=2pt,bottom=2pt,boxrule=0pt,bottomrule=1pt,toprule=1pt}\)
\(\)
\(\newtcolorbox{MyBoxTitled}[1]{colback=MyBoxBackground!100!black,colframe=MyBoxBorder!100!black,boxsep=2pt,left=0pt,right=0pt,top=2pt,bottom=0pt,%enhanced,%\)
\( coltitle=red!25!black,title=#1,boxrule=1pt}\)
\(\)
\(\newtcolorbox{MyBox}[1][]{colback=MyBoxBackground!100!black,colframe=MyBoxBorder!100!black,boxsep=0pt,left=2pt,right=0pt,top=0pt,bottom=0pt,%enhanced,%\)
\( coltitle=red!25!black,boxrule=1pt,#1}\)
\(\)
\(\newenvironment{EqnBox}[1]{\begin{adjustbox}{valign=t}\begin{minipage}{#1}\begin{MyBox}[colback=backgroundred!100!black,colframe=shadowred!100!black]}{\end{MyBox}\end{minipage}\end{adjustbox}}\)
\(\)
\(\newenvironment{topbox}[1]{\begin{adjustbox}{valign=t}\begin{minipage}{#1}}{\end{minipage}\end{adjustbox}}\)
\(\)
\(\newcommand{\Blue}[1]{{\color{aaltoblue}#1}}\)
\(\newcommand{\Red}[1]{{\color{aaltored}#1}}\)
\(%\newcommand{\Emph}[1]{\emph{\color{aaltoblue}#1}}\)
\(\newcommand{\Emph}[1]{\emph{\usebeamercolor[fg]{structure} #1}}\)
\(\newcommand{\TextDef}[1]{{\bf\usebeamercolor[fg]{structure} #1}}\)
\(\)
\(\newcommand{\todo}[1]{\textbf{\Red{\Pointer #1}}}\)
\(\newcommand{\TODO}[1]{\todo{#1}}\)
\(\)
\(\newcommand{\Pointer}{\raisebox{-1ex}{\huge\ding{43}}\ }\)
\(\)
\(\)
\(%\)
\(% Common math definitions\)
\(%\)
\(\newcommand{\Set}[1]{\{#1\}}\)
\(\newcommand{\Setdef}[2]{\{{#1}\mid{#2}\}}\)
\(\newcommand{\PSet}[1]{\mathcal{P}(#1)}\)
\(\newcommand{\Pair}[2]{(#1,#2)}\)
\(\newcommand{\Card}[1]{{\vert{#1}\vert}}\)
\(\newcommand{\Tuple}[1]{(#1)}\)
\(\newcommand{\Seq}[1]{[#1]}\)
\(\newcommand{\bbZ}{\mathbb{Z}}\)
\(\newcommand{\Ints}{\mathbb{Z}}\)
\(\newcommand{\Reals}{\mathbb{R}}\)
\(\newcommand{\bbQ}{\mathbb{Q}}\)
\(\newcommand{\Rats}{\bbQ}\)
\(\)
\(\newcommand{\False}{\textsf{F}}\)
\(\newcommand{\True}{\textsf{T}}\)
\(\)
\(\newcommand{\Implies}{\rightarrow}\)
\(\newcommand{\Iff}{\leftrightarrow}\)
\(%\newcommand{\Implies}{\Rightarrow}\)
\(%\newcommand{\Iff}{\Leftrightarrow}\)
\(\newcommand{\Xor}{\oplus}\)
\(\)
\(\newcommand{\Equiv}{\equiv}\)
\(\)
\(\newcommand{\Oh}[1]{O(#1)}\)
\(%\newcommand{\Theta}[1]{\Theta(#1)}\)
\(\)
\(\newcommand{\PHP}[2]{\mathrm{php}_{#1,#2}}\)
\(\newcommand{\PH}[2]{\mathit{x}_{#1,#2}}\)
\(\)
\(\newcommand{\NP}{\textbf{NP}}\)
\(\newcommand{\coNP}{\textbf{co-NP}}\)
\(\)
\(\newcommand{\bnfdef}{\mathrel{\textup{::=}}}\)
\(\newcommand{\bnfor}{\mathrel{\mid}}\)
\(\)
\(\newcommand{\Constrs}{\mathcal{C}}\)
\(\newcommand{\Constr}{C}\)
\(\newcommand{\Vars}{X}\)
\(\newcommand{\Var}{x}\)
\(\newcommand{\VarI}[1]{x_{#1}}\)
\(\newcommand{\CVars}{Y}\)
\(\newcommand{\CVar}{y}\)
\(\newcommand{\CVarI}[1]{y_{#1}}\)
\(%\newcommand{\DomF}{\mathit{dom}}\)
\(\newcommand{\DomF}{D}\)
\(\newcommand{\Dom}[1]{\DomF(#1)}\)
\(\newcommand{\DomPF}{\DomF'}\)
\(\newcommand{\DomP}[1]{\DomPF(#1)}\)
\(\newcommand{\DomAF}{\DomF_\text{before}}\)
\(\newcommand{\DomA}[1]{\DomAF(#1)}\)
\(\newcommand{\DomBF}{\DomF_\text{after}}\)
\(\newcommand{\DomB}[1]{\DomBF(#1)}\)
\(\newcommand{\Val}{v}\)
\(\newcommand{\ValI}[1]{v_{#1}}\)
\(\newcommand{\Asgn}{\tau}\)
\(\newcommand{\AsgnTo}[1]{\Asgn(#1)}\)
\(\newcommand{\FixD}[3]{#1_{#2 \mapsto #3}}\)
\(\)
\(\newcommand{\GlobalConstraint}[1]{\textsf{#1}}\)
\(\newcommand{\AllDiffC}{\GlobalConstraint{alldifferent}}\)
\(\newcommand{\AllDiff}[1]{\AllDiffC(#1)}\)
\(\newcommand{\SumC}{\GlobalConstraint{sum}}\)
\(%\newcommand{\Sum}[1]{\SumC(#1)}\)
\(\newcommand{\Sum}[3]{\SumC_{#2}(#1,#3)}\)
\(\newcommand{\CumuC}{\GlobalConstraint{cumulative}}\)
\(\newcommand{\Cumu}[1]{\CumuC(#1)}\)
\(\)
\(\newcommand{\PseudoSolve}{\textit{solve}}\)
\(\newcommand{\PseudoAsgn}{\mathrel{\leftarrow}}\)
\(\newcommand{\PseudoUnsat}{\mathbf{unsat}}\)
\(\newcommand{\PseudoSat}{\mathbf{sat}}\)
\(\newcommand{\PseudoPropagate}{\textit{propagate}}\)
\(\)
\(\)
\(\newcommand{\sump}{p}\)
\(\)
Backtracking Search
How can we solve CSP instances? That is, how can we deduce whether a set of constraints is satisfiable or not, or to find an optimal solution for them?
When the domains are finite, CSP instances could be solved by
reducing the CSP instance to a SAT instance, and then
solving the SAT instance with a SAT solver.
Indeed, some CSP solvers do this.
However, performing a backtracking search and
constraint propagation on the global constraints level
can result in better performance as
the expansion of non-binary domains and global constraints
to the Boolean level can be quite large, and
one can use efficient custom algorithms for propagating global constraints.
Below is a very simple backtracking search procedure that
first performs constraint propagation, and
if the solution is not yet found,
selects a variable and then recursively searches for
a solution in which the variable has a fixed value from its domain.
def \( \PseudoSolve(\Constrs,\DomF) \):
\( \DomPF \PseudoAsgn \PseudoPropagate(\Constrs,\DomF) \)
if \( \Constrs \) has a constraint \( \Constr \) that is inconsistent under \( \DomPF \): return \( \PseudoUnsat \)
if \( \Card{\DomP{x}} = 1 \) for all the variables \( x \): return \( \PseudoSat \)
choose a variable \( x \) with \( \DomP{x} = \Set{v_1,...,v_k} \) and \( k \ge 2 \)
for each \( v \in \Set{v_1,...,v_k} \):
\( r \PseudoAsgn \PseudoSolve(\Constrs,\FixD{\DomPF}{x}{\Set{v}}) \)
if \( r = \PseudoSat \): return \( \PseudoSat \)
return \( \PseudoUnsat \)
Example
Consider a simple ARM architecture assembly program with symbolic register names below.
LDR a, a_addr // a_addr is the address of the input array
MOV i, #0 // i = 0
MOV s, #0 // s = 0
loop:
CMP i, #10 // if i >= 10, goto end
BGE end
LDR t, [a, i, LSL#2] // t = a[i]
MUL v, t, t // v = t * t
ADD s, s, v // s = s + v
ADD i, i, #1 // i = i + 1
B loop
end:
LDR b, b_addr // save s to the memory location b_addr
STR s, [b]
If we perform a liveness analysis for the registers,
we get a register-inference graph (see e.g. Aho, Sethi, and Ullman: “Compilers: Principles, Techniques, and Tools”) shown below. It has an edge between register nodes if and only if there is a line in which one register is written to and the other can be read later without being written to in between.
The graph is \( k \)-colorable iff the program can be implemented by using only \( k \) hardware registers and no spills to the memory.
The graph \( k \)-coloring problem can be easily expressed as a CSP problem
by taking a variable for each vertex.
The domain of all the variables is a set of \( k \) colors.
The constraints are \( x \neq y \) for each edge between \( x \) and \( y \) in the graph.
In our simple example, the constraints are
$$\begin{array}{lll}
a \neq i & a \neq s & a \neq t & a \neq v & i \neq s \\\\
i \neq t & i \neq v & s \neq t & s \neq v & s \neq b &
\end{array}$$
A search tree for our instance when three colors are allowed is shown below.
Each node describes
the domains either when entering the solve
call or after
constraint propagation.
The instance has no solutions as all the branches end in a situation where
the domain of some variable is empty.
Our example graph is colorable with 4 colors and thus the program can be
implemented with 4 registers:
LDR R0, a_addr // a_addr is the address of the input array
MOV R1, #0 // i = 0
MOV R2, #0 // s = 0
loop:
CMP R1, #10 // if i >= 10, goto end
BGE end
LDR R3, [R0, R1, LSL#2] // t = a[i]
MUL R3, R3, R3 // v = t * t
ADD R2, R2, R3 // s = s + v
ADD R1, R1, #1 // i = i + 1
B loop
end:
LDR R3, b_addr // save s to the memory location b_addr
STR R2, [R3]
The above description of the backtracking search scheme is
simplified and omits many details.
For instance,
the variable selection heuristic,
i.e. how one chooses the variable \( x \) whose domain \( \Set{v_1,…,v_k} \)
is split into \( \Set{v_1} \),…,\( \Set{v_k} \),
is very important but not discussed further in this course.
And one could also split the domain \( \Set{v_1,…,v_k} \) of the branching variable \( x \) differently,
for instance into \( \Set{v_1,…,v_{k/2}} \) and \( \Set{v_{k/2+1},…,v_k} \)
if \( k \) is large.
Some solvers allow the user to control these aspects and thus tune the solver
for specific problem types.