\(%\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{\bbN}{\mathbb{N}}\) \(\newcommand{\Nats}{\bbN}\) \(\) \(\newcommand{\Floor}[1]{\lfloor #1 \rfloor}\) \(\newcommand{\Ceil}[1]{\lceil #1 \rceil}\) \(\) \(\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{\Def}{\mathrel{:=}}\) \(\) \(\newcommand{\LSF}{\alpha}\) \(\newcommand{\RSF}{\beta}\) \(\newcommand{\SF}{\phi}\) \(\newcommand{\MF}{\gamma}\) \(%\newcommand{\Abbrv}{\equiv}\) \(\newcommand{\Abbrv}{\Def}\) \(\newcommand{\AbbrvEq}{\equiv}\) \(\newcommand{\Exists}[2]{\exists{#1}.\,#2}\) \(%\newcommand{\E}[3]{\exists{#1{:}#2}.\,#3}\) \(\newcommand{\E}[3]{\exists{#1{:}\,#3}}\) \(\newcommand{\Forall}[2]{\forall{#1}.\,#2}\) \(%\newcommand{\Furall}[3]{\forall{#1{:}#2}.\,#3}\) \(%\newcommand{\A}[3]{\forall{#1{:}#2}.\,#3}\) \(\newcommand{\A}[3]{\forall{#1{:}\,#3}}\) \(\newcommand{\Models}{\models}\) \(\newcommand{\NotModels}{\not\models}\) \(\) \(\newcommand{\Substf}[3]{#1[#2 \mapsto #3]}\) \(\newcommand{\Functions}[2]{[#1 \to #2]}\) \(\) \(\) \(\newcommand{\Eq}{\approx}\) \(\newcommand{\EqS}[1]{\approx_{#1}}\) \(\newcommand{\Neq}{\not\approx}\) \(\) \(%\newcommand{\Th}{\mathcal{T}}\) \(\newcommand{\Th}{T}\) \(\newcommand{\ThI}[1]{\Th_{#1}}\) \(\) \(\newcommand{\Sig}{\Sigma}\) \(\newcommand{\SigI}[1]{\Sigma_{#1}}\) \(\newcommand{\Interp}{I}\) \(%\newcommand{\Interp}{{\mathcal{I}}}\) \(\newcommand{\InterpOf}[1]{#1^\Interp}\) \(\newcommand{\InterpIOf}[2]{#2^{#1}}\) \(\newcommand{\InterpRestr}[1]{\Interp^{#1}}\) \(\newcommand{\InterpI}[1]{I_{#1}}\) \(%\newcommand{\InterpI}[1]{{\mathcal{I}_{#1}}}\) \(%\newcommand{\InterpIOf}[2]{#2^{\InterpI{#1}}}\) \(\newcommand{\InterpDom}{D_{\Interp}}\) \(\newcommand{\InterpSubst}[2]{\Interp[{#1}\mapsto{#2}]}\) \(\newcommand{\ThModels}{\mathrel{\models_{\Th}}}\) \(\newcommand{\ThIModels}[1]{\mathrel{\models_{\ThI{#1}}}}\) \(\) \(% Example interpretations\) \(\newcommand{\IInts}{\InterpI{\textrm{ints}}}\) \(\newcommand{\IIntsOf}[1]{\InterpIOf{\IInts}{#1}}\) \(\newcommand{\IMods}{\InterpI{\textrm{mod7}}}\) \(\newcommand{\IModsOf}[1]{\InterpIOf{\IMods}{#1}}\) \(\newcommand{\ISilly}{\InterpI{\textrm{silly}}}\) \(\newcommand{\ISillyOf}[1]{\InterpIOf{\ISilly}{#1}}\) \(\) \(\) \(%\newcommand{\El}[1]{\textup{e}_{#1}}\) \(\) \(\newcommand{\ElemI}{\textup{\ding{40}}}\) \(\newcommand{\ElemII}{\textup{\ding{41}}}\) \(\newcommand{\ElemIII}{\textup{\ding{46}}}\) \(\) \(\newcommand{\ElemA}{\circ}\) \(\newcommand{\ElemB}{\bullet}\) \(\) \(\newcommand{\AxiomMarg}[1]{\makebox{}\hfill(\Blue{#1})}\) \(\newcommand{\Comment}[1]{\makebox{}\hfill\Blue{#1}}\) \(\) \(\newcommand{\DLZ}{\mathit{DL}(\bbZ)}\) \(\newcommand{\DLQ}{\mathit{DL}(\bbQ)}\) \(\newcommand{\EUF}{\mathit{EUF}}\) \(\newcommand{\TEUF}{\ThI{\mathit{EUF}}}\) \(\newcommand{\LIA}{\mathit{LIA}}\) \(\newcommand{\TLIA}{\ThI{\mathit{LIA}}}\) \(\newcommand{\TNRA}{\ThI{\mathit{NRA}}}\) \(\newcommand{\TNIA}{\ThI{\mathit{NIA}}}\) \(\newcommand{\LRA}{\mathit{LRA}}\) \(\newcommand{\TLRA}{\ThI{\mathit{LRA}}}\) \(\newcommand{\IDL}{\mathit{IDL}}\) \(\newcommand{\RDL}{\mathit{RDL}}\) \(\newcommand{\EUFModels}{\mathrel{\models_{\TEUF}}}\) \(\newcommand{\EUFModelsNot}{\mathrel{{\not\models}_{\TEUF}}}\) \(\newcommand{\LIAModels}{\mathrel{\models_{\LIA}}}\) \(\newcommand{\LIANotModels}{\mathrel{\not\models_{\LIA}}}\) \(\newcommand{\LIAEntails}{\mathrel{\models_{\LIA}}}\) \(\newcommand{\IDLEntails}{\mathrel{\models_{\IDL}}}\) \(\newcommand{\NIAModels}{\mathrel{\models_{\TNIA}}}\) \(\newcommand{\Div}[2]{{{#1}\mid{#2}}}\) \(\) \(\newcommand{\Sort}{s}\) \(\newcommand{\SortI}[1]{s_{#1}}\) \(\newcommand{\Sorts}{S}\) \(\newcommand{\Func}{f}\) \(\newcommand{\Funcs}{F}\) \(\newcommand{\Pred}{p}\) \(\newcommand{\Preds}{P}\) \(\newcommand{\SortName}[1]{\textsf{#1}}\) \(\) \(\newcommand{\Var}{x}\) \(\newcommand{\Vars}{X}\) \(\newcommand{\BVar}{a}\) \(\newcommand{\BVars}{\mathcal{B}}\) \(\newcommand{\Val}{v}\) \(\) \(\newcommand{\DomOf}[1]{D_{#1}}\) \(\) \(\newcommand{\Term}{t}\) \(\newcommand{\TermI}[1]{t_{#1}}\) \(\newcommand{\TermP}[1]{t'}\) \(\newcommand{\Atom}{A}\) \(\) \(\) \(%\) \(% EUF\) \(%\) \(\newcommand{\UFEq}{\equiv}\) \(\newcommand{\UFEqP}{\mathrel{\equiv'}}\) \(\newcommand{\UFEqNot}{\not\equiv}\) \(\newcommand{\UFNeq}{\not\equiv}\) \(\) \(\) \(\) \(%\) \(% Arithmetics\) \(%\) \(\newcommand{\IntsSort}{\textrm{Int}}\) \(\newcommand{\IntsSig}{\SigI{\textrm{Int}}}\) \(\newcommand{\RealsSort}{\textrm{Real}}\) \(\newcommand{\Mul}{\mathbin{*}}\) \(\) \(%\) \(% Arrays\) \(%\) \(\newcommand{\IndexSort}{\SortName{idx}}\) \(%\newcommand{\IndexSort}{\SortName{index}}\) \(\newcommand{\ElemSort}{\SortName{elem}}\) \(%\newcommand{\ArraySort}{\SortName{array}}\) \(\newcommand{\ArraySort}{\SortName{arr}}\) \(\newcommand{\ArrSig}{\Sigma_{\mathit{arrays}}}\) \(\newcommand{\ArrE}[1]{\textrm{a}_{#1}}\) \(\) \(\) \(\newcommand{\TArrays}{\ThI{\mathit{arrays}}}\) \(\newcommand{\TArraysExt}{\ThI{\mathit{arrays}}^{=}}\) \(\newcommand{\ArrModels}{\mathrel{{\models_\mathit{arrays}}}}\) \(\) \(\) \(%\) \(% Theories of Lisp-like lists\) \(%\) \(\newcommand{\ThCons}{\ThI{\textrm{cons}}}\) \(\newcommand{\ThConsAcyclic}{\ThI{\textrm{cons+}}}\) \(\newcommand{\SigCons}{\SigI{\textrm{cons}}}\) \(\newcommand{\Cons}{\FuncName{cons}}\) \(\newcommand{\Car}{\FuncName{car}}\) \(\newcommand{\Cdr}{\FuncName{cdr}}\) \(\newcommand{\LAtom}{\PredName{atom}}\) \(% Sorted version additions\) \(\newcommand{\ListSort}{\SortName{list}}\) \(\newcommand{\Nil}{\FuncName{nil}}\) \(\newcommand{\Length}{\FuncName{length}}\) \(\) \(\) \(\newcommand{\BVT}{\ThI{\mathsf{BV}}}\) \(\newcommand{\BVSig}{\SigI{\mathsf{BV}}}\) \(\newcommand{\BVS}[1]{\SortName{[}#1\SortName{]}}\) \(%\newcommand{\BVS}[1]{[{#1}]}\) \(\newcommand{\BVAdd}[1]{\mathbin{{+}_{\BVS{#1}}}}\) \(\newcommand{\BVLE}[1]{\mathbin{{\le}_{\BVS{#1}}}}\) \(\newcommand{\BVGE}[1]{\mathbin{{\ge}_{\BVS{#1}}}}\) \(\newcommand{\BVSL}[1]{\mathbin{{\ll}_{\BVS{#1}}}}\) \(\newcommand{\BVTermB}[1]{\hat{t}_{(#1)}}\) \(%\newcommand{\BVTermBI}[2]{\hat{t}_{#1}^{(#2)}}\) \(\newcommand{\BVAtom}{\hat{A}}\) \(\newcommand{\BVXB}[1]{\hat{x}_{(#1)}}\) \(\newcommand{\BVYB}[1]{\hat{y}_{(#1)}}\) \(\newcommand{\BVVar}[1]{\hat{x}_{(#1)}}\) \(\) \(\) \(% SMTLIB logics\) \(\newcommand{\SMTLIBLogic}[1]{\textrm{#1}}\) \(\newcommand{\QFUF}{\SMTLIBLogic{QF\_UF}}\) \(\newcommand{\QFLIA}{\SMTLIBLogic{QF\_LIA}}\) \(\newcommand{\QFUFLRA}{\SMTLIBLogic{QF\_UFLRA}}\) \(\newcommand{\SMTLIBLIA}{\SMTLIBLogic{LIA}}\) \(\) \(\newcommand{\CG}[1]{G_{#1}}\) \(\newcommand{\DiffEdge}[1]{\overset{#1}{\longrightarrow}}\) \(\) \(\newcommand{\FuncName}[1]{\textsf{#1}}\) \(\newcommand{\PredName}[1]{\textsf{#1}}\) \(\newcommand{\ReadF}{\FuncName{read}}\) \(\newcommand{\Read}[2]{\ReadF(#1,#2)}\) \(\newcommand{\WriteF}{\FuncName{write}}\) \(\newcommand{\Write}[3]{\WriteF(#1,#2,#3)}\) \(\) \(\newcommand{\Abs}[1]{\alpha_{#1}}\) \(\) \(\newcommand{\Expl}[1]{\textit{explain}(#1)}\) \(\) \(\newcommand{\SMTAssertF}{\textsf{assert}}\) \(\newcommand{\SMTAssert}[1]{\SMTAssertF(#1)}\) \(\) \(\newcommand{\UFRoot}{\textit{parent}}\) \(\newcommand{\UFRootOf}[1]{{#1}.\UFRoot}\) \(\newcommand{\UFRank}{\textit{rank}}\) \(\newcommand{\UFRankOf}[1]{{#1}.\UFRank}\) \(\newcommand{\UFFind}[1]{\textsf{find}(#1)}\) \(\newcommand{\UFMerge}[2]{\textsf{merge}(#1,#2)}\) \(\) \(\newcommand{\CCPending}{\textit{pending}}\) \(\) \(\) \(%\) \(% Theory solver interface\) \(%\) \(\newcommand{\TSinit}[1]{\mathop{init}(#1)}\) \(\newcommand{\TSassert}[1]{\mathop{assert}(#1)}\) \(\newcommand{\TSretract}{\mathop{retract}()}\) \(\newcommand{\TSisSat}{\mathop{isSat}()}\) \(\newcommand{\TSgetModel}{\mathop{getModel}()}\) \(\newcommand{\TSgetImplied}{\mathop{getImplied}()}\) \(\newcommand{\TSexplain}[1]{\mathop{explain}(#1)}\) \(\) \(\) \(\newcommand{\VarsOf}[1]{\mathop{vars}(#1)}\) \(\) \(\newcommand{\Dist}[1]{\mathit{dist}(#1)}\) \(%\newcommand{\Dist}[1]{\mathit{dist}(#1)}\) \(\) \(%\) \(% Nelson-Oppen\) \(%\) \(\newcommand{\TComb}{\cup}\) \(\newcommand{\NOShared}[1]{\mathop{\textrm{shared}}(#1)}\) \(\newcommand{\NOPart}{P}\) \(\newcommand{\NOPartI}[1]{P_{#1}}\) \(%\newcommand{\NOEq}{\mathrel{\approx}}\) \(%\newcommand{\NOEqNot}{\mathrel{\not\approx}}\) \(\newcommand{\NOEq}{\mathrel{{\equiv_{P}}}}\) \(%\newcommand{\NOEq}{\stackrel{\NOPart}{\equiv}}\) \(\newcommand{\NOEqNot}{\mathrel{\not\equiv_{\NOPart}}}\) \(%\newcommand{\NOEqNot}{\stackrel{\NOPart}{\not\equiv}}\) \(\newcommand{\NOArr}{\mathop{arr}(P)}\) \(\newcommand{\NOArrI}[1]{\mathop{arr}(P_{#1})}\) \(\) \(%\) \(% Example formulas in Nelson-Oppen part\) \(%\) \(\newcommand{\NOF}{\phi}\) \(%\newcommand{\NOFA}{\phi_1}\) \(%\newcommand{\NOFB}{\phi_2}\) \(%\newcommand{\NOTA}{\ThI{1}}\) \(%\newcommand{\NOTB}{\ThI{2}}\) \(\newcommand{\NOFEUF}{\phi_\mathit{EUF}}\) \(\newcommand{\NOFLIA}{\phi_\mathit{LIA}}\) \(\newcommand{\NOFLRA}{\phi_\mathit{LRA}}\) \(\newcommand{\NOFCons}{\phi_\textup{cons}}\) \(\) \(%\newcommand{\Asgn}{\mathrel{:=}}\) \(\newcommand{\Asgn}{\mathrel{\leftarrow}}\) \(\) \(%\newcommand{\Engl}[1]{(engl.\ #1)}\) \(\) \(\newcommand{\Ack}[1]{\mathop{ack}(#1)}\) \(\newcommand{\VVar}[1]{v_{#1}}\) \(\newcommand{\FVar}[2]{{#1}_{#2}}\) \(\newcommand{\PVar}[2]{{#1}_{#2}}\) \(\newcommand{\Flat}{{\phi_\textrm{flat}}}\) \(\newcommand{\Cong}{{\phi_\textrm{cong}}}\) \(\) \(\newcommand{\In}{\mathit{in}}\) \(\newcommand{\Out}{\mathit{out}}\) \(\) \(\newcommand{\SubType}{\FuncName{subtype}}\) \(\) \(%\) \(% Fourier-Motzkin elimination\) \(%\) \(\newcommand{\FM}{\phi}\) \(\newcommand{\FMup}{\phi^\textrm{up}}\) \(\newcommand{\FMlo}{\phi^\textrm{low}}\) \(%\newcommand{\FMup}{\phi^{\le}}\) \(%\newcommand{\FMlo}{\phi^{\ge}}\) \(\newcommand{\FMindep}{\phi^{\ast}}\) \(\newcommand{\Nup}{n^\textrm{up}}\) \(\newcommand{\Nlo}{n^\textrm{low}}\) \(%\newcommand{\Nup}{n^{\le}}\) \(%\newcommand{\Nlo}{n^{\ge}}\) \(\newcommand{\Rup}[1]{A^\textrm{up}_{#1}}\) \(\newcommand{\Rlo}[1]{A^\textrm{low}_{#1}}\) \(%\newcommand{\Rup}[1]{A^{\le}_{#1}}\) \(%\newcommand{\Rlo}[1]{A^{\ge}_{#1}}\) \(%\newcommand{\FMless}{\mathrel{\triangleleft}}\) \(%\newcommand{\FMmore}{\mathrel{\triangleright}}\) \(\) \(\) \(\) \(\newcommand{\ProblemName}[1]{\textup{#1}}\) \(\newcommand{\ATM}{A_\textup{TM}}\) \(\newcommand{\PCP}{\ProblemName{PCP}}\) \(\newcommand{\MPCP}{\ProblemName{MPCP}}\) \(\newcommand{\PCPAst}{\star}\) \(\) \(\newcommand{\Eps}{\varepsilon}\) \(\) \(\newcommand{\List}[1]{[#1]}\) \(\newcommand{\Strings}[1]{\{#1\}^\star}\) \(\newcommand{\StringsOver}[1]{{#1}^\star}\) \(\newcommand{\SigmaStrings}{\Sigma^\star}\) \(\newcommand{\GammaStrings}{\Gamma^\star}\) \(\newcommand{\Complement}[1]{\overline{#1}}\) \(\) \(\) \(%\) \(% SSA example\) \(%\) \(\newcommand{\In}{\mathit{in}}\) \(\newcommand{\Out}{\mathit{out}}\) \(\) \(%\) \(%\) \(%\) \(\newcommand{\DA}{♠}\) \(\newcommand{\DB}{♣}\) \(\newcommand{\DC}{♥}\) \(\newcommand{\DD}{♦}\) \(\) \(%\) \(% Jobshop example\) \(%\) \(\newcommand{\JSJobs}{J}\) \(\newcommand{\JSJob}[1]{J_{#1}}\) \(\newcommand{\JSForm}{\phi(\JSJobs)}\) \(\newcommand{\JSNofTasks}[1]{N_{#1}}\) \(\newcommand{\JSTask}[2]{T_{#1,#2}}\) \(\newcommand{\JSMach}[2]{M_{#1,#2}}\) \(\newcommand{\JSDur}[2]{D_{#1,#2}}\) \(\newcommand{\JSStart}[2]{s_{#1,#2}}\) \(\newcommand{\JSBudget}{\mathit{budget}}\)

A Theory Solver for Equality with Uninterpreted Functions

We now present a decision procedure for quantifier-free conjunctions of \( \TEUF \)-literals. The explanation is only a high-level sketch; details, optimizations and analysis can be found in the references given later.

Recall that the theory \( \TEUF \) allows arbitrary interpretations for the function symbols as long as they are functions. That is, the function congruence rule \( (v_1 = w_1) \land … \land (v_n = w_n) \Implies f(v_1,…,v_n)=f(w_1,…,w_n) \), where the \( v \)’s and \( w \)’s are values, must always hold. We can lift this rule to the level of symbolic terms as follows. Assume that we have an equivalence relation \( \UFEq \) over a set of terms. We say that the relation is closed under the function congruence rule if \[(t_1 \UFEq u_1) \land … \land (t_n \UFEq u_n) \Implies f(t_1,…,t_n) \UFEq f(u_1,…,u_n)\] holds whenever \( t_1,…,t_n,u_1,…u_n,f(t_1,…,t_n),f(u_1,…,u_n) \) are terms in the set. If \( (t_1 \UFEq u_1) \land … \land (t_n \UFEq u_n) \) holds but \( f(t_1,…,t_n) \UFNeq f(u_1,…,u_n) \), then we can apply the rule and obtain a new equivalence relation which is the same as \( \UFEq \) except that the classes of \( f(t_1,…,t_n) \) and \( f(u_1,…,u_n) \) are merged.

Example

The equivalence relation $${\UFEq_1} = \Set{\Set{x_1,x_2,x_3},\Set{f(x_1),f(x_3)},\Set{g(x_2,f(x_3))},\Set{g(x_2,f(x_1))}}$$ is not closed under the function congruence rule as \( f(x_1) \UFEq_1 f(x_3) \) but \( g(x_2,f(x_3)) \UFNeq_1 g(x_2,f(x_1)) \). Applying the rule gives the new relation $${\UFEq_2} = \Set{\Set{x_1,x_2,x_3},\Set{f(x_1),f(x_3)},\Set{g(x_2,f(x_3)),g(x_2,f(x_1))}}$$ which is closed under the rule.

The main idea of the algorithm is now quite simple: maintain an equivalence relation over the terms in the formula, and perform the following.

  • ​ Start with the discrete relation (each term is only equivalent to itself).

  • ​ When a new equality \( t_1 \Eq t_2 \) are asserted,

    1. merge the equivalence classes containing \( t_1 \) and \( t_2 \), and

    2. apply the function congruence closure rule until the relation is closed under it.

  • ​ Remember the asserted disequalities \( t_1 \Neq t_2 \), and check whether they are violated when equivalence classes are merged.

The algorithm and its variants are commonly called the congruence closure algorithm.

Implementing equivalence classes

Equivalence classes with merges can be implemented with, e.g., the union-find data structure (recall the Aalto course “CS-A1140 Data Structures and Algorithms”) which maintains the equivalence classes in disjoint trees: two elements are equivalent if they belong to the same tree. To represent the trees, one only needs to associate each element with

  • ​ a \( \UFRoot \) pointer initialized to point to the element itself, and

  • ​ a \( \UFRank \), initialized to 0, to keep the constructed tree balanced.

def \( \UFFind{e} \): // Find the root of the tree containing \( e \) while \( \UFRootOf{e} \neq e \): \( e \Asgn \UFRootOf{e} \) return \( e \) def \( \UFMerge{e_1}{e_2} \): // Merge the classes of \( e_1 \) and \( e_2 \) \( r_1 \Asgn \UFFind{e_1} \), \( r_2 \Asgn \UFFind{e_2} \) if \( r_1 = r_2 \): return if \( \UFRankOf{r_1} < \UFRankOf{r_2} \): \( \UFRootOf{r_1} \Asgn r_2 \) else if \( \UFRankOf{r_1} > \UFRankOf{r_2} \): \( \UFRootOf{r_2} \Asgn r_1 \) else: \( \UFRootOf{r_1} \Asgn r_2 \) \( \UFRankOf{r_2} \Asgn \UFRankOf{r_2}+1 \)

Example

Assume the elements \( e_1,…,e_5 \).

  1. Initially, each element is in its own class. Thus \( e_i \UFEqNot e_j \) whenever \( i \neq j \).

    _images/uf-ex1.png
  2. Execute \( \UFMerge{e_1}{e_2} \).

    _images/uf-ex2.png
  3. Execute \( \UFMerge{e_5}{e_4} \)

    _images/uf-ex3.png
  4. Execute \( \UFMerge{e_1}{e_5} \)

    _images/uf-ex4.png

    Now \( \UFFind{e_1} = e_4 = \UFFind{e_5} \) and thus \( e_1 \UFEq e_5 \).

Asserting equality and disequality atoms

The core part of our \( \TEUF \)-solver is to maintain the equivalence classes between the terms, and their sub-terms, when equalities and disequalities are asserted. Initially, each term is in its own equivalence class. When an equality between two terms is asserted, the algorithm

  • ​ merges the corresponding classes,

  • ​ applies the congruence rule until the equivalence relation becomes closed under it, and

  • ​ checks if a recorded disequality is violated.

When a disequality between two terms is asserted, the solver

  • ​ checks if the terms are equivalent, and

  • ​ records the disequality.

def \( \SMTAssert{t \Eq u} \): \( \CCPending \Asgn \Set{\Pair{t}{u}} \) while \( \CCPending \) not empty: pop a \( \Pair{v}{w} \) from \( \CCPending \) if \( \UFFind{v}=\UFFind{w} \): continue \( \UFMerge{v}{w} \) for each pair \( v' \), \( w' \) such that 1. \( v' \Abbrv f(v'_1,...,v'_n) \) and \( w' \Abbrv f(w'_1,...,w'_n) \), 2. \( \UFFind{v'_1}=\UFFind{w'_1},..., \) \( \UFFind{v'_n}=\UFFind{w'_n} \), and 3. \( \UFFind{v'} \neq \UFFind{w'} \), add \( \Pair{v'}{w'} \) in \( \CCPending \) for each recorded \( v \Neq w \): if \( \UFFind{v}=\UFFind{w} \): return false return true def \( \SMTAssert{\neg(t \Eq u)} \): if \( \UFFind{t}=\UFFind{u} \): return false record \( t \Neq u \) return true

Example

Consider the conjunction \[{f(f(f(x))) \Eq x} \land {f(f(f(f(f(x))))) \Eq x} \land {f(x) \Neq x}\] and, for clarity, use the abbreviations \( t_1 \Abbrv f(x) \), \( t_2 \Abbrv f(f(x)) \Abbrv f(t_1) \), \( t_3 \Abbrv f(t_2) \), \( t_4 \Abbrv f(t_3) \), \( t_5 \Abbrv f(t_4) \) for the component terms. The parse tree of the formula can be drawn as

_images/euf.png
  1. Initially, the equivalence classes are \( \Set{x},\Set{t_1},\Set{t_2},\Set{t_3},\Set{t_4},\Set{t_5} \) and the union-find data structure looks like

    _images/euf-eq1.png
  2. Asserting \( f(f(f(x))) \Eq x \) merges \( t_3 \) and \( x \): \( \Set{x,t_3},\Set{t_1},\Set{t_2},\Set{t_4},\Set{t_5} \)

    _images/euf-eq2.png
  3. \( x \UFEq t_3 \) implies \( {t_1 \Abbrv f(x)} \UFEq {t_4 \Abbrv f(t_3)} \): \( \Set{x,t_3},\Set{t_1,t_4},\Set{t_2},\Set{t_5} \)

    _images/euf-eq3.png
  4. \( t_1 \UFEq t_4 \) implies \( {t_2 \Abbrv f(t_1)} \UFEq {t_5 \Abbrv f(t_4)} \): \( \Set{x,t_3},\Set{t_1,t_4},\Set{t_2,t_5} \)

    _images/euf-eq4.png
  5. Asserting \( f(f(f(f(f(x))))) \Eq x \) merges \( t_5 \) and \( x \): \( \Set{x,t_3,t_2,t_5},\Set{t_1,t_4} \)

    _images/euf-eq5.png
  6. \( x \UFEq t_2 \) implies \( t_1 = f(x) \UFEq t_3=f(t_2) \): \( \Set{x,t_3,t_2,t_5,t_1,t_4} \)

    _images/euf-eq6.png
  7. Now we see that \( {t_1 \Abbrv f(x)} \UFEq x \) and thus \( f(x) \Eq x \) should hold. However, \( f(x) \Neq x \) is a conjunct in the original conjunction and therefore the conjunction is unsatisfiable.

When actually implementing the above methods, (i) the equivalence classes can be implemented with the union-find data structure, (ii) finding congruent terms can be implemented with a hash table, and (iii) backtracking equals to undoing the merges (and recomputing hash values).

When a conjunction is satisfiable, constructing a model for it is easy: just assign the elements in each equivalence class into a distinct value.

Theory-Implied Literals

Propagation of positive atoms \( t_1 \Eq t_2 \) is fast:

  • ​ at each merge, check if \( t_1 \) and \( t_2 \) are merged to the same class

  • ​ if yes, report \( t_1 \Eq t_2 \) as an implied literal.

Propagating negative literals requires more work:

  • ​ When asserting \( \neg(t_1 \Eq t_2) \) and \( t_1 \UFEqNot t_2 \) holds, report, for each atom \( t’_1 \Eq t’_2 \) with \( t’_1 \UFEq t_1 \) and \( t’_2 \UFEq t_2 \), the implied literal \( \neg(t’_1 \Eq t’_2) \)

  • ​ When merging two classes, find atoms of form \( t’_1 \Eq t’_2 \) for which (i) \( t’_1 \) or \( t’_2 \) are in the merged class, and (ii) \( t’_1 \UFEq t_1 \) and \( t’_2 \UFEq t_2 \) hold for some recorded disequality \( t_1 \Neq t_2 \), and report the implied literal \( \neg(t’_1 \Eq t’_2) \).

Example

Consider the formula \[\neg({x \Eq y} \land {y \Eq z}) \land ({y \Eq f(z)} \Implies {g(x) \Eq g(f(z))} \land {z \Eq f(z)})\] Initially all its terms are in their own equivalence classes and \( {\UFEq_0} = \Set{\Set{x},\Set{g(x)},\Set{y},\Set{z},\Set{f(z)},\Set{g(f(z))}} \). Consider the following sequence of literal assertions

  1. The CDCL SAT solver asserts \( x \Eq y \) into the theory solver, which updates the equivalence relation to \( {\UFEq_1} = \Set{\Set{x,y},\Set{g(x)},\Set{z},\Set{f(z)},\Set{g(f(z))}} \).

  2. The CDCL SAT solver asserts \( \neg(y \Eq z) \) into to theory solver, which does not update the equivalence relation but records the disequality. Note that \( \neg(x \Eq z) \) would be implied at this point if it were an atom in the formula.

  3. The CDCL SAT solver asserts \( y \Eq f(z) \) into the theory solver, which updates the equivalence relation to \( {\UFEq_2} = \Set{\Set{x,y,f(z)},\Set{g(x),g(f(z))},\Set{z}} \). Note that as \( x \) and \( f(z) \) are in the same class, the classes of \( g(x) \) and \( g(f(z)) \) are merged as well.

  4. The theory solver reports the implied literals

    1. \( g(x) \Eq g(f(z)) \), and

    2. \( \neg(z \Eq f(z)) \) as \( f(z) \UFEq_2 y \) and \( \neg(y \Eq z) \) is recorded.

To produce explanations, one can remember in a “reason graph”

  • ​ each equality and disequality assertion, and

  • ​ for each implied literal, the immediate reason for the implication.

The reasons can then be recursively expanded to get the explanation consisting only of assertions.

Example: Continues the previous one

For the previous example, the reason graph could be

_images/euf-reason.png

The explanation for \( g(x) \Eq g(f(z)) \) is obtained by explaining the immediate reason \( x \UFEq f(z) \). This is done by explaining the path between \( x \) and \( f(z) \). The result is \( (x \Eq y) \land (y \Eq f(z)) \).

The explanation for \( \neg(z \Eq f(z)) \) is \( y \Neq z \) conjuncted with the explanation for \( f(z) \UFEq y \), i.e., the assertion \( y \Eq f(z) \).

Some further reading

Classic papers on congruence closure:

A contemporary approach giving fast algorithms for congruence closure as well as an extension to integer offsets, allowing atoms of form \( x = y + k \) for integer constants \( k \):

Congruence closure in a theorem proving setting: