Analysis and Transformation of Constrained Horn Clauses for Program Verification

This paper surveys recent work on applying analysis and transformation techniques that originate in the field of constraint logic programming (CLP) to the problem of verifying software systems. We present specialisation-based techniques for translating verification problems for different programming languages, and in general software systems, into satisfiability problems for constrained Horn clauses (CHCs), a term that has become popular in the verification field to refer to CLP programs. Then, we describe static analysis techniques for CHCs that may be used for inferring relevant program properties, such as loop invariants. We also give an overview of some transformation techniques based on specialisation and fold/unfold rules, which are useful for improving the effectiveness of CHC satisfiability tools. Finally, we discuss future developments in applying these techniques.

useful also in program verification and static debugging, as illustrated by the Ciao Prolog system 1 .
During the past two decades, the application of these techniques to verification has expanded beyond logic programming to a large variety of other programming languages, including imperative, functional, object-oriented, and concurrent ones. The main reason is that logic programming, and more specifically Constraint Logic Programming (CLP), is effective as a language for specifying program semantics and program properties.
For verification applications, the term Constrained Horn Clauses (CHCs) is often used in the literature instead of CLP when dealing with clauses that encode verification problems, but are not intended to be directly executed as programs. Despite this pragmatic difference, CHCs are syntactically and semantically the same as constraint logic programs. The underlying constraint theories of CHCs are typically those that axiomatize data structures used in programming, such as booleans, integer numbers, real numbers, bit vectors, arrays, heaps, and recursively defined data structures such as lists and trees. Effective solvers for checking satisfiability of sets of CHCs have been developed during the last years. These solvers focus on constructing models in the theory of constraints; however, proof-theoretic notions from CLP such as derivation trees, resolution, and refutation are still applicable to CHCs.
The first step in CHC-based software verification is the encoding of a verification problem in CHC form. Consider, for instance, the program fragment consisting of the function definition in Figure 1. After the assignment sum = sum_upto(m), the location sum will store the sum of the integers in the interval [0,m] Suppose that we want to prove the validity of the Hoare triple {m≥0} sum = sum_upto (m) {sum≥m}, stating that, if m≥0 and the assignment sum = sum_upto(m) terminates, then sum is assigned a value larger than or equal to m. This triple is valid if and only if the following set of clauses, collectively called the verification conditions, is satisfiable. Note that, in clause 1 above, we have that: (i) M>=0 is the precondition of the Hoare triple, (ii) sum_upto (M,Sum) holds if and only if the evaluation of the function sum_upto on the input integer M terminates and returns the integer Sum, and (iii) the constraint M>Sum is the negation of the postcondition of the triple. As we will show later, CHC solvers can show that this set of CHCs is indeed satisfiable and hence the validity of the Hoare triple is proven.
In this paper, we survey and discuss various aspects of this scenario, including the derivation of the CHCs from imperative programs and Hoare triples, and techniques for automatically checking their satisfiability. Since satisfiability of CHCs is undecidable, a terminating automatic solver yields one of three answers: satisfiable, unsatisfiable or unknown. An important goal of the techniques we discuss is to return a definite answer (satisfiable or unsatisfiable) in as many cases as possible. We will show that many wellestablished analysis and transformation techniques developed for CLP, as well as new CHC-based approaches proposed in recent years to address verification problems, are effective for achieving this goal.
The paper is structured as follows. In Section 2 we present preliminary notions about constraints, CHCs, their models, and some basic techniques for checking their satisfiability, relating these techniques to the proof-theoretic and model-theoretic semantics of CHCs. Much of this background was established in the field of CLP.
In Section 3, we present various CHC semantics-preserving transformation techniques, based on CHC fold/unfold rules and specialisation transformations. Fold/unfold transformations have been extensively studied in logic programming, and specifically in CLP. They play an important role in verification due to the fact that such transformations preserve satisfiability. Specialisation is a transformation that preserves satisfiability with respect to a particular goal.
In Section 4, we present techniques for generating CHCs that encode verification problems in other languages, focussing on imperative programming languages. We describe an approach based on specialisation of semantics-based interpreters, and also survey other approaches that have been applied in CHC solving tools.
In Section 5, we describe techniques for CHC analysis applied to verification. These are derived mainly from the CLP literature, and in some cases directly yield a proof of satisfiability or unsatisfiability; in other cases, analyses help with inferring relevant program properties such as loop invariants. Static analysis also plays an important role in guiding some CHC transformations, especially specialisation.
Section 6 covers particular applications of transformation for verification. These include constraint propagation and strengthening. The section also presents transformations for predicate pairing, with application to relational verification and verification problems for abstract data types. We also summarise other transformation techniques such as tree-automata based refinement, and control-flow refinement.
In Section 7, we give a brief overview of the use of analysis and transformation techniques in some areas related to software verification, such as model checking of infinite state systems and constraint-based automated testing.
Finally, in Section 8 we discuss some developments in the area of CHC analysis and transformation, which we believe worthy of future investigation.

Constrained Horn Clauses
Constrained Horn clauses are a class of first-order logic formulas where the Horn clause format is extended by the use of formulas of an arbitrary, possibly non-Horn, constraint theory. A set of CHCs is also known as a program in CLP (Jaffar andLassez 1987, Jaffar andMaher 1994). As already mentioned, the term constrained Horn clauses is often used in the verification context (Bjørner et al. 2015), where the focus is mainly on the logical meaning, and in particular, on the construction of models for the clauses, while the term CLP program refers additionally to the notion of execution which is based on the procedural semantics of the clauses. In this survey, we will adhere to the CHC terminology, although we will occasionally make use of the CLP terminology, especially when referring to techniques that have been proposed in the CLP field.
In this section, we will recall the basic notions of constraints (Section 2.1), CHCs (Section 2.2), and their models (Section 2.3). We will also present some techniques for checking CHC satisfiability (Section 2.4). We assume some familiarity with the elementary concepts of first-order predicate logic (Enderton 1972, Mendelson 1997. For logic programming notions not defined here, we refer to standard publications (Apt 1990, Lloyd 1987).

Constraint Domains
Let L be a first-order language with equality. Let the set of terms and formulas in L, be denoted by T and F , respectively. They are constructed, as usual, starting from a set V of variables, a set of function and predicate symbols (with arity), the logical connectives, and the quantifiers. A function symbol of arity 0 is also called a constant. Given a formula ϕ ∈ F, by vars(ϕ) we denote the set of the free variables occurring in ϕ. If vars(ϕ) = ∅, we say that ϕ is a closed formula. If all variables occurring in ϕ are free, we say that ϕ is a quantifier-free formula. We denote by ∃(ϕ) the existential closure of ϕ, and by ∀(ϕ) the universal closure of ϕ. Let a substitution be a finite mapping from a set of variables {X 1 , . . . , X m } ⊆ V to a set of terms {t 1 , . . . , t m } ⊆ T , written as {X 1 /t 1 , . . . , X m /t m }. We assume that, for i = 1, . . . , m, X i is different from t i .
A constraint domain D consists of the following components (Jaffar and Maher 1994). (1) A signature Σ, that is, the subset of the function and predicate symbols of L used in D. We assume that the signature of any constraint domain D includes the predicate symbols true, false, and the equality symbol =. The terms of L using function symbols in Σ and variables are called Σ-terms. The formulas of L using symbols in Σ, variables, logical connectives, and quantifiers, are called Σ-formulas. Here we will omit the association of sorts to the symbols of Σ, as this issue is not relevant for the topics addressed in this paper. However, in some contexts, the use of many-sorted signatures is the standard (Barrett and Tinelli 2018). (2) A subset C of Σ-formulas, called constraints. We assume that the atomic constraints true, false, and equalities between terms are in C. We also assume that C is closed under conjunction and existential quantification. (3) A constraint theory A, that is, a set of closed Σ-formulas, called axioms.
(4) A fixed constraint interpretation D for the symbols in the signature Σ. As usual, D consists of a set U, called universe, together with functions and relations (with suitable arities) on U that interpret the function and predicate symbols of Σ, respectively. The equality symbol is always interpreted as the identity on U. We assume that D is a model for A, and thus, for every closed Σ-formula ϕ, if A |= ϕ, then D |= ϕ. In many constraint domains, we will also have that, if D |= ϕ, then A |= ϕ (and hence A is a complete, decidable theory).
(5) Functions for constraint satisfiability, entailment, and projection, defined as follows. − A constraint solver, that is, a computable partial function, call it solv, which tests satisfiability of any constraint c in D, that is, solv tells us whether or not D |= ∃(c) holds. We assume that solv is a total function whenever satisfiability is decidable.
− An entailment function, that is, a computable partial function, called entail, which tests whether or not, for any two constraints c 1 and c 2 , D |= ∀(c 1 → c 2 ) holds.
− A projection function, that is, a computable partial function, called proj, which, given a constraint c and a finite set V ⊆ V of variables, computes the new constraint proj(c, V ), called the projection of c onto V , such that D |= ∀((∃X 1 , . . . , X m .c) ↔ proj(c, V )), where {X 1 , , . . . , X m } = vars(c)\V . We assume that proj(c, V ) is a quantifier-free formula whenever the constraint domain D admits quantifier elimination.
Now we present some of the constraint domains which are used in practice. In the literature one can find slightly different, yet equivalent, presentations of those domains. As already stated, we assume that the signature Σ of every constraint domain includes the predicate symbols true, false, and =.

Example 1
The constraint domain Bool of the Boolean constraints is defined as follows. The signature Σ includes the function symbols 0, 1, ∼, * , +. For instance, ∼ 1 = x+0 is an atomic constraint. The axioms of Bool are those of the Boolean algebra freely generated by 0 and 1. For instance, ∀x, y. x * y = y * x is the commutativity axiom for * . The constraint interpretation B of Bool has the universe U = {false, true}. The symbols 0, 1, ∼, * , and + are interpreted as false, true, negation, conjunction and disjunction, respectively. Satisfiability and entailment are decidable and they are tested as usual in Boolean algebras. Projection is a total function. For instance, we have that B |= ∃x. (∼ 1 = x+0) holds, and proj(∼ y = x+1, {y}) is the constraint y = 0.

Example 2
The constraint domain Integer of integer arithmetic is as follows. The signature Σ includes the following function symbols: all integer numbers, +, −, ×, and the predicate symbols = and ≤. The axioms of Integer are Σ-formulas that can be derived from the axioms of Peano arithmetic (see, for instance, the paper by Wybraniec-Skardowska (2019)) and the references therein). The interpretation of the symbols of Integer is defined as expected over the universe Z of the integer numbers. Satisfiability of constraints is undecidable, as they include the Diophantine equations (Matiyasevich 1970). The constraint domain LIA of linear integer arithmetic is derived from the domain Integer by requiring that at least one of the two operands of × is an integer constant. The fully quantified Σ-formulas of LIA are decidable, by extending Presburger's algorithm. The time complexity of the decision procedure is super-exponential with respect to the size of the formula. The problem of checking satisfiability of quantifier-free formulas of LIA is an NP-complete problem (Bradley and Manna 2007).

Example 3
The constraint domain F D of finite domains is related to the constraint domain LIA and is defined as follows (Jaffar and Maher 1994). The signature Σ of F D includes all integer numbers, the binary function symbols +, −, the infinitely many unary predicate symbols '∈ [m, n]' (one for each pair m, n of integers, with m at most n), and the binary predicate symbols = and ≤. The interpretation of the atomic constraint x ∈ [m, n] over the universe Z is x ∈ {m, m+1, . . . , n}. For instance, x =4 ∧ x∈ [2,5] is a constraint in F D. As for LIA, we have that for F D the fully quantified Σ-formulas are decidable and satisfiability of the quantifier-free Σ-formulas is NP-complete.

Example 4
The constraint domain Real of real arithmetic is defined as follows. The signature Σ includes the following function symbols: all rational numbers, +, −, ×, and the predicate symbols < and ≤. The axioms of Real are those of an ordered, real closed field (Shoenfield 1967). The interpretation of the function and predicate symbols of Real is the expected one over the universe R of the real numbers. Satisfiability is decidable and there exists a constraint solver for Real (Jaffar et al. 1992, Barrett and Tinelli 2018).
The constraint domain LRA of linear real arithmetic is derived from the domain Real by requiring that at least one of the two operands of × is a rational constant. Satisfiability of LRA constraints can be computed using Fourier-Motzkin elimination (Schrijver 1998). If we consider the universe Q of the rational numbers, instead of R, from the domain Real we get the domain Q of rational arithmetic, and from the domain LRA we get the domain LQA of linear rational arithmetic. LRA and LQA are two elementary equivalent structures (Shoenfield 1967), and thus a solver for LRA is also a solver for LQA, and vice versa.

Example 5
The constraint domain EUF of Equality of Uninterpreted Functions is a domain defined as follows. The signature Σ includes a set {f 0 , . . . , f k } of function symbols and the predicate symbol = 2 . The axioms are those for =, that is, reflexivity, symmetry, transitivity, and function congruence (that is, ∀x, y. x = y → f (x) = f (y)), together with the axiom for = : ∀x, y. x = y ↔ ¬(x = y). The universe of the interpretation is the set T of finite trees. The 0-ary function symbol a is interpreted as a tree made out of the single node a, and the n-ary (with n > 0) function symbol f is interpreted as the mapping that, given the trees that are the interpretations of the n arguments of f , returns a tree having f as root and the n trees as children of the root. The satisfiability of conjunctions of quantifier-free Σ-formulas of EUF can be decided in polynomial time by congruence closure algorithms (Jaffar andMaher 1994, Bradley andManna 2007). For instance, we have that T |= f (f (f (a))) = a ∧ f (f (a)) = a ∧ f (a) = a. Indeed, the first two conjuncts imply f (a) = a.

Example 6
The constraint domain Term is defined as follows. The signature Σ includes a given set of function symbols. The axioms of Term are the usual ones for = (see Example 5), together with the axioms specific of the Clark Equality Theory (Clark 1978)). In particular, (i) for all distinct function symbols f and g, for all tuples u and v of terms, ¬ (f (u)= g(v)), and (ii) for all terms t and t ′ , if t is a proper subterm of t ′ , then ¬(t = t ′ ). As for EUF, the universe of the interpretation is the set of finite trees. The unification algorithm defines a total constraint solver for quantifier-free formulas in the domain Term (Apt 1990).
There is a variant of the constraint domain Term that takes as universe, instead of the set of finite trees, the set of rational trees, that is, the set of all (finite or infinite) trees, each tree having a finite set of (finite or infinite) subtrees (Colmerauer 1982). This extension of the domain Term from finite trees to rational trees, call it Term Rat , has been the first step made towards the integration of a constraint domain into logic programming. Indeed, when performing unification between atoms, the equalities between rational trees are manipulated as constraints in CHCs. In Term Rat , satisfiability of quantifier-free formulas is decidable and a constraint solver is a unification algorithm that does not perform the occur-check (Jaffar 1984). In particular, the unification between a variable x and a non-variable term containing x always succeeds.

Example 7
The constraint domain Array is the domain of the arrays as commonly used in programming. The signature of Array includes the read and write function symbols for denoting, respectively, the reading of an array at an index position, and the writing of an element in an array at an index position. The axioms of Array are the usual ones for equality between indexes and equality between elements, together with the following two axioms: for all arrays a, elements v, indexes i and j, (a, i, v), j) = read(a, j) Satisfiability of fully quantified formulas in the Array domain is undecidable. However, there are suitably restricted classes of Array formulas in which it is decidable (Bradley andManna 2007, Alberti et al. 2015).
Since in practice many verification problems deal with programs that manipulate different data types, an important theoretical and practical aspect of the use of constraint domains is the combination of solvers relative to different constraint domains (Nelson andOppen 1979, Barrett andTinelli 2018) Many Prolog systems support constraint solving by including selectable solvers as libraries, in the CLP(X ) spirit, such as F D (B-Prolog, Ciao, ECLiPSe, GNU, SICStus, and SWI), Bool (B-Prolog, GNU, SICStus, SWI), Q and Real (Ciao, ECLiPSe, SIC-Stus, SWI, XSB), and Sets (B-Prolog, ECLiPSe), among others. Also, many Prolog systems (e.g., Ciao, ECLiPSe, SICStus, SWI, XSB, YAP) support Constraint Handling Rules (CHR), a committed-choice rule-based language designed for writing constraint solvers (Frühwirth 1998). This brings support for additional constraint domains or alternative implementations. Finally, the Parma Polyhedral Library (Bagnara et al. 2008) provides several Prolog systems (Ciao, GNU, SICStus, SWI, XSB, Yap) with the implementation of primitives, such as widening and convex-hull, for constraint manipulation over various subdomains of the domain Real, including boxes, bounded differences, octagons, and convex polyhedra.
Constraint solvers for several constraint domains have also been developed using techniques of Satisfiability Modulo Theories (SMT), which build upon various decision procedures for first-order theories and very efficient algorithms for propositional satisfiability (Barrett and Tinelli 2018). Constraint solvers based on that approach are called SMT solvers, and have their main applications in the field of program verification. For that reason they focus on constraint domains that formalise data types often used in programming, such as Booleans, integer and floating point numbers, bit vectors, and arrays. Among other SMT solvers, we have CVC4 (Barrett et al. 2011), Eldarica (Hojjat and Rümmer 2018), MathSAT (Cimatti et al. 2013), Yices (Dutertre 2014), and Z3 (de Moura and Bjørner 2008, Komuravelli et al. 2013). An important initiative is SMT-LIB , which has the goals of proposing common languages and interfaces for SMT solvers and constructing a library of benchmarks.

Syntax of CHCs
Let D be a constraint domain with signature Σ, subset of the first-order language L. Let Pred u be a set of the predicate symbols of L which do not belong to Σ. Pred u is called the set of the user-defined predicate symbols. Let C be the set of constraints of D. An atom is an atomic formula p(t 1 , . . . , t m ), where p is a predicate symbol in Pred u and t 1 , . . . , t m are Σ-terms. Let Atom be the set of all atoms. A constrained Horn clause (CHC) (or simply, a clause) is a universally quantified implication of the form: ∀(c ∧ A 1 ∧ . . . ∧ A n → H) whose premise (or body) is the conjunction of a constraint c and n (≥ 0) atoms A 1 , . . . , A n , and whose conclusion (or head) H is either an atom or false. We will use the logic programming notation and we will write a clause as H ← c, A 1 , . . . , A n . In the examples we will also adopt the usual Prolog notation and, in particular, the symbol '←' will be replaced by ':-'.
A constrained goal (or simply, a goal) is a clause of the form: false ← c, A 1 , . . . , A n . A definite clause is a clause whose conclusion is an atom. A constrained fact (or simply, a fact) is a definite clause of the form: H ← c. A clause D (or a set P of clauses) is said to be over C in case we want to stress that the constraints occurring in D (or in P ) belong to the set C of constraints. A clause H ← c, A 1 , . . . , A n is said to be linear if n ≤ 1, and nonlinear otherwise. Given a set P of clauses, we say that predicate p immediately depends on a predicate q if in P there is a clause of the form: p(...) ← c, A 1 , . . . , A n such that q occurs in one of the atoms A 1 , . . . , A n . The relation depends on between predicates is the transitive closure of the relation immediately depends on.

Models of CHCs
Let D be a constraint domain, where D is the fixed interpretation for the constraint signature Σ and U is the universe of D. Without loss of generality, we assume that for every element in U there is a corresponding constant in the signature Σ and in L (indeed, we can always extend Σ and L by adding new constants). A valuation σ for D is a mapping from V to U, and its extension that maps terms to U and formulas to closed formulas, based on the replacement of every free variable occurrence X by σ(X). The D-base for L, denoted B D , is the set {σ(A) | A ∈ Atom and σ is a valuation for D}.
A D-interpretation is an interpretation of L that agrees with the interpretation D on the symbols of Σ. A D-interpretation I can be identified with the following subset of B D : {p(a 1 , . . . , a m ) ∈ B D | p I (a 1 , . . . , a m ) holds in I} where p I denotes the m-ary relation on U m that interprets the symbol p in I. Given any set F of formulas, a D-interpretation M is a D-model of F , written M |= F , if, for all formulas ϕ ∈ F , M |= ϕ holds, that is, ϕ is true in M. F is D-satisfiable if it has a Dmodel. We will often say satisfiable, instead of D-satisfiable, when the specific constraint domain D is irrelevant or understood from the context. We write D |= F if, for every D-interpretation M, M |= F holds.
Every set P of definite CHCs is D-satisfiable and has a least (with respect to set inclusion) D-model, denoted lm(P, D) (Jaffar and Maher 1994). Thus, if Q is any set of constrained goals, then P ∪ Q is D-satisfiable if and only if lm(P, D) |= Q.
When presenting satisfiability procedures, it will be convenient to consider false as a user-defined predicate, so that P ∪ Q is a set of definite CHCs, and hence lm(P ∪ Q, D) exists. Thus, we will say, with a slight abuse of language, that P ∪ Q is satisfiable if and only if false does not belong to lm(P ∪ Q, D), written false ∈ lm(P ∪ Q, D).

If the constraint theory
A D-interpretation I is represented by a set I of constrained facts if, for all predicates p∈Pred u , p(a 1 , . . . , a m ) ∈ I if and only if, for some constrained fact p(X 1 , . . . , X m ) ← c in I, we have that D |= σ(proj(c, {X 1 , . . . , X m })), where σ is a valuation that maps X 1 , . . . , X m to a 1 , . . . , a m . In general, a D-interpretation may be represented by more than one (finite or infinite) set of constrained facts. On the other hand, a set of constrained facts represents a unique D-interpretation. We will extend the terminology and notation defined for D-interpretations to their representation as sets of constrained facts. In particular, For instance, given the following CHCs over LIA : The least LIA-model of these CHCs is the infinite set {p(0), p(1),...}, which is represented by the set {p(X) :-X>=0.} of one constrained fact only.
Most of the satisfiability techniques work on D-interpretations that can be represented by finite sets of constrained facts. Such interpretations are said to be D-definable (Bjørner et al. 2015). If a set S of CHCs has a D-definable model, then S is said to be solvable, and the model is said to be a solution for S. Clearly, if S is solvable, then S is D-satisfiable. In general, the converse does not hold: there exist sets of CHCs that are D-satisfiable, and yet they do not have any D-definable models (see Section 6.2 for an example).

Satisfiability
The reasoning task for CHCs which is most relevant to program verification applications is checking their satisfiability. We call CHC solvers the tools implementing methods for solving this task. Unfortunately, as a consequence of classical computability results (Tärnlund 1977), the problem of checking the satisfiability of a set of CHCs is undecidable, and hence only incomplete methods can be found. Here we will briefly present two kinds of procedures which are the basis of many methods for checking satisfiability: (i) bottom-up procedures, and (ii) top-down procedures.

Bottom-up procedures
Given a constraint domain D, a set P of definite CHCs over D, and a set Q of constrained goals over D, we have that P ∪ Q is D-satisfiable if and only if the set Q of constrained goals holds in the least D-model lm(P, D) (see Section 2.3).
Bottom-up procedures for checking the satisfiability of P ∪ Q are based on the least fixpoint characterisation of the least D-model of P , which allows us to construct lm(P, D) as the least upper bound of a sequence of D-interpretations that under-approximate lm(P, D), starting from the empty set, by making forward inferences (that is, using clauses as implications for inferring new atoms to be added to the current D-interpretation).
Indeed, the least D-model lm(P, D) can be computed as the least fixpoint of a function, denoted T D P , which given a D-interpretation returns a new D-interpretation. This function is called the immediate consequence operator for P , and it is defined as follows: P is a continuous function on the complete partial order (2 B D , ⊆), it has a least fixpoint lfp(T D P ) (Tarski 1955). This fixpoint is the least upper (Jaffar et al. 1998).

Example 8
Let D be the constraint domain Integer and let P be the following set of clauses over D: It can be shown by induction that the bottom-up computation of lfp(T D P ) constructs the following Kleene sequence of D-interpretations: whose least upper bound is: . The construction of lfp(T D P ) can be used as the basis for checking the satisfiability of P ∪ Q. By the continuity of T D P , any goal in Q is false in lfp(T D P ) if and only if it is false in T D P ↑ i, for some i ≥ 0. Thus, a bottom-up procedure which computes lfp(T D P ) by constructing the Kleene sequence, is sound and complete for showing the unsatisfiability of P ∪ Q. However, if P ∪ Q is satisfiable, then the construction of the Kleene sequence may not terminate (recall that satisfiability is not even semidecidable). In this case, in order to prove satisfiability, one should prove that Q is true in T D P ↑ i, for i ≥ 0, by some method different from direct inspection of lfp(T D P ), e.g., by the abstract interpretation methods presented in Section 5, which compute an over-approximation of lfp(T D P ). In the next example we use a method based on induction on i.
As already mentioned, (i) these clauses encode the verification problem for the program fragment of Figure 1 in the sense that the triple {m≥0} sum = sum_upto(m) {sum≥m} holds if and only if they are D-satisfiable, and (ii) these clauses are D-satisfiable if and only if goal 1 holds in lfp(T D P ), where P is the set made out of clauses 2-4. It can be shown by induction that the bottom-up computation of lfp(T D P ) constructs the following Kleene sequence of D-interpretations: Now, in order to check that goal 1 holds in lfp(T D P ) (which is equal to k≥0 T D P ↑ k), we reason as follows. First, we have that lfp(T D P ) is equal to: (Note that for all integers k>1, we have that k(k+1)/2 and (k-1)k/2 are integer numbers, and thus the constraints in the above expression of lfp(T D P ) are all in the domain Integer.) Then, with reference to the constraint X=k-1, R=(k-1)k/2 in Expression ( †), we can show by induction that, for all k≥1, we have that k-1 ≤ (k-1)k/2, which implies that X ≤ R. Thus, no atom in lfp(T D P ) with predicate sum_upto(M,Sum) satisfies the constraint M>Sum, M>=0 in goal 1, and we get that goal 1 is true in lfp(T D P ). Hence, P ∪ {goal 1} is D-satisfiable and the validity of the Hoare triple is proved.

Top-down procedures
The top-down approach to check satisfiability is based on the extension of SLD-resolution (Kowalski and Kuehner 1971, Lloyd 1987, Apt 1990 to CHCs, which is used to define the operational semantics of CLP languages (Jaffar andLassez 1987, Jaffar et al. 1998). The core of this approach is the proof-theoretic notion of a top-down derivation. In a derivation of that kind, in order to check whether or not the atom false can be derived from a given initial constrained goal and a given set of definite CHCs, one proceeds by making backward inferences, that is, replacing an atom which is unifiable (modulo satisfiability of constraints) with the head of a clause by the corresponding body of the clause.
Similarly to the bottom-up case, given a set Q of constrained goals and a set P of definite CHCs over a constraint domain D, we will present a top-down procedure which is sound and complete for showing unsatisfiability, but it may not terminate if P ∪ Q is satisfiable.
Without loss of generality, we may assume that Q consists of a single goal G, as P ∪ Q is satisfiable if and only if for every constrained goal G∈Q, P ∪ {G} is satisfiable. Let us also assume that goal G is of the form: false ← d, A 1 , . . . , A n .
In this case, a top-down procedure for satisfiability checking can be formalised by first defining a rewriting system (a similar approach is followed by Jaffar and Maher (1994)). At every rewriting step, a pair of the form B, e , where B is a multiset of atoms and e is a constraint in D, is rewritten into either a new pair B ′ , e ′ or fail, as we now specify.
There are two kinds of rewritings: (i) the r-rewriting, which makes use of a computation rule and a search rule, and (ii) the c-rewriting. They are defined as follows, starting from a given pair B, e . (i) The r-rewriting, denoted −→ r . Assume that B = ∅ and e is a satisfiable constraint.
Let p(u 1 , . . . , u k ) be an atom which is selected among those in B by the computation rule. Then, the search rule selects in P a (renamed apart) clause, if any, of the form: If that clause exists, then we have the following r-rewriting: where B ′ is the multiset of atoms obtained from B by deleting the atom p(u 1 , . . . , u k ) and adding the atoms in C.
If that clause does not exist, we have the rewriting: (ii) The c-rewriting, denoted −→ c . Assume that e is an unsatisfiable constraint. (B may be ∅ or not.) We have the rewriting: For all i ≥ 0, by −→ i r we denote the i-fold composition of −→ r . As usual, by −→ + r and −→ * r we denote the relation i>0 −→ i r and i≥0 −→ i r , respectively. A top-down derivation (or simply, a derivation) for the goal false ← d, A 1 , . . . , A n and the set P of definite CHCs, is a (finite or infinite) maximally extended sequence of r-rewritings or c-rewritings that starts from the pair {A 1 , . . . , A n }, d .
A derivation is successful if it is finite and its last pair is of the form ∅, e , where e is a satisfiable constraint, and it is failed if it is finite and its last element is fail. A derivation is fair if either it is failed or every atom which occurs in a pair of the derivation is rewritten in some later rewriting. A computation rule is fair if it gives rise to fair derivations only. A goal G is finitely failed if every derivation from G which uses a fair computation rule, is failed.
The choices made by the search rule give rise to the notion of derivation tree for a goal G: false ← d, A 1 , . . . , A n , a set P of definite CHCs, and a computation rule. The root of the derivation tree is {A 1 , . . . , A n }, d , and every path starting from the root is a derivation for G and P , according to the given computation rule.
In a derivation tree, every node B, e , where e is a satisfiable constraint, has the children B 1 , e 1 , . . . , B k , e k , if, for i = 1, . . ., k, there exists the rewriting B, e −→ r B i , e i for any search rule. Every node B, e such that B, e −→ r fail or B, e −→ c fail has the single child fail.
A derivation tree for a goal G: false ← d, A 1 , . . . , A n and a set P of definite CHCs is fair if all its paths from the root are fair derivations. It is finitely failed if it is fair and all its paths from the root are failed derivations.
In order to know whether or not a constraint is satisfiable (and thus, to know whether we will perform an r-rewriting or a c-rewriting), we use the function solv associated with the constraint domain at hand. We may assume that, if the constraint e is satisfiable, solv(e) returns a constraint equivalent to e presented in a suitably defined normal form (such as the solved form for a set of equations (Apt 1990)). Moreover, during an r-rewriting step (see (1) above), after the modification of the current constraint, one could invoke solv and, if the modified constraint is unsatisfiable, one could immediately derive fail without performing a successive c-rewriting. We will not discuss further these issues concerning the application of the function solv, as they are not relevant for the topic of the present paper.

Example 10
Let P be the set of clauses over the Integer domain we have considered in Example 8 of Section 2.4.1. Those clauses are: In Figure 2 we have depicted the derivation tree for the goal false :-p(5,X) and P . The constraint X<3, 5=X+3 in the left child of the root can be replaced by the equivalent constraint X=2 by an application of a suitable version of the function solv. The success set of a set P of definite CHCs over the constraint domain D is the set of all elements of the D-base B D , each of which occurs in the starting pair of a successful derivation, that is: Recall that in our case by Pred u we denote the set of the predicates symbols occurring in the heads of the clauses of P . A representation of SS(P ) D as a set of constrained facts is as follows: The fundamental result for top-down procedures is that the success set coincides with the least D-model, that is, SS(P ) D = lm(P, D) (Jaffar andMaher 1994, Jaffar et al. 1998).
Given a set P of definite CHCs over a constraint domain D, a basic top-down procedure for the computation of SS(P ) D can be defined as follows. First, we introduce the success set up to depth k for P , denoted SS(P ) k D , as follows: SS(P ) k D = {p(a 1 , . . . , a n ) ∈ B D | p(a 1 , . . . , a n ),

Example 11
Let D be the constraint domain Integer. Let us consider the set P = {C1, C2} of clauses considered in Example 10 and the goal false :-p(A,X). It can be shown by induction that the top-down procedure constructs the following sequence of sets of atoms: Thus, we have that: Let us consider a derivation tree for goal G: false ← d, A 1 , . . . , A n and a set P of definite CHCs. We have that P ∪ {G} is satisfiable if and only if no successful derivation for G exists in that tree. Thus, in the case where the satisfiability of constraints in D is decidable, a sound and complete method for showing unsatisfiability is to search for a successful derivation for G. On the contrary, in order to show satisfiability one should prove that no such a derivation exists. In the particular case where the derivation tree for G and P is finitely failed, then P ∪{G} is satisfiable. However, when the derivation tree is infinite, more sophisticated techniques for showing the absence of successful derivations should be used. For instance, one can apply memoization (or tabling) (Warren 1992, Cui andWarren 2000) or top-down techniques for CHC analysis, which construct suitable over-approximations of SS (P ) D (see Section 5.2). Now we present an example of program verification based on the construction of SS(P ) D .

Example 12
Let D be the constraint domain Integer and let P be the set of definite CHCs over D that we have considered in Example 9. It can be shown by induction that the top-down procedure computes the following sequence of sets of atoms: Thus, the set of the sum_upto atoms in SS (P ) D is equal to: {sum_upto(X,R) | X=<0,R=0} ∪ k>1 {sum_upto(X,R) | X=k-1, R=(k-1)k/2} as expected from the value of lm(P, D) shown in Example 9. Now we have that in SS (P ) D there is no atom of the form sum_upto(M,Sum) that satisfies the constraint M>Sum, M>=0 occurring in goal 1. Hence, by using the top-down procedure, we have that there is no successful derivation for goal 1. We conclude that goal 1 is true in SS(P ) D and the validity of the Hoare triple is proved.
In practical verification systems, one can use the atom false 'with arguments', and instead of the clause 1, one might consider the clause: In this case, if a successful derivation starting from the pair false(M,Sum), true is found, then one could know the values of M and Sum which invalidate the triple.

Semantics Preserving Transformations
Program transformation is a technique that modifies the text of a program while preserving its semantics. Various programming languages and formal semantics can be considered, and also the notion of preservation can be defined depending on the applications. The transformation-based approach we will consider in this paper derives from two main streams of work that gained popularity starting from the 1970s. The first stream of work is on rule-based program transformation, which has been first proposed in the field of functional programming (Burstall and Darlington 1977) and later extended to logic programming (Tamaki and Sato 1984) and CLP (Etalle and Gabbrielli 1996). A second stream of work is on program specialisation techniques, such as partial evaluation and, in the case of (constraint) logic programming, partial deduction. Various surveys of early developments can be found in the literature (Jones et al. 1993, Gallagher 1993, Leuschel and Bruynooghe 2002.
The transformation techniques developed for CLP, with respect to its logical semantics, can also be applied to CHCs. In this paper we will survey a number of these transformation techniques, whose objective is to transform a set of CHCs into a new set for which satisfiability may be easier to check.
A transformation of a set S of CHCs into a new set S ′ is a pair, denoted S → S ′ . Often, the CHC transformation S → S ′ is obtained in several steps, by constructing a transformation sequence S 0 → S 1 → . . . → S n , such that S 0 =S and S n =S ′ . The semantics of interest is defined in terms of D-models (see Section 2.3), and we are mainly interested in the preservation of D-satisfiability.

Definition 1
A CHC transformation S → S ′ is said to be: (i) sound if the D-satisfiability of S ′ implies the D-satisfiability of S, and (ii) complete if the D-satisfiability of S implies the D-satisfiability of S ′ .
Note that in the above definition, S and S ′ may contain constrained goals, and these goals may be modified by the transformation.

Fold/Unfold Transformations
CHC transformation rules, such as fold/unfold rules, can be used to perform a sequence of small modifications at clause level, which may result in a radical restructuring of the whole set of clauses by changing their pattern of recursion. In the context of logic programming and CLP, many papers have addressed the problem of showing that the transformation rules preserve a large variety of semantics defined in terms of least Herbrand models, finite failure, computed answers Proietti 1994, Tamaki andSato 1984), least D-models (Etalle and Gabbrielli 1996), and many others, by taking into consideration also extra language features, such as negation as (finite or infinite) failure (Fioravanti et al. 2004, Roychoudhury et al. 2002, Seki 1991) and coinduction (Seki 2012).
We now present some transformation rules usually considered in the literature, with the help of an example, which also motivates their usefulness for program verification. Let us consider the following set S of CHCs over a particular instance of the constraint domain Array in which the array indexes and the array elements are assumed to be integers (see Section 2.1).  (I=N and S=0) or, if I<N, S is the sum of the elements of A from I to N-1. The constrained goal, i.e., clause 5, states the property that if all elements of A from I (≥0) to N-1 are positive, then their sum is not smaller than N-I. We may assume that, similarly to the example in the introduction, these clauses have been generated from an imperative program acting on arrays that defines a function asum, and the specification is given by the Hoare triple {all_pos(a,i,n)} s=asum(a,i,n) {s≥n-i}. In order to construct a model of clauses 1-5 that is definable in the constraint domain, a CHC solver needs to extend the Array constraint domain by array formulas with quantifiers over index variables (Bradley and Manna 2007). We will transform clauses 1-5 in such a way that this type of quantified constraints is no longer needed.
The transformation sequence starts off by applying the definition rule, which allows us to introduce a new predicate defined in terms of already existing predicates. In our example, the new predicate newa is defined as the body of clause 5: The objective of the subsequent transformation steps is to derive a recursive definition of newa. First, we apply the unfolding rule which, given a set S i of CHCs and a clause C: H ← c, B 1 , A, B 2 in S i , where A is any selected atom in the body and B 1 , B 2 are conjunctions of atoms, replaces C by the set of all resolvents (with respect to A) of C and the clauses in S i whose head is unifiable with A (modulo the theory of constraints). In our example, we unfold clause 6 selecting the atom asum(A,I,N,S), and by resolving that clause with respect to clauses 3 and 4, we get the following two clauses: The constraint in the body of clause 7 is unsatisfiable, and hence, by applying the clause deletion rule, we may remove that clause, which is true in all Array-interpretations. Now, we unfold clause 8 selecting all_pos(A,I,N) and, by applying again the clause deletion rule and replacing constraints by equivalent ones, we get the new clause: We can also fold clause 5 using clause 6, and derive the new constrained goal: 11. false :-S<N-I, I>=0, newa(A,I,N,S).
Finally, we apply another instance of the clause deletion rule, which consists in deleting any clause C from a set S i when no predicate in the constrained goals of S i depends on the head predicate of C. By this rule we can delete clauses 1-4, as the predicate newa depends on neither asum nor all_pos. The final set of clauses is S ′ = {clause 10, clause 11}. It is trivially satisfiable in the constraint domain Array because it does not contain any constrained fact for newa, and its least Array-model is the empty Array-interpretation. The following general result (De Angelis et al. 2018a, Etalle andGabbrielli 1996) guarantees that also the initial set S of CHCs is satisfiable in the domain Array.

Theorem 1 (Soundness and Completeness of Fold/Unfold Transformations)
Let S 0 → S 1 → . . . → S n be a transformation sequence of CHCs over a constraint domain D. Suppose that, for i = 0, . . . , n−1, S i+1 is derived from S i by an application of one of the following rules: definition, unfolding, folding, clause deletion and replacement of constraints which are equivalent in D. Suppose also that each clause used for folding has been unfolded in a previous step of the sequence. Then, (i) S 0 is D-satisfiable if and only if S n is D-satisfiable; and (ii) if S 0 has a D-definable model, then S n has a D-definable model.
Note that, in the case where both S 0 and S n are satisfiable, they may have different D-models, simply because they may contain different predicate symbols. However, their least D-models agree on common predicates (Etalle and Gabbrielli 1996). Point (ii) of Theorem 1 is important because, as already mentioned, many CHC solvers work by looking for D-definable models, and fold/unfold transformations guarantee the preservation of the existence of such models (De Angelis et al. 2018a). However, by the fold/unfold rules we may derive, from a set S 0 of satisfiable CHCs that do not have any D-definable model, for a given constraint domain D, a new set S n with a D-definable model that can be computed by a CHC solver (see also an example of this transformation in Section 6.2.1 where a set of satisfiable clauses with no LIA-definable model are transformed into a set of clauses with a LIA-definable model).
To understand why the condition on folding in Theorem 1 is indeed needed, let us observe that, in particular, it disallows self-folding. For instance, consider the following unsatisfiable set of clauses: 1. p.

By introducing the new predicate
3. q :-p. and then folding clauses 2 and 3 using clause 3 itself, we get the following set of clauses: 1. p. 4. false :-q. 5. q :-q.
which is satisfiable.
Besides semantics preservation, a very relevant issue for fold/unfold transformations is the design of strategies that guide the application of the transformation rules for the achievement of a specific objective. In particular, the introduction of new predicates via the definition rule (see, for instance, the introduction of predicate newa in the example above), also known as eureka step in the transformation literature (Burstall and Darlington 1977), often needs ingenious techniques to achieve automation. In the context of CHC verification, several fully automated strategies have been designed with the objective of deriving clauses whose satisfiability can be checked in a more efficient, effective way by CHC solvers. In Section 6, we will present some of those strategies through application examples, and we will point to the relevant literature for the detailed technical presentations.

CHC Specialisation
Program specialisation is a transformation that customises a program with respect to its context of use, often identified by a set of partially known input data (Jones et al. 1993). In the field of logic programming, program specialisation (and in particular, partial evaluation, also called partial deduction) has been formalised in a proof-theoretic way, by building upon the notion of incomplete SLD(NF )-tree (Lloyd and Shepherdson 1991). Such tree represents a set of partial computations starting from an atomic goal that constitutes the context of use of the program. From a set of incomplete SLD(NF)-trees, one can extract new clauses specialised to the atomic goals of interest. A similar approach has been extended to CLP ). An alternative, equivalent presentation, which we will follow here for CHCs, is based on fold/unfold transformations Pettorossi 1993, Sahlin 1993). Indeed, CHC specialisation can be viewed as a strategy for applying the transformation rules we have introduced in Section 3.1. The definition of a sound and complete CHC specialisation will be an instance of Definition 1 in the following sense. Given a set P of definite CHCs and an atomic goal false ← c, A, where A is an atom, a sound and complete CHC specialisation yields a set P ′ of clauses and an atomic goal From a technical point of view, the main restriction of CHC specialisation with respect to general fold/unfold transformations, is that the new predicates introduced by specialisation are defined by clauses whose body has a single atom, and not a conjunction of two or more atoms. Thus, each new definition introduces a specialised version of a given predicate, and in particular, a specialised version of the predicate occurring in the atom A. However, this characterisation of CHC specialisation should be taken with some flexibility, as there are techniques like conjunctive partial deduction (De Schreye et al. 1999), which similarly to the general fold/unfold rules, transform logic programs by producing specialised predicates that correspond to conjunctions of atoms.
Let us show how specialisation works with the help of an example. Let us consider the following set of CHCs over the constraint domain LIA: the clauses with respect to derivations of the atom false. Thus, by looking at goal 1, we use the definition rule and we introduce a specialised predicate sp(X) for the atom In this first step, we might have introduced a different specialised predicate, e.g., by taking into account the constraint X=0. The key issue of controlling the introduction of new predicates will be discussed later. Now, by unfolding clause 5, we explore all possible one-step derivations from p(X,[0]).
Clause 8 can be deleted because the constraint in its body is unsatisfiable. By folding clauses 1 and 6 using clause 5, which defines the specialised predicate sp, we derive our final set of clauses: It is easy to see that this set of clauses is satisfiable. Indeed, its least LIA-model is {sp(X) :-X>0.}, which can be computed in two iterations of the immediate consequence operator. This example suggests some of the potential advantages of CHC specialisation. First of all, specialisation computes a portion of the CHCs that is relevant to the goal of interest. For instance, the predicate q, which might require a complex computation when checking satisfiability, has been discarded. Another interesting effect is that lists have been removed, and hence the specialised CHCs can be solved on the LIA domain, instead of the more complex domain that combines Term and LIA.
Two main control issues must be tackled for automating CHC specialisation (Leuschel and Bruynooghe 2002). The first one is local control, that is, the control of the unfolding process starting from a given definition of a specialised predicate. The specialisation algorithm should: (i) select an atom in the body of a clause to be unfolded (trivial in our example because all clauses are linear), and (ii) decide when to stop unfolding (after one step in our example).
The second issue is global control (Martens and Gallagher 1995), that is, the introduction of suitable definitions of specialised predicates. When we stop unfolding, we may want to replace (by folding) a constrained atom by a specialised predicate, as done in the above example by folding clause 6 using clause 5. To perform this folding we may need to introduce a new specialised predicate definition, which in turn must be unfolded, thus generating new constrained atoms to be folded. In order to terminate the whole process, we need to introduce a finite number of new definitions by which we are able to fold all atoms in the body of the clauses derived by unfolding (this is related to the closedness and coveredness conditions introduced by Lloyd and Shepherdson (1991) and , respectively). In most specialisation algorithms for CLP and CHCs, this set of definitions is constructed via suitable generalisation techniques Gallagher 2003, Fioravanti et al. 2013a), which compare the various specialised versions of the same predicate introduced during transformation, and compute a finite set that generalises them all by using, for instance, widening operators on constraints derived from the field of abstract interpretation Cousot 1977, Cousot andHalbwachs 1978). More details on widening and generalisation will be given in Sections 5 and 6.

Redundant Argument Removal
Redundant argument removal in a set of clauses P with respect to a goal G is a program transformation that removes an argument from a predicate in all its occurrences in P ∪ {G}. Let us call the resulting clauses and goal, after deleting the argument, P ′ and G ′ , respectively. Algorithms, called RAF (Redundant Argument Filtering, for topdown elimination with respect to a goal) and FAR (for bottom-up goal-independent elimination), which remove redundant arguments, were formulated by Leuschel and Sørensen (1996). The RAF and FAR algorithms determine sound and complete transformations from P ∪ {G} to P ′ ∪ {G ′ }. Similar algorithms for CLP have been presented by De Angelis et al. (2017b). Removing redundant arguments can be a useful pre-processing step since removing variables leads to the elimination of constraints, and can greatly reduce the complexity of constraint solving operations. The RAF and FAR algorithms are related to classical liveness analysis, as shown by Henriksen and Gallagher (2006), while the relation to the well-known notion of slicing was discussed by Leuschel and Vidal (2005).
Consider the following simple example (Leuschel and Sørensen 1996, adapted from Example 8), which illustrates how the combination of argument removal and constraint simplification can result in the removal of constraints. It is common for verification conditions to include a goal of the form false ← c, p(X 1 , . . . , X n ), where p(X 1 , . . . , X n ) represents the state of the computation at some program point, and c is a constraint on a small subset of the state variables X 1 , . . . , X n . In such cases, redundant argument removal can often lead to the elimination of constraints involving the remaining variables of the predicate p in other clauses, whose values do not affect c.

Example 13
Let us consider the clauses: Applying the algorithm RAF with respect to the goal false :-X>0, q(X,Y) results in the following clauses in which the second argument of q is removed. Intuitively, the argument Y is not 'used' in the goal. The constraint X<Y can then be replaced in the clause body by true. Applying the FAR algorithm to the resulting clauses further eliminates the remaining argument of q1, after which the constraint X>0 can be replaced by true and we are left with the clauses false :-q2. q2 :-true.
Note that the RAF algorithm can be reconstructed as an application of the fold/unfold transformation rules (by introducing a new predicate defined by q1(X) :-q(X,Y), in our example), while, in general, FAR cannot, in a straightforward way, as it exploits information derived from the constrained facts, rather than from the clause where the predicate we want to transform occurs.

Query-Answer Transformations
Query-answer transformations were originally inspired by the magic-set transformation from deductive databases and the language Datalog (Bancilhon et al. 1986, Rohmer et al. 1986). The typical form of the query-answer (QA) transformation is as follows: given a set P of definite clauses and an atom A, let {p 1 , . . . , p n } be the predicates occurring in P ∪ {A}. For each predicate p i , with 1 ≤ i ≤ n, define an answer predicate p a i and a query predicate p q i . Let the atom A a (resp. A q ) be the same as atom A with the predicate p replaced by p a (resp. p q ). The transformed clauses consist of the union of two sets of clauses, called the answer clauses P a and the query clauses P q (Kafle and Gallagher 2017a). Given a set P of definite clauses and a goal false ← c, A, then for each clause H ← c, A 1 , . . . , A n (n ≥ 0) in P , we have that: (i) P a contains the answer clause H a ← c, H q , A a 1 , . . . , A a n , and (ii) P q contains the query clauses A q j ← c, H q , A a 1 , . . . , A a j−1 , for 1 ≤ j ≤ n. In addition to the above clauses, P q contains the query clause A q ← c.
The relevant correctness property of the transformation is that P ∪ {false ← c, A} is satisfiable if and only if P a ∪ P q ∪ {false ← c, A a } is satisfiable. The purpose of the QA transformation is to simulate a top-down derivation (see Section 2.4.2) with left-toright computation rule; the query predicates capture the calls in a top-down, left-to-right derivation of A, and the answer predicates represent the result of successful calls within the derivation.
The bottom-up procedure for the set R of CHCs (see Section 2.4.1) yields the following , and hence the original set {1,2,3} of clauses is satisfiable. However, note that the least model of the set of the original set of clauses {2,3} is infinite. Furthermore, the top-down derivation from goal 1 in the original clauses yields a finite computation, failing after a call to p(0).
Applying the QA transformation to linear clauses yields clauses in which the answer predicates depend on the query predicates, but not vice versa. However, in the case of non-linear CHCs, QA transformation gives clauses in which answer predicates and query predicates are mutually dependent. For example, for a clause of the form p(X) ← c, r(Y ), p(Z) (with a left-to-right computation rule), p q depends on r a (via query clause p q (Z) ← c, p q (X), r a (Y )), which depends on r q (via answer clause of the form r a (X) ← r q (X), . . .), which in turn depends on p q (via query clause r q (Y ) ← c, p q (X)).
The use of QA transformations is entirely pragmatic; they allow bottom-up analysis tools (see Section 5.1) to achieve the constraint propagation and thereby analysis precision that would otherwise require top-down analysis frameworks (see the paper by Codish et al. (1997) for a related discussion on the precision of goal-dependent analyses versus goal-independent analyses). Frameworks for goal-dependent analyses making use of such transformations were developed (Kanamori 1993, Debray and Ramakrishnan 1994, Nilsson 1995. Examples of practical implementations of logic program analysis using QA transformations include the work of Codish and Demoen (1995) for modes and simple types and Gallagher and de Waal (1994) for regular approximations.

From Programs to Constrained Horn Clauses
Constrained Horn clauses have been used to represent a wide variety of systems and programs in other languages. These include imperative, functional and object-oriented programs (at different compilation levels, including bytecode, LLVM-IR, or machine instructions) (Peralta et al. 1998, Henriksen and Gallagher 2006, Méndez-Lojo et al. 2007, Navas et al. 2008, Gómez-Zamalloa et al. 2009, Grebenshchikov et al. 2012, De Angelis et al. 2015, Kahsai et al. 2016, Pérez-Carrasco et al. 2020. Apart from programming languages, Section 7 mentions other formalisms that have been translated into CHCs for the purpose of verification.
In this section we summarise different approaches to translating programs, focussing on the translation of imperative programs, together with properties to be proved, into a set of CHCs to be tested for satisfiability.

Semantics-driven Translation of Imperative Languages
An imperative program defines a relation s, σ 0 =⇒ σ 1 , which means that if statement s is executed in initial state σ 0 , then σ 1 is the state after execution of s, assuming that the execution halts. In this discussion, a program state is just a mapping from variables to values; see examples later in the section. The relation =⇒, closely related to the wellknown notion of a Hoare triple (Hoare 1969), can be specified by Horn clauses, using the operational semantics of the language of s, in two main styles: small-step (structural operational semantics) (Plotkin 1981) or big-step (natural semantics) (Kahn 1987), or a mixture of the two. Let the predicate exec(S,St0,St1) represent the relation, where S, St0 and St1 are first-order terms representing s, σ 0 and σ 1 , respectively.

Small-step specification
In the small-step style the exec relation is specified as a chain of steps. In a single step s 0 , σ 0 ⇒ s 1 , σ 1 , s 0 is executed in state σ 0 , leaving the remaining statement s 1 to be executed in state σ 1 ; this is represented by the relation step(S0,St0,S1,St1) in which The small step for a simple statement such as an assignment of the form x := e, represented asg(var(X),E), evaluates the expression e in state σ 0 (using predicate eval), computes state σ 1 by replacing the value of x with the result of the evaluation (using predicate replace) and moves to the halt statement.
Let the term seq(S1,S2) represent the compound statement s 1 ; s 2 , where S1 and S2 represent the component statements s 1 and s 2 , respectively. Then a small step on s 1 ; s 2 is specified as follows.
For program analysis and transformation, both big-step and small-step styles have advantages and disadvantages. Clauses derived using small-step semantics are often simpler, and essentially represent transition systems; thus they are amenable to well established model-checking techniques. Big-step predicates allow compositional analysis since each program component is represented by an input-output predicate; however, this means that predicates have a greater number of arguments than small-step predicates, which can increase the complexity of analysis algorithms.

Big-step specification
In the big-step style, the exec relation is defined by structural decomposition of statements. For instance, the complete execution of x := e and s 1 ; s 2 are specified as follows.
These logical formulations of big-and small-step semantics are direct translations of the semantic rules to be found in textbooks, e.g., (Nielson and Nielson 1992) (see Figure 3). The close connection between semantic judgements and Horn clauses was first noted by Kahn and exploited in semantics-based tools (Kahn 1987, Donzeau-Gouge et al. 1984). More complex semantic rules than the simple ones considered above can be represented, such as the Clight big-step specifications for a subset of the language C (Blazy and Leroy 2009).
Derivation of small-step CHCs from big-step CHCs, and vice versa, can also be defined (Gallagher et al. 2020). Big-step and small-step styles can be mixed; for example, a procedure call in the small-step style can be defined as a single step that completely executes the procedure body, such as is done in (De Angelis et al. 2017b). The following clause omits parameter passing, for simplicity, and we assume that def(F,FDef) encodes the relation between the procedure name F and its definition.

Translation by specialisation
Let I be the set of CHCs defining the exec relation, introduced in Section 4.1.1, for the language of statement (or program) s, that is, exec(S,St0,St1) holds iff s, σ 0 =⇒ σ 1 . Then, we can apply CLP specialisation (Section 3.2) to I ∪ {false :-exec(S,St0,St1)}, yielding a specialised version of the exec relation for S. This is an instance of the first Futamura projection (Futamura 1971); an interpreter specialised (by partial evaluation) with respect to a source program P can be seen as a compilation of P into the language of the interpreter, which in our case is the language of constrained Horn clauses. By suitable choice of renaming definitions, the syntactic structure of P and the state representations can be removed, leaving predicates whose arguments are the values of the program variables.

Example 15
Let the source program consist of the assignment sum = sum_upto(m), together with the function in Figure 1. Using a big-step semantics specification of exec, we obtain by partial evaluation the following CHCs 3 : , and M1 is detected during specialisation to be equal to M. After partial evaluation, every statement of the source program results in a corresponding call to exec; trivial calls to exec are then unfolded. These clauses can be run as a logic program with goal asg1(M,Sum1) (assuming standard procedures for evaluating arithmetic predicates) with some specific input value of M, simulating the execution of the given source program and returning the result Sum1.
A similar translation based on a small-step semantics can also be performed. Variations of this are described in the literature (Peralta et al. 1998, Henriksen and Gallagher 2006, De Angelis et al. 2015. Calls to the step predicate can be completely unfolded, leaving linear clauses of the form: where s0, st0, s1, st1 are terms and c is a constraint on the variables occurring in those terms. The predicate run can then be renamed as in the big-step translation.
The main advantage of translation by specialisation of a semantics-based interpreter is that the correctness of translation follows from the correctness of the interpreter and of the partial evaluator. The correctness of semantics-based interpreters is established by reference to the formal semantic rules of which the interpreter is composed. The correctness of the partial evaluator can be demonstrated once and for all, and can then be applied to many different interpreters.

Generating verification conditions from semantics-based interpreters
Consider a Hoare triple {Pre} s {Post}, where we have predicates on states pre(St) and post(St) defining Pre and Post, respectively, and error(St) defining the negation of Post. We also assume that the statement s is given using a fact prog(S). The Hoare triple is expressed by a goal: For instance, the verification problem presented in Section 1 is to show that the Hoare triple {m≥0} sum = sum_upto(m) {sum≥m} is valid. Let pre, post, and error be defined as follows: (g') and T ′ is the set of clauses shown in Example 15, which is essentially the same set of verification conditions (see clauses 1-4) shown in Section 1. (Note, in fact, that the third argument of predicate while4 in T ′ is redundant.) Reachability-style verification conditions. Assume now that the exec predicate is specified using small-step semantics, using the clauses for exec, run, and step shown in Section 4.1.1. We derive reachability-style verification conditions by an unfold-fold transformation of the semantics-based formulation of the verification of a Hoare triple. By unfolding exec, we obtain the following clauses whose satisfiability has to be checked (together with the clauses defining step): Unfolding the definition of error_reach and folding twice, we obtain the following clauses: After specialising these clauses for the instances of pre, error, and S from Section 1 (in particular, S is asg(var(sum),call (sum_upto,[var(m)])), we obtain the following different set of verification conditions than the ones shown previously: This set of conditions has some potential advantages over the previous ones. The predicate arguments relate to only one state at a time, rather than both an initial and a final state as encoded in the exec or run predicates. Secondly, small-step semantics gives linear clauses that are closely related to the transition systems handled by model checkers and techniques for reachability analysis.
The above clauses encode backwards reachability; the base case of the error_reach relation is the error state and the goal is the initial state. A similar unfold-fold transformation can be performed to yield verification conditions based on forwards reachability, or else the Reversal transformation discussed in Section 6.1 can be applied to the backwards reachability clauses shown above. The resulting set of clauses (shown in the following subsection) is essentially the same as the schema for proving safety properties of transition systems given by Grebenshchikov et al. (2012).

Translation via Proof Rules
Although the semantics-based approach provides a comprehensive framework for deriving CHCs and verification conditions from imperative programs, other techniques are often used in the literature. Rather than translating the source language, some works translate a verification problem for some source language into CHCs indirectly, by encoding the proof rules and semantic model of the system as CHCs.
A comprehensive presentation of CHC-based verification was given by Grebenshchikov et al. (2012); in that work, it is assumed that imperative procedures are represented as transition systems, and CHCs are then constructed from the transitions themselves and from CHC schemata for proof rules from the literature on program verification, such as relyguarantee rules, procedure summarisation rules (Reps et al. 1995), and termination proof rules. For instance, the following scheme is used to formulate proofs of safety of a transition system, where tr(St0,St1) represents a transition from state St0 to state St1,init(St) states that St is the initial state, reach(St) states that St is reachable from the initial state, and error(St) states that St is an error state. Essentially the same scheme was derived in the previous section from semantic definitions and unfold-fold transformations. Other proof-based approaches are briefly presented in Section 7.

Abstract Compilation
A variation on the approach described above is obtained when the semantics-based interpreter is an abstract interpreter written as a set of CHCs, which is then specialised with respect to a given source program. The resulting CHCs represent an abstraction of the original source program. This technique, and its application to program analysis, is called abstract compilation (Warren et al. 1988). The aim is to generate from an original source program P an abstract set of clauses P ′ whose execution yields the analysis results corresponding to the abstraction encoded in the interpreter. An example is the generation of size-change transitions for termination analysis, where the abstract interpreter computes the size of data structures rather than their values (Verschaetse and De Schreye 1992).

Compiler-based Translation
Translating from general-purpose programming languages such as C or Java to CHCs is a challenge due to the complexity of the source language. A pragmatic approach is to rely on a compiler from the source language into an intermediate language such as three-address code, LLVM, or Java bytecode, and then translate from there into CHCs.
Indeed, it has been argued that constrained Horn clauses provide many advantages as an intermediate compiler representation language (Méndez-Lojo et al. 2007, Gange et al. 2015, naturally incorporating features such as SSA form, reduction of all iterative constructs to a single one (recursion), clarification of variable scope, built-in capture and representation of alternative executions paths and non-determinism, and so on. A CHC representation facilitates analysis and optimisation of compiled code using solvers, analysers, and transformation tools available for CHCs. These arguments apply to all CHC-based representations of imperative code, not only those intended for compilation.
SeaHorn, a verification framework for C based on CHCs, uses a compiler front-end and then "takes as input the optimized LLVM bitcode and emits verification conditions as Constrained Horn Clauses (CHC)" . JayHorn, a translator for Java, follows a similar approach (Kahsai et al. 2016); the description of the translation to CHCs states that "most steps of the translation from Java into logic are implemented as bytecode transformations, with the implication that their soundness can be tested easily". Thus, it is argued that the translation from intermediate languages is simpler than translating the source program. Neither of the above cited works provides a formal proof of correctness of the translation, relying on the correctness of the compiler to reduce the source to a form where the translation is relatively straightforward.

Translation of Source Language Annotations
Some programming languages and systems provide facilities for adding annotations to the source code, supporting software engineering methods such as design by contract (Meyer 1988, Leavens et al. 2006), or as a part of an advanced program development environment integrating debugging, analysis, and static and dynamic verification (Hermenegildo et al. , 2005Puebla et al. 2000).
Such languages and systems include assertions such as assume(A) and check(A). For example, a procedure contract in Eiffel or JML might contain in the procedure body the precondition assume(x > 0), where x is a parameter of the procedure, meaning that the procedure call is assumed to satisfy that condition. Similarly, at the end of the procedure the assertion check(x < w) means that if the precondition holds when the procedure starts, and the procedure terminates, then at termination we should have x < w. In a constraint logic programming language with assertions, such as Ciao , similar check-style literals can be used at any program point, but there is also a specific form for stating conditions on the execution of an atom. For instance, we may have: :-check calls p(X,W) : X>0. (1) :-check success p(X,W) : X>0 => X<W.
(2) where assertion (1) is a condition X>0 on the call constraints for the atom p(X,W) and assertion (2) is a condition X<W on the success (answer) constraints for the same atom, for calls that meet the call constraint X>0. There may be several of these assertions for a given atom.
In general, verification conditions for such procedure contracts are essentially the same as for a Hoare triple, and can be generated from the language semantics as discussed above.
Conditions to be checked may be inserted at arbitrary program points, and a general scheme for generating CHC verification conditions is to assume that for each program point k there is a predicate reach k (St), such that St is the state when point k is reached. Then, the verification condition for some property ϕ that should hold at point k is the goal false ← reach k (St), error(St), where error(St) is a predicate defining the negation of the desired property ϕ on state St.
As we will see in Section 5.2, static analyses can produce information directly at all program points k, without explicitly generating predicates reach k (St), for each k. Program point assertions can be checked directly against this inferred information.
An additional proof requirement in the above precondition/postcondition scenario may consist in checking that all calls to a procedure satisfy a given precondition. For example, the Ciao calls assertion as (1) above, does require this. If this precondition cannot be proved statically, before running the program (and this may always happen because of undecidability limitations), then a dynamic, run-time check will be introduced for it, issuing a warning or calling an exception handling routine if the check fails .

Analysis for Verification
In this section we review techniques for CHC analysis applied to verification. These techniques, derived mainly from the CLP literature, in some cases directly yield a proof of satisfiability (or unsatisfiability), while in others, they help with inferring relevant program properties such as loop invariants. Static analysis also plays an important role in guiding some CHC transformations, especially specialisation.
The main technique used in these approaches is Abstract Interpretation (Cousot and Cousot 1977), a technique for static program analysis in which execution of the program is simulated on an abstract domain (D α ) which is simpler than the concrete domain (D). Values in the abstract domain and values in the concrete domain are related via a pair of monotonic mappings α, γ : the abstraction α : D → D α , and the concretisation γ : D α → D, which form a Galois connection. An abstract value d ∈ D α approximates a concrete value where ⊑ is the partial ordering on D α . We refer to these abstract values also as descriptions. The correctness of abstract interpretation guarantees that the descriptions inferred (by computing a fixpoint through a Kleene sequence (Tarski 1955)) approximate all the actual values which occur during any possible execution of the program, and that this fixpoint computation process will terminate given some conditions on the abstract domains (such as being finite, or of finite height, or without infinite ascending chains) or by the use of a widening operator (Cousot and Cousot 1977). Guaranteed termination implies one of the fundamental characteristics of abstract interpretation-based analyses: automation. Given an abstract domain and, if needed, a widening operator, analysis does not require user intervention. This comes at the price of some loss in precision, determined by the abstraction used. Abstraction also brings about scalability, since it makes it possible to trade off precision for efficiency. These two characteristics enable the use of abstract interpretation in practical automated tools.
In the following we review the two main techniques used for CHC analysis applied to verification, which are based on abstracting respectively the bottom-up and top-down satisfiability procedures of Section 2.4.

Bottom-up Semantics-based Analysis
The bottom-up approach to logic program analysis was first proposed by Marriott and Søndergaard (1988) and further elaborated by Codish et al. (1994). The approach is based on the bottom-up semantics discussed in Section 2.4.1, in which the least model of a set P of clauses is computed as the least fixpoint of the function T D P : 2 B D → 2 B D , that is, the least upper bound of the sequence ∅ ⊆ T D P ↑ 1 ⊆ T D P ↑ 2 ⊆ . . . Bottom-up analysis using abstract interpretation involves approximating the function T D P by a new continuous function U P : A → A, where the abstract domain A is a complete lattice with bottom element ⊥, partial order ⊑, and concretisation func- . . converges to an over-approximation of lfp(T D P ), that is, lfp(T D P ) ⊆ γ(lfp(U P )). If the lattice A has no infinite ascending chain, lfp(U P ) is reached in a finite number of steps; otherwise a widening (Cousot and Cousot 1992) is used to construct a sequence ⊥ ⊑ M 1 ⊑ M 2 ⊑ . . ., such that for all i ≥ 1, U i P (⊥) ⊑ M i and the sequence is ultimately stationary; that is, for some finite k, M k = M k+1 = M k+2 = . . . In both cases we obtain in a finite number of steps some over-approximation L of lfp(U P ). Thus, information about the least model of P can be inferred and hence satisfiability can be checked; in particular, if a goal false ← c, B 1 , . . . , B n is true in γ(L), then it is also true in lfp(T D P ) and hence P ∪ {false ← c, B 1 , . . . , B n } is satisfiable. An early example of bottom-up analysis was the type analysis by Barbuti and Giacobazzi (1992). Mode analyses using a bottomup analysis framework were also developed by Corsini et al. (1994) and .

Example 16
Consider again the clauses of Example 9 on the constraint domain Integer. They are: A bottom-up analysis using the abstract domain of convex polyhedra over real numbers (Cousot and Halbwachs 1978) is applied to these clauses. This kind of analysis was first introduced into logic programming by Benoy and King (1997). For each predicate p(X 1 , . . . , X n ), where X 1 , . . . , X n range over reals, a convex polyhedron is represented by a constrained fact p(X 1 , . . . , X n ) ← c, where c is a linear constraint over X 1 , . . . , X n representing a convex polyhedron. An element of the abstract domain for the set of CHCs at hand is thus a set of constrained facts, one for each predicate. The concretisation function maps a set of constrained facts to the set of atoms p(d 1 , . . . , d n ) such that the point (d 1 , . . . , d n ) is inside the polyhedron for p. The function U P is defined as any function on the tuple of polyhedra for the predicates, satisfying T D P • γ ⊆ γ • U P ; a suitable implementation of U P makes use of well-established libraries for manipulating convex polyhedra such as the Parma Polyhedra Library (Bagnara et al. 2008). The abstract domain has infinite ascending chains and so, in general, a widening operation on polyhedra is needed to force convergence of the sequence ⊥ ⊑ U P (⊥) ⊑ U 2 P (⊥) ⊑ . . . In the following sequence of approximations, we first compute the approximation of the model of the recursive predicate while; this is reached in Step 4 after applying a widening from Step 3 to Step 4, which (in particular) discards the potentially infinite sequence of constraints X=<1, X=<2, . . . In Step 5, the approximation of the model of the non-recursive predicate sum_upto is obtained in one step. The goal false :-M>Sum, M>=0, sum_upto(M,Sum) is true in the concretisation of the model computed at Step 5, and hence we can conclude that clauses 1-4 are satisfiable.

Top-down Semantics-based Analysis
Top-down analyses represent another class of CHC-based program analyses, and were first used in analysers such as MA3 and Ms (Warren et al. 1988), PLAI Hermenegildo 1990, 1992, García de la Banda et al. 1996), GAIA (Le Charlier and Van Hentenryck 1994), or the CLP(R) analyser (Kelly et al. 1998). This style of analysis was extended early on to CLP/CHCs by García de la Banda and Hermenegildo (1993) and García de la Banda et al. (1996). These techniques have also been applied to the analysis of functional, imperative, and object-oriented programs (Méndez-Lojo et al. 2007, Albert et al. 2007, Navas et al. 2008, Liqat et al. 2014, 2016, Pérez-Carrasco et al. 2020, by transforming the original program into CHCs as explained in Section 4. Such transformations often use the big-step semantics approach.

Basic top-down analysis. Top-down analyses are based on the top-down semantics of CHCs presented in Section 2.4.2 or variations thereof.
A basic top-down analysis using abstract interpretation can be derived from this semantics, in a similar way to the bottom-up analysis, as we now specify. Recall that the top-down semantics is given by a rewriting system on a set S, whose elements are the pairs B, e , where B is a multiset of atoms and e is a constraint on a given constraint domain D, together with the distinguished element fail. Every element of S can be viewed as a constrained goal, being fail any unsatisfiable goal. A rewriting step on S, denoted −→, is either an r-rewriting (−→ r ) or a c-rewriting (−→ r ). Given a set Q of goals in S, we define the one-step top-down function td Q : 2 S → 2 S , as follows: Then, we have that the set of goals reachable by a (possibly infinite) sequence of rewritings from Q is equal to lfp(td Q ).
To construct an abstract interpretation, we assume as before an abstract domain A which is a complete lattice with bottom element ⊥ and concretisation function: γ : A → 2 S . Thus, an element of A denotes a set of goals. Let I in A be an abstract goal. An abstract top-down function is a function td α I : A → A, satisfying td γ(I) • γ ⊆ γ • td α I . This condition ensures that td α I has a least fixpoint and lfp(td γ(I) ) ⊆ γ(lfp(td α I )). And-trees and call-success semantics. For top-down analysis, it is useful to structure derivations as trees, rather than sequences of rewritings. This will allow us to identify the call and (possibly) success constraints for each atom occurring in a derivation, and this information that can be directly related to atoms in the CHCs. First, we need the following notion. Given a set P of CHCs, an and-tree for P is defined as follows. 1. Each node is a triple A, c, C , where A is an atom (possibly the atom true), c is a constraint whose free variables are a subset of vars(A), and C is a clause in P . The component C is empty for leaf nodes.

In each non-leaf node, the C component is a clause
which is renamed so that: (i) the head A is identical to the atom of the node, and (ii) the variables which occur in the body of the clause and not in the head, do not occur outside the subtree at that node. Constrained facts are written as A ← c ′ , true. 3. A non-leaf node A, c, A ← c ′ , B 1 , . . . , B k has k ≥ 1 ordered children, B 1 , proj(c ∧ c ′ , vars(B 1 )), C 1 , · · · , B k , proj(c ∧ c ′ , vars(B k )), C k with possibly empty clauses components C 1 , . . . , C k . Let t be an and-tree and constr(t) be the set of all constraint components of the nodes of t. Then t is feasible if constr(t) is satisfiable; t is successful if it is feasible and all leaf nodes have atom true; t is failed if it has a leaf node with constraint false. When understood from the context we will feel free to say 'tree', instead of 'and-tree'.
Call constraints and answer constraints in an and-tree. For each successful and-tree t with root A, c, C , the answer constraint of the root is proj(constr(t), vars(A)). Nonsuccessful and-trees have no answer constraint of the root. We can also compute call constraints for nodes of an and-tree, corresponding to the leftmost selection rule. A node N = A, c, C has a call constraint if the subtrees t 1 , . . . , t j (j ≥ 0) rooted at the sibling nodes to the left of N are successful, and have answer constraints c 1 , . . . , c j , respectively. In this case the call constraint is proj(c ∧ c 1 ∧ . . . ∧ c j , vars(A)).
The analysis graph approach. Many practical top-down abstract interpreters adopt a particular approach that is based on computing an analysis graph. This approach was first proposed in PLAI and is followed in other analysers, like GAIA, or the CLP(R) analyser. The graph inferred is a finite, abstract object whose concretisation approximates the (possibly infinite) set of (possibly infinite) maximal and-trees of the concrete semantics.
This approach separates the abstraction of the structure of the trees (i.e., the paths in the concrete trees) from the abstraction of the constraints at the nodes in the concrete trees. Thus, the abstract domain is made out of two abstractions. The first one, called T α , is typically built-in (even if there may be several choices for it), and is the abstract domain of the analysis graph, which finitely approximates the shapes of the concrete and-trees, independently of the contents of the nodes.
The T α abstraction is parametric on a second abstraction domain, called D α . Elements of D α are used as labels in the nodes of the analysis graph, and represent the sets of call constraints and success constraints of the nodes of the concrete and-trees. Using the same T α abstraction, many D α domains have been developed to use T α for inferring modes, sharing (variable aliasing), types, numerical constraints, arrays, definiteness, determinacy, non-failure, resources, etc. Each such D α domain has its concretisation function γ and its basic operations on the domain lattice (such as least upper bound, greatest lower bound, and, optionally, widening), a few additional instrumental operations such as projection and extension, and the semantics (transfer functions) of any built-ins (basic operations) of the language (see, e.g., the papers by Muthukumar and Hermenegildo (1992), García de la Banda et al. (1996), and Hermenegildo et al. (2000)).
The input to the analysis is a set P of CHCs, an abstract domain D α , and a set Q α of abstract goals 4 A i , λ i , where each A i is an atom with variables as arguments and λ i ∈ D α . The set Q α defines the (possibly infinite) set of concrete goals for which that the analysis should be performed: The concrete semantics to be safely approximated is then the set of all and-trees that have an element of Q as root. The result of the analysis is an analysis graph, where every node is of the form A, λ c , λ s , where {λ c , λ s } ⊆ D α (note that the component λ of a node has been split into a call component λ c and a success component λ s ).
Correctness of the analysis requires that if there are one or more nodes in the concrete trees of the form A, d c , d s (also for concrete nodes the constraint components is split into two), then there exists a node A, λ c , λ s in the analysis graph such that d c ∈ γ(λ c ) and d s ∈ γ(λ s ). This means that the analysis graph must capture all the call-success pairs in all the nodes of the and-trees of the concrete semantics. For a given predicate A, the analysis graph can contain more than one node, with different call descriptions. A node A, λ c , ⊥ indicates that calls to predicate A with description d ∈ γ(λ c ) either fail or do not terminate. An edge in the analysis graph A, λ c , λ s → B, µ c , µ s represents that calling A with calling description λ c generates an atom B to be called with calling description µ c . Correctness requires that if in any concrete tree there is a node A, d c with a child B, e c , then there exists an edge A, λ c , λ s → B, µ c , µ s in the graph such that d c ∈ γ(λ c ) and e c ∈ γ(µ c ).
Generating the analysis graph consists essentially in following the construction of the and-tree with two main differences: (i) instead of the concrete operations for the constraints, the operations from D α should be used, and (ii) in the construction of the graph, call descriptions are tabulated so that, if the abstract call constraint of a node is equal to (or, optionally, subsumed by) that of a node already present, the graph is not extended and, instead, an edge is introduced pointing to that node (see, node C in Figure 4). The success label is initialised to ⊥ and the iteration for constructing a fixpoint for the labels is started. For domains with infinite ascending chains the widening operator is applied to limit the number of call and success descriptions considered. Ad-ditional details and optimisations of the particular algorithms used can be found in the references given above. Also, many variants have been proposed and among them, let us mention the incremental analyses (Puebla and Hermenegildo 1996, García-Contreras et al. 2020a. In all cases by the fundamental results of abstract interpretation one has that (i) termination is guaranteed, and (ii) the concretisation of the analysis graph is a safe over-approximation of the and-trees generated by the concrete semantics. . Node B = ( par(Msg,X,P), (Msg/⊤, X/z, P/⊤), (Msg/⊤, X/z, P/b) ) captures the fact that par may be called with X bound to 0 in γ(z) and, if par succeeds, the third argument P will be bound to any value in γ(b) = {0, 1}. Note that node C captures the fact that, after this call, there are other calls to par where X/b. Edges in the graph stem from the A, λ c , λ s → B, µ c , µ s relation. For example, two such edges exist from node B, denoting that par may call xor (edge from B to D) or par itself with a different call description (edge from B to C). In this example we have used a simple, non-relational abstract domain. In the following example we will use a relational domain over the integers.

Example 18
The following is an encoding of the sum_upto example in Ciao The check calls assertion instructs the system to check that M>=0 holds for calls to sum_upto and, similarly, check success asks for a check that Sum>=M holds after successful derivations starting from {sum_upto(M,Sum)}, M>=0 (see also Section 4.5).
The checked success assertion for sum_upto is the result of comparing (reducing, using abstract specialisation) the original check success and the true assertion inferred, and it indicates that the postcondition Sum>=M has been proven for the assumption M>=0 (Bueno et al. 1997. However, since this assumption cannot be proven to hold without context information (i.e., without knowing how this module will be called), the check calls assertion remains in check status and a run-time test will be generated for it. If this module is analysed in the context of other modules that call it, perhaps inter-modular analysis allows this condition to be discharged and the run-time test eliminated. The analysis graph also contains abstract information at all points in the bodies of the CHCs, which can also be printed out as assertions, e.g., for the sum_upto predicate: sum_upto(X,R) :-true(X>=0), R0=0, true((X>=0,R0=0)), while(X,R0,R), true((X>=0, R0=0, R>=X, R>=2 * X-1, R>=3 * X-3, R>=4 * X-6)).
where the true literals are program point assertions which state properties that hold at those points (for a left-to-right computation rule).
Polyvariance (context-and path-sensitivity). The analysis graph approach allows representing the different call descriptions encountered during the execution, separating the cases in which such calls differ, even if some of them subsume others. This feature is traditionally referred to as polyvariance (or multivariance) in the context of logic program analysis, and, in our context, it serves two purposes: 1. Precision: Different calling descriptions for the same predicate can be recorded depending on which exact clause and literal this predicate is called from and with which call description. This idea of storing multiple calling contexts in this way is used in recent implementations of context sensitivity in imperative program analyses (Khedker andKarkare 2008, Thakur andNandivada 2020) where it is referred to as keeping multiple value contexts. 2. Efficiency: For the same literal and clause in the CHCs, storing different calling descriptions allows keeping the fixpoint computation localised to only those descriptions that change. In addition, the different call descriptions for and paths to a given predicate that the analysis graph encodes in a compact way are really representing different possible versions of that predicate. These versions, which are implicit in the analysis graph, can be materialised in a process called polyvariant specialisation (Bulyonkov 1984, Jacobs et al. 1990, Giannotti and Hermenegildo 1991, Jones et al. 1993, which is essentially the abstract version of traditional predicate specialisation (see Sections 3.2 and 6.1), allowing additional optimisations. An instrumental concept for the latter is abstract executability (Giannotti andHermenegildo 1991, Puebla and, i.e., the partial evaluation of concrete code with respect to abstract values.

Example 20
The following are all the versions (the abstract polyvariant specialisation) generated during analysis by the Ciao analyser for the sum_upto example, assuming as before the precondition M>=0, and using again the domain of convex polyhedra: The last version, predicate while_4, is obtained after a widening step, reaching a fixpoint expressed by the constraint X1>-1, R1>=X1+1, R>=R1, R>=X1+R1, which holds for call description X1>-1, R1>=X1. Note that this fixpoint denotes a subset of the model computed at Step 4 of Example 16 in which a bottom-up analysis is performed.
In addition to polyvariant specialisation, other, more powerful combinations of topdown analysis and partial evaluation have been proposed . In particular, the interleaving method of combining top-down analysis and partial evaluation of Puebla et al. (2006) has been proved to be strictly more powerful than any bounded sequence of applications of abstract interpretation and partial evaluation procedures.
Finally, note that the analysis graph, through the A, λ c , λ s → B, µ c , µ s relation, provides an abstraction of the paths followed by the concrete executions represented by the concrete trees. The analysis graph generalises the way in which the call-stack is represented in the popular call-strings method by Sharir and Pnueli (1981) (this method has been used in recent work (Khedker andKarkare 2008, Thakur andNandivada 2020)). Indeed, the call-string method only keeps track of the callers of the abstracted call, whereas the analysis graph allows us to infer, as a tree all the procedures executed before that call and not only its direct callers or a limited-depth sequence.

Abstraction Refinement
Previous sections have shown how abstraction Cousot 1977, Jhala andMajumdar 2009) can be effectively used within bottom-up and top-down procedures to check satisfiability of CHCs and infer useful properties from them.
Abstraction also enables the design of hybrid approaches that combine bottom-up and top-down procedures to compute an over-approximation of the least D-model of a set P of CHCs. Indeed, in some cases, such an over-approximation S, where S ⊇ lm(P, D), can be computed in a finite number of steps as a D-definable interpretation by using these procedures enhanced with abstraction (Sections 5.1 and 5.2 present two effective ways for computing S). If a constrained goal G is true in S ⊇ lm(P, D), then G is true in lm(P, D) and hence P ∪{G} is satisfiable. However, if G is false in S, a derivation for G may or may not exist. If such a derivation can be constructed, then P ∪ {G} is indeed unsatisfiable. Otherwise, a spurious counterexample is used to refine the over-approximation S.
Predicate abstraction (Graf and Saïdi 1997) with Counterexample Guided Abstraction Refinement (CEGAR) (Clarke et al. 2003), and Property Directed Reachability (PDR) (Een et al. 2011) (we use this terminology to refer to all those verification methods originated from the hardware model checking algorithm IC3 (Bradley 2011)), represent the mainstream (software) model checking approaches, based on abstraction and its refinements, that have been successfully applied to the problem of checking satisfiability of CHCs (see, for instance, the CHC-COMP-20 report (Rümmer 2020)).
The well-established combination of predicate abstraction and CEGAR refinement is implemented by Eldarica (Hojjat and Rümmer 2018) and HSF-QARMC (Grebenshchikov et al. 2012). Specifically, given a predicate symbol p occurring in a set of CHCs and a set Pred of predicates, predicate abstraction maps p into a boolean combination of the predicates in Pred. Starting from a possibly empty set Pred, this approach makes use of spurious counterexamples to extend Pred with additional predicates, and thereby obtain more precise over-approximations. Craig interpolation (Craig 1957) is widely used as a tool for deriving additional predicates from spurious counterexamples (Jhala and Majumdar 2009, McMillan and Rybalchenko 2013, Demyanova et al. 2017.
Interpolation is also used as a generalisation technique to improve efficiency of tabling (Jaffar et al. 2009) for CLP programs and to enhance program verification techniques. In particular, interpolants are computed as generalisations of the constraints encountered during the construction of the derivation trees. The computed interpolants avoid redundant exploration of subtrees rooted at constraints that are subsumed by the corresponding tabled interpolant. Improvements and extensions of this approach have been effectively used to perform program verification (Jaffar et al. 2012, Gange et al. 2013. Abstraction and refinement are also the basic building blocks of PDR. In presenting this approach, we build upon Hoder and Bjørner (2012) as a basis to recast the PDR algorithm in terms of the definitions introduced in the previous sections and the following additional technical notions.
The index of an atom in a derivation is inductively defined as follows. All atoms in the initial pair of the derivation have index 0. If in the derivation there is a rewriting B, e −→ r B ′ , e ′ , where B ′ is the multiset of atoms obtained from B by replacing an atom A with index k by a multiset of atoms C, then the index of the atoms in C is k + 1 and the index of all other atoms in B ′ is the same as their index in B. Given a (successful or failed) derivation A, c −→ * r B, d −→ x L (where x is either r or c and L is either ∅, e or fail), the depth of the derivation is m+1, where m is the maximal index of an atom in B.
Given a set P ∪ {G} of CHCs, where P is a set of definite CHCs and G is a constrained goal, PDR incrementally constructs, by extension and refinement, a sequence σ of interpretations of the form: I 0 , ..., I n−1 , I n , such that I 0 = T D P (∅), where T D P is the immediate consequence operator defined in Section 2.4.1, and for k = 0, . . . , n−1, (i) I k |= G, (ii) I k ⊆ I k+1 and (iii) T D P (I k ) ⊆ I k+1 (that is, I k+1 is an over-approximation of T D P (I k )). PDR terminates the construction of σ at the smallest n where we have I n ⊆ I n−1 (in which case T D P (I n ) ⊆ I n and therefore lm(P, D) ⊆ I n ), or a successful derivation of G is found. Hence, upon termination we have that either I n |= G, in which case P ∪ {G} is satisfiable, or there exists a derivation of G, in which case P ∪ {G} is unsatisfiable. Now we present a high-level account of the mechanism for extending σ = I 0 , ..., I k by appending a new interpretation I k+1 or refining σ. This process starts by generating any I k+1 that satisfies T D P (I k ) ⊆ I k+1 . In the case where I k+1 |= G, PDR proceeds by attempting to construct a successful derivation of depth k + 1 for G. If such a derivation is found, then PDR terminates reporting that P ∪ {G} is unsatisfiable. Otherwise, assuming that G is false ← c, A 1 , . . . , A q , there exists a failed derivation and there is an atom A in B such that I j |= ∃(A ∧ d) and T D P (I j−1 ) |= ∃(A ∧ d) (meaning that I j represents a too coarse over-approximation of T D P (I j−1 )). This failed derivation is also called a spurious counterexample. In this last case, PDR refines σ by replacing I j by a different one, say I j , such that I j |= ∃(A ∧ d); then the construction of σ resumes from I j .
PDR guarantees that whenever a new over-approximation I k+1 is added to σ, all spurious counterexamples of depth k+1 have been removed (that is, I k+1 |= G), making PDR a complete procedure for showing unsatisfiability. Of course, the effectiveness of PDRbased algorithms highly relies on the underlying strategy for searching for (successful or failed) derivations of G, and the interpolation procedure used to get rid of spurious counterexamples.
The PDR solving approach presented in Hoder and Bjørner (2012) has been implemented on top of Z3 (de Moura and Bjørner 2008), and called Generalized PDR (GPDR) to stress the fact that it can deal with general, non-linear CHCs clauses. Indeed, the IC3 algorithm, which gave rise to the PDR solving approaches, has been introduced for performing model checking of transition systems, which correspond to linear CHCs.
Currently, Z3 provides the SPACER solving engine (Komuravelli et al. 2016) that further extends GPDR by computing under-approximations to improve the strategy for deriving counterexamples.
Let P be the set {clause 5, clause 6} and G be goal 7.
Note that there is some freedom in choosing such a constraint F and, in particular, we can take F as (X=<0, R1=R2) ∨(X=1, R2=R1+X), which is equivalent to T LIA P (I 0 ). However, by doing so, the refinement process would produce an infinite sequence σ of interpretations. Indeed, in order to help the convergence of σ to I n ⊆ I n−1 , PDR refines I 1 in a more gradual manner by trying to find a constraint that satisfies these additional two conditions: (c) all constraints occurring in constrained facts in P entail F, and (d) the interpretation I| F refined using F is a subset of T D P (I| F ). A constraint enjoying these properties is R2>=R1+X. Hence, we can use R2>=R1+X to refine the current over-approximation of the predicate while in I 1 , thereby getting I 1 = {while(X,R1,R2):-R2>=R1+X}. Now I 1 satisfies goal 7. Hence, PDR keeps going on by introducing a new interpretation I 2 , that is, {while(X,R1,R2) :-true}. Now, the algorithm performs exactly the same steps performed from the introduction of I 1 . This process leads to the refinement of I 2 and we get I 2 = I 1 , and thus PDR terminates computing an over-approximation of lm(P, LIA). Since I 1 satisfies goal 7, we conclude, as desired, that the Hoare triple is valid. Note that in Example 9 the proof of validity of the Hoare triple makes use of an induction principle.

Transformation for Verification
We recall from Section 4 that a program verification problem can often be reduced to the problem of checking the satisfiability of a set P ∪ Q of CHCs, called the verification conditions. The set P consists of clauses whose heads are atoms with user-defined predicate symbols (that is, definite clauses) and Q consists of clauses whose head is false (that is, constrained goals). In Section 4, we have also surveyed some techniques, based on the specialisation of interpreters, by which P ∪ Q can be generated from: (i) a program text written in a language whose semantics is specified by an interpreter, and (ii) a property to be verified for that program.
More transformations can be applied to the set P ∪ Q of CHCs, with the objective of easing the satisfiability check. That is, we can transform P ∪ Q to a new set P ′ ∪ Q ′ , and then attempt to check satisfiability of P ′ ∪ Q ′ using any of the techniques summarised in previous sections such as those based on bottom-up, or top-down, or abstractionrefinement approaches. Transformations can be sound and/or complete (see Definition 1). Using a sound transformation P ∪ Q → P ′ ∪ Q ′ , a proof of satisfiability of P ′ ∪ Q ′ implies the satisfiability of P ∪ Q. Using a complete transformation, a proof of satisfiability of P ∪ Q implies the satisfiability of P ′ ∪ Q ′ . By contraposition, this means that, if a counterexample to satisfiability exists in P ′ ∪ Q ′ obtained by a complete transformation, a counterexample to satisfiability also exists in P ∪ Q. Transformations that are sound and complete preserve both satisfiability and unsatisfiability.
CHC transformations can often take advantage of the analysis techniques described in Section 5, which may help infer over-and under-approximations of the least D-model of P . These combinations of CHC analysis and transformation can be applied as a preprocessing step, with the aim of enhancing the effectiveness of subsequent applications of CHC solvers, but they can also be part of the satisfiability checking algorithm itself.
In the rest of the section, we will first focus on the use of CHC specialisation, and other supporting analysis and transformation techniques, for propagating the constraints appearing in P ∪ Q and deriving a set of more specific clauses. We will show that this specialisation often aids the verification of satisfiability. Then, we will present techniques based on fold/unfold transformation rules, which extend CHC specialisation by allowing the introduction of new predicates defined as constrained conjunctions of atoms, instead of constrained atoms only (see Section 3). This extended ability is very helpful for relational verification and for the verification of programs manipulating inductively defined data structures. Finally, we will briefly recall various refinements and applications of the above mentioned techniques.

Constraint Propagation by Specialisation
In order to check the satisfiability of the set P ∪ Q of CHCs, different approaches have been proposed in the literature (see Section 2.4). Among these, CHC solvers based on abstraction refinement implement a hybrid bottom-up and top-down approach. They try to compute an over-approximation of lm(P, D) where all goals in Q are true (that is, the bodies of the goals Q are all false). This over-approximation is constructed in a bottom-up fashion, by applying some abstraction operator to the T D P immediate consequence operator. The search for such over-approximation is guided, through refinement, by looking at the goals in Q, and by interleaving the bottom-up procedure with the attempt to construct a successful top-down derivation of one of those goals which would show the unsatisfiability of P ∪ Q.
A weakness of this family of satisfiability procedures is that they may fail to derive from Q a refinement that is inductive, i.e., that is preserved by an application of T D P . In many cases we may mitigate this weakness by preprocessing the set of clauses and propagating constraints from Q into the clauses of P , so that information about the goals can be carried over during the bottom-up construction. Constraint propagation from goals can be achieved by CHC specialisation, as we explain with the help of an example.
Let us consider the following clauses with constraints in the domain LRA of Linear Real Arithmetic: The clauses are satisfiable, but the CHC solvers Eldarica and Spacer/Z3 (with default settings) fail to terminate on this simple example. A specialisation of the above clauses can be obtained by applying the fold/unfold transformation rules as described in Section 3.2. We introduce a specialised predicate 4. sp(X,Y,N) :-X>=0, Y>=0, p(X,Y,N). whose constraint is a generalisation of the one occurring in the body of the goal clause 1. Then, by unfolding clause 4, we get The constraint in the body of clause 6 implies X1>=0, Y1>=0, and hence we can fold this clause using clause 4. By also folding the goal clause 1 and simplifying the constraints, we derive the following specialised set of clauses Thus, the effect of specialisation has been to add the constraint X>=0,Y>=0 to both the recursive clause 9 and the constrained fact 8. Now, Eldarica (and Spacer/Z3) easily computes the following model for the derived specialised clauses 7-9: sp(X,Y,N) :-X>=Y+1, Y>=0.
Several algorithms have been proposed to mechanise CHC specialisation (Craig and Leuschel 2003, Fioravanti et al. 2001a, Peralta and Gallagher 2003. As already mentioned in Section 3.2, these algorithms control the application of the unfolding rule (local control) and, more crucially, the introduction of suitable specialised predicates (global control). We refer to the original papers for a detailed presentation of those algorithms. Here we will only discuss the role of constraint generalisation for global control.
Some specialisation algorithms manage the global control by maintaining a set Defs (possibly structured as a tree that records the various transformation paths) of specialised predicate definitions, that is, a set of clauses of the form sp(X) ← c, A(X), where: (i) sp is a new predicate symbol not occurring in P ∪ Q ∪ Defs, (ii) X is a tuple of variables, and (iii) A(X) denotes an atom whose variables are the components of the tuple X.
New predicate definitions are introduced by means of generalisation functions acting on clauses. These functions use generalisation operators acting on constraints as we now indicate.
Definition 2 (Generalisation) Given two constraints c and d in D, we say that d is more general than c, written c ⊑ D d, if D |= ∀(c → d), where D is the constraint interpretation of D. A generalisation of two constraints c 1 and c 2 is a constraint, denoted ω(c 1 , c 2 ), such that: (i) c 1 ⊑ D ω(c 1 , c 2 ), and (ii) c 2 ⊑ D ω(c 1 , c 2 ). The function ω is called a generalisation operator on D. (In general, ω may be non-commutative.) We say that an infinite sequence g 0 ⊑ D g 1 ⊑ D . . . of constraints stabilises if there exists n > 0 such that g n ⊑ D g n−1 . The generalisation operator ω is a widening operator if, for every infinite sequence c 0 , c 1 , . . . of constraints, the infinite sequence g 0 , g 1 , . . ., where: (1) g 0 = c 0 , and (2) for all i ≥ 0, g i+1 = ω(g i , c i+1 ), stabilises.
Given two clauses C: sp1(X) ← c, A(X) and D: sp2(X) ← d, A(X) (modulo the order of the variables in the tuple X), a generalisation of C and D, denoted gen(C, D), is the clause sp-gen(X) ← ω(proj(c, X), proj(d, X)), A(X), and gen is called a generalisation function.
Widening operators on the LRA constraint domain have been first introduced in the field of abstract interpretation (Cousot and Cousot 1977) (see also Section 5) and later used for the specialisation of constraint logic programs (Fioravanti et al. 2001a, Craig and Leuschel 2003, Peralta and Gallagher 2003. Widening is often combined with the computation of the convex-hull of a disjunction of linear constraints (Cousot and Halbwachs 1978), which may help discover relations among variables.
Many specialisation algorithms achieve termination by using a generalisation operator that is based on a widening operator on constraints. Indeed, any sequence of clauses obtained by repeatedly applying such an operator is necessarily finite.
A simple example of a widening operator in the LRA constraint domain, is defined as follows. Let c 1 = a 1 ∧ . . . ∧ a n be a constraint, where a 1 , . . . , a n are atomic constraints of the form p ≥ 0 or p > 0, and p is a linear polynomial. Given a constraint c 2 , the widening of c 1 with respect to c 2 , denoted c 1 ∇c 2 , is n i=1 {a i | c 2 ⊑ LRA a i }. This widening operator can also be extended to the case when some of the a i 's are equalities, by first splitting them into conjunctions of inequalities. Now, we see how, in our example, the generalisation operator based on the widening ∇, determines the introduction of the predicate sp. We start off from the goal clause 1, and we define a new predicate whose body is exactly the body of that goal: Clause 11 has an unsatisfiable body and is deleted. Clause 12 is simplified as follows: 13. sp1(X,Y,N) :-X=0, Y=0, 0<N, X1=1, Y1=1, p(X1,Y1,N).
Thus, we introduce a new specialised predicate defined as follow: 14. sp2(X,Y,N) :-0<N, X=1, Y=1, p(X,Y,N). whose body has a constraint that is the projection of the constraint of clause 13 onto the variables of atom p(X1,Y1,N) (we have renamed the variables). The comparison of clauses 10 and 14 shows that, by iterating the unfolding and projection operations, the specialisation would generate an infinite sequence of specialised predicate definitions.
Some specialisation algorithms avoid nontermination by applying the generalisation function gen to pairs of clauses (C, D), where C is an ancestor of D in the tree Defs of specialised predicate definitions, and the two clauses have the same atom in their body. In our example, clause 10 is the parent of clause 14 in Defs. Thus, we apply the generalisation function gen based on the widening operator ∇ to the pair (clause 10, clause 14). The value of gen is computed by applying the operator ∇ to the constraints appearing in the two clauses, as follows: where the left operand has been obtained by splitting the equalities of clause 10 into conjunctions of inequalities. Thus, the result of applying gen to (clause 10, clause 14) is clause 4, which defines predicate sp.
In some cases, in order to verify the satisfiability of P ∪ Q, it is useful to specialise the clauses by propagating constraints occurring in the constrained facts of P . Various approaches can be followed. In the case where all clauses in P ∪Q are linear, we can apply the Reversal transformation (De Angelis et al. 2014a), which, for each clause, interchanges its head with its body. The Reversal transformation is related to the transformation of regular grammars from right recursive to left recursive (and vice versa) (Brough and Hogger 1991). For instance, the clauses for reachability presented in Section 4.2 can be transformed from: and vice versa. Note that in the original set of clauses the predicate reach holds for the states that are reachable from the initial ones, while in the clauses obtained after Reversal reach holds for the states from which error states are reachable. Reversal is a sound and complete transformation. After Reversal we can specialise the clauses with respect to the constrained goal and propagate the constraint defining init(St).
As mentioned above, also the QA transformation has the effect of simulating bottomup evaluation through standard top-down execution. Thus, a technique for propagating constraints from constrained facts is to specialise a set of clauses with respect to the constrained goals, after applying the QA transformation to the original clauses. An advantage of the QA transformation over Reversal is that it can be applied to non-linear clauses. However, the QA transformation may transform a linear clause into a non-linear one, while Reversal preserves linearity.
Constraint strengthening is another transformation technique that has been proposed for propagating constraints from constrained goals and constrained facts (Kafle and Gallagher 2017a). A strengthening of a clause H ← c, A 1 , . . . , A n is a clause H ← c ′ , A 1 , . . . , A n , such that c ′ ⊑ D c. Note that replacing c ′ by false is strengthening. Constraint strengthening of clauses is a complete transformation in the sense of Definition 1, and thus can be used to check unsatisfiability. However, in general, constraint strengthening is not sound, as it can transform a set of unsatisfiable clauses into a set of satisfiable clauses (for example, {false :-p., p.} can be transformed into {false :-false, p., p.}).
One way to achieve a sound and complete constraint strengthening of a set P ∪ Q of CHCs is to add constraints that are a consequence of the body of the clause where the strengthening is realised. Let us see how we can obtain such a constraint strengthening. Consider a predicate p in P , and suppose that lm(P, D) |= ∀(p(X) → d). Then, every clause in P of the form p(X) ← c, B, can be replaced by p(X) ← c, d, B, and every clause in P ∪Q of the form H ← c, p(X), B, where H may be false, can be replaced by H ← c, d, p(X), B. If P ′ ∪ Q ′ is obtained by all these applications of constraint strengthening, then P ∪ Q is satisfiable if and only if P ′ ∪ Q ′ is satisfiable.
Properties of the form lm(P, D) |= ∀(p(X) → d) to be used for strengthening P ∪ Q, can be discovered by applying abstract interpretation techniques (see Section 5). A strategy proposed by Kafle and Gallagher (2017a) consists in transforming P ∪ Q by the following three steps, where, without loss of generality, we assume that Q consists of a single goal false ← e, A (we can always get to this case by introducing a new predicate defined in terms of the goals in Q).
Step (1). Apply the QA transformation to P ∪ {false ← e, A}, and derive a new set of clauses P a ∪ P q ∪ {false ← e, A a } (see Section 3.4); Step (2). Apply Convex Polyhedral Analysis (CPA) Halbwachs 1978, Benoy andKing 1997) to construct an over-approximation M of lm(P a ∪ P q , D).
Step (3). Since CPA computes a convex over-approximation for each predicate, without loss of generality, we may assume that M has a single constrained fact p a (X) ← g, for the answer predicate p a , and by the soundness and completeness of the QA transformation, p(X) ← g is also an over-approximation of the atoms for p that are true in lm(P, D), that is, {p(a) | p(a) ∈ lm(P, D)} ⊆ {p(a) | D |= ∃(g{X/a})}. Thus, lm(P, D) |= ∀(p(X) → proj(g, X)). The QA transformation at Step (1), enforces that the CPA bottom-up construction performed at Step (2) simulates top-down, goal-directed constraint propagation.
For example, consider again clauses 1-3 above. We rewrite them here for the reader's convenience.

At
Step (2) CPA derives the following model: where we have underlined the added constraints. Now, the constraint appearing in the body of clause 1' is unsatisfiable, and hence the set {1',2',3'} of clauses is trivially satisfiable.
The dual transformation to constraint strengthening is constraint weakening, that is, the replacement of the clause constraint c by c ′ such that c ⊑ D c ′ . Constraint weakening applied to the clauses of P ∪Q is a sound transformation but, in general, it is not complete. Thus, if the weakened set P ′ ∪ Q ′ of CHCs is satisfiable, so is the original set. Constraint weakening is related to abstraction techniques, as every D-model of P ′ ∪Q ′ (where false is considered as a user-defined predicate symbol) is an over-approximation of lm(P ∪ Q, D).
Finally, we point out that, as long as CHC transformations are sound and complete, we can compose any number of them while preserving both satisfiability and unsatisfiability. This opens the way to the design of (un)satisfiability checking algorithms that incorporate CHC transformations as building blocks. Some of these transformation-based algorithms are implemented in the CHC solvers VeriMAP (De Angelis et al. 2014b) and RAHFT (Kafle et al. 2016).
VeriMAP generates verification conditions by specialising an interpreter for the smallstep semantics of (a fragment of) the C language with respect to a given program, a precondition, and an error property (see Section 4). The tool generates linear CHCs. Then VeriMAP iterates the following three steps. (i) The specialisation of the CHCs with respect to constrained goals. (ii) The analysis of the specialised CHCs, based on unfolding and clause deletion, to determine whether or not there is a derivation of false. If such a derivation is found, then the clauses are unsatisfiable, else if the analysis is able to discover that such a derivation is impossible, because false does not depend on any predicate with constrained facts, then the clauses are satisfiable. Otherwise, the analysis is inconclusive. (iii) The reversal of the CHCs, in the case when the analysis at Step (2) is inconclusive. Reversal enables us to alternate the propagation of the constraints occurring in the goals with the propagation of those occurring in the facts.
RAHFT (Refinement of Abstraction in Horn clauses using Finite Tree automata) combines: (1) the preprocessing of the input CHCs by constraint strengthening, as recalled above, (2) the construction of an over-approximation of the least model of the clauses, based on Convex Polyhedral Analysis, and (3) the CHC refinement based on Finite Tree Automata (FTA) techniques (Kafle and Gallagher 2017a), which in the case where the over-approximation computed at Step (2) allows for unfeasible derivations of false (i.e., spurious counterexamples), transforms the CHCs in such a way that the new clauses avoid those unfeasible derivations (see Section 6.3 for more details). Steps (1)-(3) can be iterated until a conclusive result is reported.

Predicate Pairing
CHC specialisation is able to produce specialised versions of an existing predicate by introducing a new predicate defined in terms of a constrained atom. In some applications it is very useful to exploit the full power of fold/unfold transformations, which allow us to introduce a new predicate defined as a constrained conjunction of atoms (see Section 3). This technique is called predicate pairing (De Angelis et al. 2018a), and is an adaptation to CHC verification of fold/unfold transformation strategies previously proposed for combining two or more predicates with similar recursive definitions into a single new predicate (Burstall andDarlington 1977, Pettorossi andProietti 1994). In essence, predicate pairing is also equivalent to conjunctive partial deduction (De Schreye et al. 1999), which indeed extends partial deduction by enabling the specialisation of conjunctions of atoms.
Algorithms and implementations of predicate pairing, also enhanced with constraint propagation techniques such as the ones described in Section 6.1, have been presented in the literature (De Angelis et al. 2016, 2018a. In particular, we refer to those papers for the issue of introducing in a fully automated way the new predicate definitions needed for fold/unfold transformations. Here, we will show through examples two applications of predicate pairing for relational verification and for the verification of properties of programs that compute on Algebraic Data Types.

Relational verification
Relational program properties are properties that relate two different programs or two executions of the same program. The verification of relational program properties, also called relational verification, is useful during the process of software development, where the programmer often produces several versions of the same program, and may want to formally prove relations between old and new program versions. Relational properties that have been studied in the literature include various forms of program equivalence, relational cost analysis (in terms of computation time or any other resource consumption), non-interference for software security, and relative correctness (Barthe et al. 2011, Benton 2004, Churchill et al. 2019, Çiçek et al. 2017, Godlin and Strichman 2008, Lahiri et al. 2013, Lopes and Monteiro 2016, Zaks and Pnueli 2008. Many relational program properties can be specified by extending pre/postconditions in the style of Hoare triples to pairs of programs, rather than a single program (Barthe et al. 2011). Given two imperative programs P and Q, with disjoint tuples, say x and y, respectively, of global variables and two formulas ϕ(x, y), ψ(x, y), the relational property {ϕ(x, y)} P ∼ Q {ψ(x, y)} holds if the following holds: if the inputs of P and Q satisfy the pre-relation ϕ(x, y) and P and Q both terminate, then the outputs of P and Q satisfy the post-relation ψ(x, y).
Several papers have advocated the formalisation of relational verification problems in CHCs and the use of a CHC solver, possibly enhanced by ad hoc solving techniques (Chen et al. 2019, De Angelis et al. 2016, 2018a, Felsing et al. 2014, Mordvinov and Fedyukovich 2017, Shemer et al. 2019, Zhou et al. 2019. The relational property {ϕ(x, y)} P ∼ Q {ψ(x, y)} has the following straightforward translation into CHCs: where: (i) X1 and Y 1 are the values of x and y, respectively, before execution of P and Q, (ii) X2 and Y 2 are the values of x and y, respectively, after execution of P and Q, is the translation of ¬ψ(x, y) into a CHC predicate, (v) p(X1, X2) and q(Y 1, Y 2) are the input/output relations of programs P and Q, respectively, derived by one of the methods described in Section 4 (for instance, by specialising the interpreter of the imperative language with respect to the two programs). The order of the constraints and atoms in the body of (RelProp) is not significant from a logical point of view but, as usual, we write constraints before atoms. The relational property {ϕ(x, y)} P ∼ Q {ψ(x, y)} holds if and only if the set of CHCs consisting of (RelProp) together with the clauses for notpost, pre, p, and q, is satisfiable. Many relational properties can be defined by using constraints as pre/postconditions. For instance, program equivalence is simply translated as Non-interference, a property that guarantees information-flow security (Goguen and Meseguer 1982), is another relational property that can be easily expressed in CHCs. Let us consider a program P whose variables are partitioned into a set of public variables (or low security variables) and a set of private variables (or high security variables). We say that P satisfies the non-interference property if any two terminating executions of P , starting with the same initial values of the public variables, but possibly with different values of the private variables, compute the same values of the public variables. Thus, if a program satisfies the non-interference property, an attacker cannot acquire information about the private variables by observing the input/output relation between the public variables, which are functionally dependent on the public input variables only. The non-interference property for program P is translated into the following goal: where: (i) the predicate p(L, H, OutL) is the input/output relation of P , (ii) L and H are the tuples of values of the public and private variables, respectively, before the execution of P , and (iii) OutL is the tuple of values of the public variables upon termination of P .
Unfortunately, it is often the case that the straightforward translation of relational properties into CHCs is not sufficient to allow verification using state-of-the-art solvers. Indeed, the strategies for checking satisfiability employed by those solvers deal with the sets of clauses encoding the semantics of each of the two programs in an independent way, thereby failing to take full advantage of the interrelations between the two sets of clauses. Let us illustrate this limitation through an example.
Let us consider the two programs of Figure 5. Program Sum_upto_rec computes the sum of the first x1 positive integers and program Prod computes the product of x2 by y2 by summing up x2 times the value of y2.  We want to verify that the following relational property holds: Leq) meaning that, if x1=x2, x2 ≤ y2 holds before the execution of Sum_upto_rec and Prod, then z1 ≤ z2 holds after their execution. Property Leq cannot directly be proved using techniques based on structural similarity of programs (Barthe et al. 2011, Felsing et al. 2014, because Sum_upto_rec is a (non-tail) recursive program and Prod is an iterative program. By interpreter specialisation (see Section 4) and constraint propagation, the relational property Leq is translated into the set of CHCs over LIA shown in Figure 6.  As mentioned above, CHCs solvers using linear integer arithmetic are unable to prove the satisfiability of the set of clauses in Figure 6. This is due to the fact that those solvers look for a LIA-definable model, and no such a model exists.
An alternative approach is based on applying fold/unfold transformations according to the predicate pairing strategy (De Angelis et al. 2016, 2018a. This transformation strategy introduces new predicates defined as conjunctions of already existing predicates, and then derives (possibly recursive) clauses for the new predicates by applying the unfolding and folding rules, along with clause deletion and constraint replacement.
In our example, by predicate pairing, we introduce a new predicate fg, defined as the conjunction of f and g as follows: fg(X1,Z1,Y2,W,Z2) :-f(X1,Z1), g(X1,Y2,W,Z2). and then, by unfolding and folding, the clauses of Figure 6 are transformed into the ones shown in Figure 7.

Solving CHCs over Algebraic Data Types
Constraint solving techniques have been applied to the verification of programs manipulating recursively defined data structures, such as lists and trees and, in general, algebraic data types (ADTs). In most applications, constraint solvers (and, in particular, SMT solvers), are used as a back-end by program verifiers, such as Boogie (Barnett et al. 2006 Many constraint solvers implement techniques for checking the satisfiability of constraints on ADTs (see, for instance, https://rise4fun.com/Z3/tutorial/guide for Z3). However, when we consider CHCs over ADTs with user-defined predicates, similarly to the case of CHCs on other domains, the satisfiability problem becomes undecidable and we need to develop incomplete solving methods. While methods based on resolution work well for proving unsatisfiability (indeed, they are sound and complete for unsatisfiability, as mentioned in Section 2), they are not as effective for proving satisfiability.
One recent line of research has proposed the extension of CHC (and SMT) solving over ADTs with inductive reasoning (Reynolds and Kunčak 2015, Suter et al. 2011, Unno et al. 2017) by incorporating methods derived from the field of automated theorem proving (Bundy 2001).
An alternative approach to the extension of CHC solvers with induction is based on the application of fold/unfold transformations with the objective of removing data structures while preserving satisfiability. The transformation-based approach is related to techniques for improving the efficiency of execution of functional and logic programs, such as deforestation (Wadler 1990), unnecessary variable elimination (Proietti and Pettorossi 1995), and conjunctive partial deduction with redundant argument filtering (De Schreye et al. 1999).
Recent work has shown that methods for removing data structures are also very effective for improving CHC solvers (De Angelis et al. 2018b). The advantage of this approach is that it allows us to separate the reasoning on inductively defined data structures from the reasoning on clause satisfiability over basic types, such as booleans or integers. For instance, when dealing with CHCs over trees of integers, the transformation attempts to derive an equisatisfiable set of clauses with constraints on integers only, which can then be solved by using, for instance, the approximation-based methods of Section 5.
As an example of application of the transformation-based approach to the verification of call-by-value functional programs, we consider the following Tree -Processing program, which we write according to the OCaml syntax (Leroy et al. 2017).
Let us also consider the following property Prop, which we would like to verify for the Tree -Processing program: The direct translation into CHCs of a first-order functional program with the call-byvalue semantics is straightforward (Unno et al. 2017), although one could also follow the approach based on interpreter specialisation. We get the following set of clauses: where a predicate f(X,Y) is the translation of the relation 'f x evaluates to y'.
This set of CHCs is satisfiable iff Prop holds for Tree -Processing. However, CHC solvers without induction (e.g., Eldarica and Spacer/Z3) are not able to check satisfiability, because of the presence of variables ranging over trees.
To solve this problem, we can apply the Elimination Algorithm (De Angelis et al. 2018b), which automatically introduces two new predicates: and by applying fold/unfold transformations, derives the following equisatisfiable set of clauses without tree variables, whose constraints are in LIA only: Now, state of the art solvers for CHCs on LIA constraints are able to prove the satisfiability of these clauses. In particular, Eldarica computes the following model: In some cases, in order to remove inductively defined ADTs from CHCs, fold/unfold transformations need to be complemented by the discovery of suitable intermediate lemmas, which allow the replacement of subconjunctions occurring in the body of a clause by a new one. This is not surprising, as the need for lemma discovery has long been recognised as a key factor for the automation of inductive proofs (Bundy 2001). A recent transformation technique uses the idea that lemmas can be generated by means of the so-called difference predicates, based on the impossibility of applying the folding rule (De Angelis et al. 2020).

Other Transformation-based Techniques
In this section we summarise other satisfiability-preserving transformations of CHCs that have been developed for specific applications. Their correctness in most cases follows from the general principles of semantics-preserving transformations presented in Section 3 although the transformation algorithms are not presented in that style.

Refinement based on tree automata
Recall that an and-tree represents a top-down derivation (see Section 5.2). The success set of a set of CHCs P , SS(P ) D , can be identified with the set of successful and-trees of P . We say that t is a successful and-tree for A if t is successful and has root A, true, C . SS(P ) D = {A ← proj(constr(t), vars(A)) | t is a successful and-tree for A} Kafle and Gallagher (2017b) develop a transformation preserving the set of successful and-trees for a set of CHCs. The transformation is achieved by associating a tree automaton A P with a set P of CHCs, such that the set of trees recognised by A P , called L(A P ), is the set of and-trees (both successful and failed) for P . If a spurious counterexample is discovered while attempting to show satisfiability of P (such as in abstractionrefinement procedures, see Section 5.3), then we can construct the corresponding failed and-tree t. A tree automaton for the difference language L(A P ) \ {t} is then constructed; from this a new set P ′ of CHCs can be derived from this tree automaton. The set of feasible and-trees of P is preserved in P ′ , since only one infeasible tree was removed; thus P ′ has the same success set as P . Hence the transformation from P to P ′ is sound and complete.
That work generalised the approach of refinement by trace abstraction (Heizmann et al. 2009) from string traces to tree traces. Interpolation techniques can be applied to generalise an infeasible and-tree t to a set A t of infeasible and-trees (Wang and Jiao 2016), and the difference L(A P ) \ A t is then computed, instead of L(A P ) \ {t}. Tree-automata based refinement was applied in the RAHFT CHC verification tool (Kafle et al. 2016).

Control-flow refinement by specialisation
A useful application of constraint propagation is control-flow refinement (Doménech et al. 2019), which transforms a set of clauses by specialising with respect to internal constraints rather than constrained goals or constrained facts. The effect is to produce different specialised versions of predicates arising from different instances that are obtained in derivations, and hence control-flow refinement is a form of polyvariant specialisation (Bulyonkov 1984, Jacobs et al. 1990, Giannotti and Hermenegildo 1991, Jones et al. 1993, as discussed in Section 5.2 (see Figure 4 and Example 20). Polyvariant specialisation is often crucial in applications to program verification (Gulwani et al. 2009), allowing the inference of disjunctive invariants, which cannot be discovered, for instance, by a direct application of convex polyhedral analysis , De Angelis et al. 2014a. Control-flow refinement is especially useful for termination and complexity analysis, when it allows complex loops to be decomposed into simpler ones, thus enabling the discovery of more precise loop invariants or simpler ranking functions (Doménech et al. 2019). Polyvariant specialisation introduces the additional issue of controlling the set of specialised versions of the same predicate so as to achieve maximal precision and, at the same time, avoid the explosion in size of the transformed set of clauses (Doménech et al. 2019, Fioravanti et al. 2013, Ochoa et al. 2006.

Example 22
Let P be the following set of clauses. These clauses represent a while loop whose body contains a branch. Proof of program properties, in particular termination of the loop, is hampered by the branch which necessitates inference of a lexicographical ranking function. After control-flow refinement, we obtain the following clauses. This yields separate loops (while1 and while2), each of which has a simple ranking function (and the predicate while0 becomes a simple branch), and thus termination is easily proved for the transformed clauses.

Related CHC-based Techniques
As already mentioned in Section 4, constrained Horn clauses have recently been applied for modelling programs written in many different programming languages. Besides programs, CHCs have also been used for encoding more abstract computational models of various kinds, including Petri nets (Fribourg andOlsén 1997, Leuschel andLehmann 2000), timed automata (Jaffar et al. 2004), linear hybrid automata (Banda and Gallagher 2009), concurrent systems (Delzanno and Podelski 1999, Fioravanti et al. 2001b, 2013a, parameterized systems (Roychoudhury et al. 2000), process algebras (Fioravanti et al. 2013b) and business processes .
Constraints ease the modelling of systems whose state space is infinite, as data or time values can be represented using variables ranging over infinite domains. Usually, these systems are represented as transition systems encoded as CHCs, and it is argued that the CHCs generate the same transition system as the one defined by the source system. The predicates defining the corresponding transition relation range from a simple collection of constrained facts to more sophisticated operational semantics (in the latter case program specialisation can be used for removing intermediate data structures).
The most common application of CHCs in verification is proving (or disproving) safety properties, i.e., that 'something bad never happens' during computation. Notable examples of safety properties are partial correctness (Hoare triples), deadlock freedom (the program does not enter a state from which it cannot make progress), and mutual exclusion (no two processes, or threads, are in their critical sections at the same time). However, CHCs have also been used for modelling other kinds of properties such as liveness properties stating that 'something good will eventually happen'. Among them, there are program termination and starvation freedom.
Safety and liveness properties can be specified using temporal logics such as the µ-calculus or the Computation Tree Logic (CTL) (Clarke et al. 1999), that can be encoded using CHCs. Different methods have been developed for proving these properties based on explicit fixpoint construction (Delzanno and Podelski 2001), tabled resolution (Roychoudhury et al. 2000), and co-induction (Gupta et al. 2007).
A proof-based approach using logic programming is followed by Leuschel and Massart (2000), where verification of CTL properties is performed by combining tabulation and partial evaluation. An extension to constraint logic programming based on program specialisation of a CTL interpreter is presented by Fioravanti et al. (2001bFioravanti et al. ( , 2013a. In both cases, the extension of logic programs with negation as (finite or infinite) failure (Apt and Bol 1994) plays a central role in the proof procedures. Leuschel and Massart (2000) handle negation by using under-approximations of the answers of predicate calls as safe over-approximations of their negation, while Fioravanti et al. (2001bFioravanti et al. ( , 2013a use transformation rules that preserve the perfect model semantics of clauses with locally stratified negation. Termination properties constitute a particular class of liveness properties, but they are often treated separately and proved using specialised techniques. Termination analysis of Java bytecode programs based on constraint logic programs has been studied by Albert et al. (2008) and Spoto et al. (2010). Termination properties are also proved by applying CEGAR techniques on Horn-like clauses with existentially quantified variables in their head (Beyene et al. 2013), and by reducing the termination problem to a safety problem and using syntax-guided synthesis (Fedyukovich et al. 2018).
Automatic complexity and resource analysis is closely related to CHC verification and has been an important subject of investigation in the CLP context (Debray et al. 1990, Debray and Lin 1993, Albert et al. 2011, 2016). Some of these analyses have been developed for analysing CLP/CHC programs directly and also for analysing imperative programs, by translation to CHCs, using different representation levels as starting point, such as source, bytecode, compiler intermediate representations (e.g., LLVM-IR), or machine code. An area of particular interest in this context has been static analyses for bounding the energy consumption of programs (Navas et al. 2008, Liqat et al. 2014, 2016, López-García et al. 2015. Recently, CHCs have been used for modelling the operational semantics of time-aware business processes (De Angelis et al. 2019), whose activities have durations that are either controllable (that is, determined by the organisation that executes the process), or uncontrollable (determined by the environment). Controllability properties, which guarantee process completion independently of the values of the uncontrollable durations, are encoded using reachability formulas with existential and universal quantifiers, and are verified by combining resolution and constraint solving in LIA.
Techniques for the verification of higher-order functional programs have been developed using machine learning (Champion et al. 2020) or extending CHCs to higher-order logic (Burn et al. 2018). Other extensions of CHCs, such as existential and universal CHCs, have been studied by Bjørner et al. (2015).
Further applications of Horn clauses include verification of smart contracts and security protocols. Indeed, several approaches to verification and analysis of smart contracts for the Ethereum cryptocurrency are based on CHCs and use abstraction (Grishchenko et al. 2018, Kalra et al. 2018, Tsankov et al. 2018, possibly combined with partial evaluation (Tsankov et al. 2018, Schneidewind et al. 2020. Moreover, abstract models of secu-rity protocols are represented through Horn clauses in the automatic symbolic verifier ProVerif (Blanchet 2016), that uses resolution with free selection for verifying properties of these protocols, such as secrecy, authentication, and process equivalence.
Verification is not the only validation task that can be conveniently carried out using CHCs. It is well known that constraints can be effectively and efficiently used for software testing (Gotlieb et al. 1998, Meudec 2001, and various CHC-based techniques have been developed for test case generation (TCG) using different approaches.
White-box TCG has been performed by means of bounded symbolic execution , after applying partial evaluation to derive CHCs from object-oriented or bytecode programs . The approach has been extended to TCG for concurrent programs (Albert et al. 2018) by integrating partial-order reduction techniques for mitigating state space explosion. Concolic testing ), combining concrete and symbolic execution for TCG, has recently been applied to CLP programs (Mesnard et al. 2020).
A CLP-based approach exploiting unification and constraint solving , combined with program transformation , has been applied to Bounded-Exhaustive Testing (BET) (Coppit et al. 2005), where the task is that of generating all input data satisfying a given property, and has shown to be very competitive with respect to other approaches to BET. Some recent papers use CHCs for Property-Based Testing (PBT) (Claessen and Hughes 2000), where inputs are randomly generated so that input and output pairs satisfy some given properties. The idea of using properties defined by predicates as generators for testing arises naturally in the CLP/CHC context, since calls to predicates with free variables will instantiate (or constrain) those variables to values that will eventually cover all the success set, as shown in Section 2.4.2. In particular, the Ciao assertion framework  implements assertionbased testing: the properties that appear in assertions are defined using predicates, and then the preconditions of such assertions act as generators that are used to drive the run-time testing of those parts of assertions that are not discharged at compile time, essentially embodying the PBT approach. Recent work (Casso et al. 2019) shows how this generation process can be performed for complex properties and random values by executing the predicates defining such properties under different search rules (e.g., breadth-first, iterative deepening, random), available in the Ciao system.
Other work is aimed more specifically at PBT, such as PrologCheck (Amaral et al. 2014), which provides custom test data generators and a predicate specification language for PBT of Prolog programs. When the input consists of data structures that must satisfy complex properties, such as sorted lists or AVL trees, naive generation is not always suitable and programmers may have to write custom generators. The ProSyT tool (De Angelis et al. 2019) relieves programmers from writing such generators for PBT of Erlang programs. Inputs are automatically generated from functional specifications by interleaving (via coroutining) symbolic data structure generation, constraint solving, and random variable instantiation.

Future Directions
The idea that CHCs provide a common logical framework (or lingua franca) for program verification problems has gained traction in recent years (McMillan 2013, Bjørner et al. 2015 and has been boosted by the development of powerful satisfiability checkers for a range of constraint domains. The roots of the idea can be traced to the early years of (constraint) logic programming, and many works in the field of CLP in the past three decades have exploited the expressiveness of CHCs and their model-and proof-theoretic properties for verification problems (see the many references to the work on analysis, transformation, and verification of CLP programs surveyed in this paper). Continued progress depends on research in several areas.
Transformation of verification problems to CHCs. The translation of a verification problem from a source language into CHCs needs to be scalable to large problems in mainstream languages, and verifiable with respect to the language semantics. Most existing approaches are lacking in scalability or rigour. One area for research is to exploit existing logical frameworks and semantic specification languages, such as the rewritingbased K Framework (Rosu and Serbanuta 2010) or constructive logic proof assistants (Barras et al. 1997, Nipkow et al. 2002, which have previously been used to specify a variety of languages. An interpretive approach based on semantic rules expressed as CHCs, combined with CHC specialisation, as discussed in Section 4, is one possible strategy. Another strategy is compiler-based translation, in which a validated compiler is applied, leaving a 'simpler' intermediate language to translate into CHCs. Effective and scalable translations to and from SMT-LIB representations to CHCs can also play an important role in interfacing with existing translation tools and solvers. Translators from program verifiers based on pre/post-condition specifications (Barnett et al. 2006, Filliâtre and Paskevich 2013, Hamza et al. 2019, Leino 2013 could also be useful for generating verification conditions in CHC format that can be handled by CHC-based tools. In addition, research is needed on formalising and translating other languages and systems to which CHC verification has not previously been applied, in particular popular languages which are not strongly typed (e.g., Javascript, Python), machine learning systems, and heterogeneous distributed systems.
Advances in CHC solvers. As with verification tools in general, CHC solvers face the challenges of automation and scalability. As regards automation, some techniques, such as abstract interpretation (see Section 5), are indeed automatic. Moreover, various practical tools are based on algorithmic strategies for applying the techniques discussed in this paper and for making the so-called eureka steps (see Section 3.1). Some such strategies were presented through examples in Section 6. Scalability is addressed in two ways: firstly, large problems are tackled, whenever possible, by divide-and-conquer approaches, including, for example, modularity and incrementality (within abstract interpretation, we refer to the paper by García-Contreras et al. (2020b) and the references therein); and, secondly, abstract interpretation (as mentioned in Section 5) offers the possibility of trading off scalability for precision, less precise analyses being, in general, more scalable; hence strategies for choosing and refining abstractions are crucial. An annual competition for CHC solvers (https://chc-comp.github.io/) motivates progress and provides evidence of the increasing effectiveness of the solvers.
As impressive as recent progress is, much research is still needed on the scalability and expressiveness of CHC solvers. On the one hand, as shown in this survey, most existing techniques are for numerical constraint domains, with extensions for arrays, and ADTs for standard data structures such as lists and trees. On the other, new domains are being developed to handle strings, heaps, bit-vectors, floating point numbers and other such typical constructs that arise in program verification applications (see, for instance, (Brain et al. 2014, Brummayer and Biere 2009, Liang et al. 2016, Madhusudan et al. 2011). Furthermore, progress in solving numerical constraint problems requires techniques for effective handling of non-linear constraints, both through decision procedures for selected theories (Jovanovic and de Moura 2012), and abstract domains for safe approximation of non-linear problems (Jeannet and Miné 2009). Apart from constraint domains themselves, research and experimentation is needed on verification strategies combining analysis and transformation with refined techniques for generalisation and counterexample-based refinement. Novel verification strategies such as Newtonian iteration (Esparza et al. 2010) are also being investigated from the perspective of CHC verification .
Applications. Advances in general CHC solving techniques, as just discussed, will enable existing application areas to be addressed more effectively and at larger scale. By contrast, some applications require conceptual advances to find effective ways to express them as CHC verification problems. One such area is the automatic verification of properties of concurrent systems, which has been the subject of intensive research for many years. Approaches that simultaneously exploit the power of CHC solvers and techniques developed for model checking, such as partial order reduction (Clarke et al. 2003, Flanagan and, are needed. The approach described by Grebenshchikov et al. (2012), in which proof rules for concurrency properties (such as Owicki-Gries rules and rely-guarantee rules) are encoded as CHCs, provides a promising direction for future research. Verification of co-inductive program properties, arising in concurrency, type theory and elsewhere, can exploit the greatest fixpoint semantics of CHCs. The literature contains initial work in this area (Basold et al. 2019, Gupta et al. 2007, Seki 2012.
A new challenging field of application for CHC-based techniques is the verification of security properties of computations executing in cryptographic currency systems on top of the highly decentralised and distributed blockchain structure. Indeed, the usefulness of CHCs for specifying the formal semantics and for the static analysis of smart contracts has been advocated by recent papers (Grishchenko et al. 2018, Kalra et al. 2018, Tsankov et al. 2018, Schneidewind et al. 2020, Pérez-Carrasco et al. 2020.
Probabilistic program verification problems arise either from probabilistic programs, which include random choices, or from deterministic programs where a probability distribution is provided for inputs, and the problem is to verify the probability of reaching a specified state. This is becoming an active research topic, with applications in machine learning and real-time systems among others. CHCs can be given probabilistic interpretations Kameya 1997, Kimmig et al. 2011) which can provide the basis for probabilistic reasoning. Recent work on probabilistic Horn clause verification is described by Albarghouthi (2017); probabilistic abstract interpretations have also been considered (Monniaux 2000, Kirkeby 2019.
Automatic analysis of the resource consumption of programs is also a very important and active area, where CHC-based techniques play a very relevant role. Of particular interest are static (or combined static and dynamic) analyses for bounding the energy consumption of programs (Navas et al. 2008, Liqat et al. 2014, 2016, López-García et al. 2015 This application area is of increasing importance as, on one hand, the global energy consumption of software systems grows rapidly, and on the other hand, wearable, implantable, and portable systems need to minimize energy consumption in order to maximize battery life.