arXiv:2211.15207v2 [cs.LO] 11 Jan 2024
Multiple Query Satisfiability
of Constrained Horn Clauses ⋆
Emanuele De Angelis1[0000−0002−7319−8439] ,
Fabio Fioravanti2[0000−0002−1268−7829] ,
Alberto Pettorossi1,3[0000−0001−7858−4032] , and
Maurizio Proietti1[0000−0003−3835−4931]
1
2
IASI-CNR, Rome, Italy {emanuele.deangelis,maurizio.proietti}@iasi.cnr.it
DEc, University ‘G. d’Annunzio’, Chieti-Pescara, Italy fabio.fioravanti@unich.it
3
DICII, University of Rome ‘Tor Vergata’, Italy pettorossi@info.uniroma2.it
Abstract. We address the problem of checking the satisfiability of a set
of constrained Horn clauses (CHCs) possibly including more than one
query. We propose a transformation technique that takes as input a set
of CHCs, including a set of queries, and returns as output a new set
of CHCs, such that the transformed CHCs are satisfiable if and only if
so are the original ones, and the transformed CHCs incorporate in each
new query suitable information coming from the other ones so that the
CHC satisfiability algorithm is able to exploit the relationships among all
queries. We show that our proposed technique is effective on a non trivial
benchmark of sets of CHCs that encode many verification problems for
programs manipulating algebraic data types such as lists and trees.
1
Introduction
Constrained Horn Clauses (CHCs) have been advocated as a logical formalism
very well suited for automatic program verification [3, 6]. Indeed, many verification problems can be reduced to problems of checking satisfiability of CHCs [13],
and several effective CHC solvers are currently available as back-end tools for
program verification purposes [4, 7, 16, 18, 19].
Following the CHC-based verification approach, a program is translated into
a set of definite CHCs (that is, clauses whose head is different from false), which
capture the semantics of the program, together with a set of queries (that is,
clauses whose head is false), which specify the program properties to be verified.
Very often the CHC translation of the verification problem generates several
queries. In particular, this is the case when the program includes several functions, each one having its own contract (that is, a pair of a pre-condition and a
post-condition).
CHC solvers try to show the satisfiability of a set of CHCs of the form:
P ∪ {false ← G1 , . . . , false ← Gn }, where P is a set of definite CHCs, and
⋆
The Version of Record of this contribution will be published in the Proceedings
of PADL 2023, Boston, MA, USA, January 16–17, 2023: The 25th International
Symposium on “Practical Aspects of Declarative Languages” as a volume of the
Lecture Notes of Computer Science (LNCS) series of Springer Nature.
2
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
false ← G1 , . . . , false ← Gn are queries, by trying to show in a separate way
the satisfiability of each set P ∪ {false ← Gi }, for i = 1, . . . , n. This approach
may not be always quite effective, as the solver may not be able to exploit the,
possibly mutual, dependencies among the various queries. There is a simple way
of combining all queries into one (as done, for instance, in the CHC solver competition [10]): we introduce a new predicate f , and from the above mentioned set
of CHCs we get P ∪ {false ← f, f ← G1 , . . . , f ← Gn }. However, also in this case,
existing solvers will handle each query separately and then combine the results.
In this paper we propose, instead, a technique that, given a set P ∪{false ← G1 ,
. . . , false ← Gn } of CHCs, derives an equisatisfiable set P ′ ∪ {false ← G′1 , . . . ,
false ← G′n }, for whose satisfiability proof a CHC solver may exploit the mutual
interactions among the n satisfiability proofs, one for each query.
Our technique builds upon the transformation approach for verifying contracts that we presented in previous work and implemented in the VeriCaT
tool [8]. The algorithm of VeriCaT takes as input a set of CHCs that manipulate
algebraic data types (ADTs) such as lists and trees, and a set of CHCs defining
contracts by means of catamorphisms [20], and returns as output a set of CHCs
without ADT variables such that the original set is satisfiable if the new set is
satisfiable. For CHCs without ADT variables state-of-the-art solvers are more
effective in proving satisfiability, and hence validity of contracts.
The objective of the transformation algorithm presented in this paper, which
we call Tmq , is not to eliminate ADT variables, rather, it is to incorporate into
the clauses relative to a particular query some additional constraints that are
derived from other queries. These additional constraints are often very beneficial
to the CHC solvers when trying to check the satisfiability of a given set of clauses,
thereby enhancing their ability to verify program properties. Algorithm Tmq is
both sound and complete, that is, the transformed clauses are satisfiable if and
only if so are the original ones. The completeness of Tmq is very important
because if a property does not hold, it allows us to infer the unsatisfiability of
the original clauses. Thus, whenever the solver shows the unsatisfiability of the
transformed clauses, we deduce the invalidity of the property to be verified.
2
Preliminary Notions
We consider constrained Horn clauses that are defined in a many-sorted first
order language L with equality (=) whose constraints are expressed using linear integer arithmetic (LIA) and boolean (Bool) expressions. A constraint is a
quantifier-free formula c, where the LIA constraints may occur as subexpressions
of boolean constraints, according to the SMT approach [2]:
c ::= d | B | true | false | ∼ c | c1 & c2 | c1∨c2 | c1 ⇒ c2 | c1 = c2 |
ite(c, c1 , c2 ) | t = ite(c, t1 , t2 )
d ::= t1= t2 | t1< t2 | t1≤ t2 | t1≥ t2 | t1> t2
where: (i) B is a boolean variable, (ii) ∼, &, ∨, and ⇒ denote negation, conjunction, disjunction, and implication, respectively, (iii) the ternary function ite
denotes the if-then-else operator, and (iv) t is a LIA term of the form a0 +
Multiple Query Satisfiability of CHCs
3
a1 X1 + · · · + an Xn with integer coefficients a0 , . . . , an and variables X1 , ..., Xn .
The equality symbol will be used both for integers and booleans. We will often
write B = true (or B = false) as B (or ∼B). The theory of LIA and boolean
constraints will be denoted by LIA ∪ Bool . The integer and boolean sorts are
said to be basic sorts. A recursively defined sort (such as the sort of lists and
trees) is said to be an algebraic data type (ADT, for short).
An atom is a formula of the form p(t1 , . . . , tm ), where p is a predicate symbol
not occurring in LIA ∪ Bool, and t1 , . . . , tm are first order terms in L. A constrained Horn clause (CHC), or simply, a clause, is an implication of the form
H ← c, G. The conclusion H, called the head, is either an atom or false, and the
premise, called the body, is the conjunction of a constraint c and a conjunction G
of zero or more atoms. A clause is said to be a query if its head is false, and a
definite clause, otherwise. Without loss of generality, we assume that every atom
of the body of a clause has distinct variables (of any sort) as arguments. The set
of all variables occurring in an expression e is denoted by vars(e). By bvars(e)
(or adt -vars(e)) we denote the set of variables in e whose sort is a basic sort (or
an ADT sort). The universal closure of a formula ϕ is denoted by ∀(ϕ).
Let D be the usual interpretation for the symbols of theory LIA ∪ Bool. By
M (P ) we denote the least D-model of a set P of definite clauses [17].
Now, in order to characterize the class of queries that can be handled using our transformation technique, we introduce (see Definition 1 below) a class
of recursive schemata defined by CHCs [8]. That class is related to those of
morphisms, catamorphisms, and paramorphisms considered in functional programming [15, 20]. We will not introduce a new terminology here and we will
refer to our schemata as generalized catamorphisms, or catamorphisms, for short.
Let f be a predicate symbol with m+n arguments (for m ≥ 0 and n ≥ 0) whose
sorts are α1 ,. . ., αm , β1 , . . . , βn , respectively. We say that f is a functional predicate from α1 ×. . .×αm to β1 ×. . .×βn , with respect to a set P of definite clauses,
if M (P ) |= ∀X,Y,Z. f (X,Y ) ∧ f (X,Z) → (Y = Z), where X is an m-tuple of distinct variables, and Y and Z are n-tuples of distinct variables. Given the atom
f (X, Y ), we say that X and Y are the tuples of the input and output variables
of f , respectively. Predicate f is said to be total if M (P ) |= ∀X∃Y. f (X, Y ). In
what follows, a ‘total, functional predicate’ f from a tuple α of sorts to a tuple β
of sorts will be called a ‘total function’ and denoted by f ∈ [α → β] (the set P
of clauses that define f will be understood from the context).
Definition 1 (Generalized Catamorphisms). A generalized list catamorphism, shown in Figure 1 (A), is a total function h ∈ [σ × list (β) → ̺], where :
(i) σ, β, ̺, and τ are (products of ) basic sorts, (ii) list (β) is the sort of lists
of elements of sort β, (iii) base1 is a total function in [σ → ̺], (iv) f is a
catamorphism in [σ × list (β) → τ ] and (v) combine1 is a total function in
[σ × β × ̺ × τ → ̺]. Similarly, a generalized tree catamorphism is a total function t ∈ [σ × tree(β) → ̺] defined as shown in Figure 1 (B).
Note that the above definition is recursive, that is, the predicates f and g are
defined by instances of schemata (A) and (B), respectively. Examples of catamorphisms will be shown in the following section.
4
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
t(X, leaf , Y ) ← base2(X, Y ).
t(X, node(L, N, R), Y ) ←
g(X, L, RLg), g(X, R, RRg),
t(X, L, RL), t(X, R, RR),
combine2(X, N, RL, RR, RLg, RRg, Y ).
h(X, [ ], Y ) ← base1(X, Y ).
h(X, [H|T ], Y ) ←
f (X, T, Rf ),
h(X, T, R),
combine1(X, H, R, Rf , Y ).
(B)
(A)
Fig. 1: (A) Generalized list catamorphism. (B) Generalized tree catamorphism.
3
An Introductory Example
Let us consider the clauses of Figure 2, which are the result of translating an
iterative program for Insertion Sort. (Details on how this translation can be
performed are outside the scope of this paper.) The clauses in Figure 2 will be
called program clauses and the predicates defined by those clauses will be called
program predicates.
We have that ins--sort (Xs, Ys, Zs) holds if Zs is the ordered list of integers
(here and in what follows, the order is with respect to ≤) obtained by inserting
every element of the list Ys in the proper position of the ordered list Xs. Thus,
the result of sorting a list Ys is the list Zs such that ins--sort ([ ], Ys, Zs) holds.
The predicate ins--sort depends (see clause 2) on the predicates empty --list and
ord --ins. We have that empty --list (L) holds if the list L is empty, and
ord --ins(Y , Xs1, Xs2, Ys, Zs) holds if: (i) the concatenation of the lists Xs1 and
Xs2 is ordered, (ii) Y is greater than or equal to the last element of Xs1, and
(iii) ins--sort (Xs ′ , Ys, Zs) holds, where Xs ′ is the concatenation of Xs1 and the
ordered list obtained by inserting (according to the ≤ order) Y into Xs2. As
usual, append (Xs, Ys, Zs) holds if Zs is the concatenation of the lists Xs and
Ys, and snoc(Xs, Y , Zs) holds if append (Xs, [Y ], Zs) holds.
It is not immediate to see why the above properties for ins--sort and ord --ins
are valid. This is also due to the fact that the predicates ins--sort and ord --ins
are mutually recursive. The goal of this paper is to present a technique based on
CHC transformations that allows us to automatically prove properties expressed
by possibly mutually recursive predicates, using a CHC solver.
1. ins--sort(Xs, [ ], Xs).
2. ins--sort(Xs, [Y |Ys], S ) ←
empty--list(L),
ord --ins(Y , L, Xs, Ys, S ).
3. append ([ ], Ys, Ys).
4. append ([X |Xs], Ys, [X |Zs]) ←
append (Xs, Ys, Zs).
5. snoc([ ], X , [X ]).
6. snoc([H |T ], X , [H |TX ]) ←
snoc(T , X , TX ).
7. empty--list([ ]).
8. ord --ins(Y , Xs1, [ ], Ys, Zs) ←
snoc(Xs1, Y , Xs1Y ),
ins--sort(Xs1Y, Ys, Zs).
9. ord --ins(Y , Xs1, [X |Xs2], Ys, Zs) ←
Y ≤ X , snoc(Xs1, Y , Xs1Y ),
snoc(Xs1Y , X , Xs1YX ),
append (Xs1YX , Xs2, Xs),
ins--sort(Xs, Ys, Zs).
10. ord --ins(Y , Xs1, [X |Xs2], Ys, Zs) ←
Y > X , snoc(Xs1, X , Xs1X ),
ord --ins(Y , Xs1X , Xs2, Ys, Zs).
Fig. 2: Program clauses for Insertion Sort.
Multiple Query Satisfiability of CHCs
5
Now we will present the clauses that formalize the properties we want to show
in our Insertion Sort example. This set of clauses is made out of two subsets:
(A) a set of definite CHCs that define the catamorphisms used in the queries,
and (B) a set of queries that specify the program properties to be shown.
For (A), in Figure 3 we present the definite CHCs defining the three catamorphisms we will use. They are: (i) ordered , which takes as input a list Ls
and returns a boolean B such that if Ls is ordered, then B = true, otherwise
B = false; (ii) first , which takes as input a list Ls and returns a boolean B and
an element F such that if Ls is empty, then B = false and F = 0 (this value
for F is an arbitrary integer and will not be used elsewhere), otherwise B = true
and F is the head of Ls; and (iii) last , which is analogous to first, except that
it returns the last element L, if any, instead of the first element.
The predicates of these catamorphisms are called property predicates.
11. ordered ([ ], B ) ← B .
12. ordered ([H |T ], B ) ←
B = (B 1 ⇒ (H ≤ F & B 2)),
first(T , B 1, F ), ordered (T , B 2).
13. first([ ], B , F ) ← ∼B & F = 0.
14. first([H |T ], B , F ) ← B & F = H .
15. last([ ], B , L) ← ∼B & L = 0.
16. last([H |T ], B , L) ←
B & L = ite(B 1, L1, H ), last(T , B 1, L1).
Fig. 3: Property clauses for Insertion Sort: (A) the catamorphisms.
For (B), we present the set of queries that specify the program properties. We
assume that: (i) at most one property is specified for each program predicate, and
(ii) the property related to the program predicate p is expressed as an implication
of the form: p(. . .), cata 1 (. . .), . . . , cata n (. . .) → d, where the cata i (. . .)’s are
catamorphisms and d is a constraint. This implication can be expressed as a
query by adding ∼ d to its premise and changing its conclusion to false. For our
Insertion Sort example, in Figure 4 we specify four properties by introducing a
query for the predicates ins--sort, ord--ins, append , and snoc.
For ins--sort, query q1 states that given a list of integers Ys, if Xs is ordered
and ins--sort (Xs,Ys, Zs) holds, then Zs is ordered. For ord--ins, query q2 states
that if the concatenation of the lists Xs1 and Xs2 is ordered (that is, Xs1 and
Xs2 are ordered, and the last element of Xs1 is less than or equal to the first
element of Xs2), Y is greater than or equal to the last element of Xs1, and
ord --ins(Y , Xs1, Xs2, Ys, Zs) holds, then Zs is ordered. For append , query q3
states that if Xs1 and Xs2 are ordered, and the last element of Xs1 is less than
or equal to the first element of Xs2 and append (Xs,Ys,Zs) holds, then Zs is
ordered. For snoc, query q4 states that if Xs is ordered, and the last element of
Xs is less than or equal to X , and snoc(Xs, X , XsX ) holds, then XsX is ordered.
At this point, we can check whether or not the properties expressed by the
queries q1–q4 do hold by checking the satisfiability of the program clauses together with the property clauses. In order to perform that satisfiability check, we
have used the state-of-the-art CHC solver SPACER, based on Z3 [18]. SPACER
failed to return an answer within five minutes. The weakness of CHC solvers for
examples like the one presented here, motivates our technique based on CHC
transformation. This technique produces an equisatisfiable set of CHCs whose
6
(q1)
(q2)
(q3)
(q4)
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
false ← ∼ (B 1 ⇒ B 2), ordered (Xs, B 1), ordered (Zs, B 2), ins--sort(Xs, Ys, Zs).
false ← ∼ ((B 1 & B 2 & ((B 4 & B 5) ⇒ L ≤ F ) & (B 4 ⇒ L ≤ Y )) ⇒ B 3),
ordered (Xs1, B 1), ordered (Xs2, B 2), ordered (Zs, B 3),
last(Xs1, B 4, L), first(Xs2, B 5, F ), ord --ins(Y , Xs1, Xs2, Ys, Zs).
false ← ∼ ((B 1 & B 2 & ((B 4 & B 5) ⇒ L ≤ F )) ⇒ B 3),
ordered (Xs, B 1), ordered (Ys, B 2), ordered (Zs, B 3),
last(Xs, B 4, L), first(Ys, B 5, F ), append (Xs, Ys, Zs).
false ← ∼ ((B1 & (B2 ⇒ L ≤ X)) ⇒ B3),
ordered (Xs, B 1), last(Xs, B 2, L), ordered (XsX , B 3), snoc(Xs, X , XsX ).
Fig. 4: Property clauses for Insertion Sort: (B) the queries.
satisfiability can be, hopefully, easier to verify. Indeed, in our example, SPACER
succeeds to prove the satisfiability of the new set of CHCs produced by our transformation algorithm. In Section 7, we will show that our technique improves the
effectiveness of state-of-the-art solvers on a non-trivial benchmark.
4
Catamorphism-based Queries
As already mentioned, the translation of a program verification problem to CHCs
usually generates two disjoint sets of clauses: (i) the set of program clauses, and
(ii) the set of property clauses, with the associated sets of program predicates,
and property predicates. Without loss of generality, we will assume that property
predicates may occur in the property clauses only. Moreover, in order to define
a class of CHCs where our transformation technique always terminates, we will
consider property predicates that are catamorphisms (see Definition 1). In the
sequel we need the following definitions. An atom is said to be a program atom
(or a catamorphism atom), if its predicate symbol is a program predicate (or a
catamorphism, respectively). Recall that when writing a catamorphism atom as
cata(X, T, Y ), we stipulate that X is the (tuple of its) input basic variable(s), T
is the input ADT variable, and Y is the (tuple of its) output basic variable(s).
Definition 2. A catamorphism-based query is a query of the form :
false ← c, cata 1 (X1 , T1 , Y1 ), . . . , cata n (Xn , Tn , Yn ), pred (Z)
where: (i) pred is a program predicate and Z is a tuple of distinct variables,
(ii) c is a constraint such that vars(c) ⊆ {X1 , . . . , Xn , Y1 , . . . , Yn , Z}, (iii) cata 1 ,
. . . , cata n are catamorphism atoms, (iv) Y1 , . . . , Yn are pairwise disjoint tuples
of distinct variables of basic sort not occurring in X1 , . . . , Xn , Z, (v) T1 , . . . , Tn
are ADT variables occurring in Z.
The queries of Figure 4 are examples of catamorphism-based queries. Many
interesting program properties can be defined as catamorphism-based queries,
although, in general, this might require some ingenuity.
5
Transformation Rules
In this section we present the rules that we use for transforming CHCs. These
rules are variants of the usual transformation rules for CHCs (and CLP pro-
Multiple Query Satisfiability of CHCs
7
grams), specialized to our context where we use catamorphisms. Then, we prove
the soundness and completeness of those rules.
The goal of the transformation rules is to incorporate catamorphisms into
program predicates, that is, to derive for each program predicate p, a new predicate newp whose definition is given by the conjunction of an atom for p with the
catamorphism atoms needed for showing the satisfiability of the query relative
to p. In this section we will indicate how this can be done referring our Insertion Sort example, while in the next section we will present a transformation
algorithm to perform this task in an automatic way.
A transformation sequence from S0 to Sn is a sequence S0 Z⇒ S1 Z⇒ . . . Z⇒ Sn
of sets of CHCs such that, for i = 0, . . . , n−1, Si+1 is derived from Si , denoted
Si Z⇒ Si+1 , by performing a transformation step consisting in applying one of
the following rules R1–R4.
(R1) Definition Rule. Let D be a clause of the form newp(X1 , . . . , Xk ) ←
c, Catas, A, where: (1) newp is a predicate symbol not occurring in the sequence
S0 Z⇒ S1 Z⇒ . . . Z⇒ Si constructed so far, (2) {X1 , . . . , Xk } = vars({Catas, A}),
(3) c is a constraint such that vars(c) ⊆ vars({Catas, A}), (4) Catas is a conjunction of catamorphism atoms, with adt-vars(Catas) ⊆ adt-vars(A), and (5) A
is a program atom. By definition introduction we may add D to Si and get
Si+1 = Si ∪ {D}.
The case where A is absent is accommodated by considering A to be true(X),
which holds for every X of ADT sort.
For j = 0, . . . , n, by Defs j we denote the set of clauses, called definitions,
introduced by rule R1 during the construction of the sequence S0 Z⇒ S1 Z⇒
. . . Z⇒ Sj . Thus, Defs 0 = ∅, and for j = 0, . . . , n, Defs j ⊆ Defs j+1 .
In our Insertion Sort example, the set S0 consists of all the clauses shown in
Figures 2, 3, and 4, and we start off by introducing the following definition (with
constraint true), whose body consists of the atoms in the body of query q1:
D1. new 1(Xs,B 1,Zs,B 2,Ys) ← ordered (Xs,B 1), ordered (Zs,B 2), ins--sort (Xs,Ys,Zs).
Thus, S1 = S0 ∪ {D1}.
The clauses for newp are obtained by first (i) unfolding the definition of
newp, then (ii) incorporating some catamorphisms and constraints provided by
the queries into the clauses derived by unfolding, and (iii) finally, folding using
suitable new definitions. Now, we introduce an unfolding rule (see R2 below),
which actually is the composition of the unfolding and the application of the
functionality property presented in previous work [8]. Let us first define the
notion of the one-step unfolding which is a step of symbolic evaluation performed
by applying once the resolution rule.
Definition 3 (One-step Unfolding). Let C: H ← c, L, A, R be a clause, where
A is an atom, and let P be a set of definite clauses with vars(C) ∩ vars(P ) = ∅.
Let Cls: {K1 ← c1 , B1 , . . . , Km ← cm , Bm }, with m ≥ 0, be the set of clauses
in P , such that: for j = 1, . . . , m, (i) there exists a most general unifier ϑj of
A and Kj , and (ii) the conjunction of constraints (c, cj )ϑj is satisfiable. The
one-step unfolding produces the following set of CHCs :
8
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
Unf (C, A, P ) = {(H ← c, cj , L, Bj , R)ϑj | j = 1, . . . , m}.
In the following Rule R2 and in the sequel, Catas denotes a conjunction of
catamorphism atoms.
(R2) Unfolding Rule. Let D: newp(U ) ← c, Catas, A be a definition in Si ∩ Defsi
and P be the set of definite clauses in Si . We derive a new set UnfCls of clauses
by the following three steps.
Step 1. (One-step unfolding of the program atom) UnfCls := Unf (D, A, P );
Step 2. (Unfolding of the catamorphism atoms)
while there exists a clause E: H ← d, L, C, R in UnfCls, for some conjunctions L and R of atoms, such that C is a catamorphism atom whose
argument of ADT sort is not a variable do
UnfCls := (UnfCls \ {E}) ∪ Unf (E , C , P );
Step 3. (Applying Functionality)
while there exists a clause E: H ← d, L, cata(X, T, Y 1), cata(X, T, Y 2), R
in UnfCls, for some catamorphism cata do
UnfCls := (UnfCls − {E}) ∪ {H ← d, Y 1 = Y 2, L, cata(X, T, Y 1), R};
Then, by unfolding D we derive Si+1 = (Si \ {D}) ∪ UnfCls.
For instance, in our Insertion Sort example, by unfolding definition D1, at Step 1
we replace D1 by:
E1. new 1(A, B, A, C, [ ]) ← ordered (A, B), ordered (A, C).
E2. new 1(A, B, C, D, [E|F ]) ← ordered (A, B), ordered (C, D),
empty--list(G), ord--ins(E, G, A, F, C).
Step 2 of the unfolding rule is not performed in this example. At Step 3, clause
E1 is replaced by:
E3. new 1(A, B, A, C, [ ]) ← B = C, ordered (A, B).
Thus, S2 = S0 ∪ {E2, E3}.
The query-based strengthening rule allows us to use the queries occurring
in the set of CHCs whose satisfiability is under verification for strengthening
the body of the other clauses with the addition of catamorphism atoms and
constraints.
(R3) Query-based Strengthening Rule. Let Si = P ∪Q, where P is a set of definite
clauses obtained by applying the unfolding rule, and Q is a set of catamorphismbased queries, and let C: H ← c, CatasC, A1 , . . . , Am be a clause in P , being
the Ai ’s program atoms. Let E be the clause derived from C as follows:
for k = 1, . . . , m do
- consider program atom Ak ; let Catas C
k be the conjunction of every catamorphism atom F in CatasC such that adt -vars(Ak ) ∩ adt -vars(F ) 6= ∅;
- if in Q there exists a query (modulo variable renaming)
qk : false ← ck , cata 1 (X1 , T1 , Y1 ), . . . , cata n (Xn , Tn , Yn ), Ak
where Y1 , . . . , Yn do not occur in C, and the conjunction cata 1 (X1 , T1 , Y1 ), . . . ,
cata n (Xn , Tn , Yn ) can be split into two subconjunctions B1 and B2 such
that: (i) a variant of B1 is a subconjunction of Catas C
k , and (ii) for every
catamorphism atom cata i (Xi , Ti , Yi ) in B2 there is no catamorphism atom
cata i (V, Ti , W ) in Catas C
k
then add the conjunction ∼ ck , B2 to the body of C.
Multiple Query Satisfiability of CHCs
9
Then, by query-based strengthening of clause C using queries q1 , . . . , qm (some
of these queries may be absent), we get the new set Si+1 = (Si \ {C}) ∪ {E}.
For instance, from clause E2 by query-based strengthening using q2 (note that
in E2 the program atom empty--list has no associated query), we get:
E4. new1(A, B, C, D, [E|F ]) ←
L & B & ((J &H ) ⇒ K ≤ I ) & (J ⇒ K ≤ E ) ⇒ D ,
ordered (A, B), ordered (C, D),
(B1 )
ordered (G, L), last (G, J, K), first (A, H, I),
(B2 )
empty--list(G), ord--ins(E, G, A, F, C).
where the subconjunction B1 mentioned in Rule R3 is in line (B1 ), while the
subconjunction B2 is in line (B2 ). Thus, S3 = S0 ∪ {E3, E4}.
The folding rule allows us to replace a conjunction of a program atom and
catamorphisms by a single atom, whose predicate has been introduced in a previous application of the Definition Rule.
(R4) Folding Rule. Let C: H ← c, CatasC , A1 , . . . , Am be a clause in Si , where
either H is false or C has been obtained by the unfolding rule, possibly followed
by query-based strengthening. For k = 1, . . . , m,
C
- let Catas C
k be the conjunction of every catamorphism atom F in Catas such
that adt -vars(Ak ) ∩ adt -vars(F ) 6= ∅;
- let Dk : Hk ← dk , Catas D
k , Ak be a clause in Defs i (modulo variable renaming)
D
such that: (i) D |= ∀(c → dk ), and (ii) Catas C
k is a subconjunction of Catas k .
Then, by folding C using D1 , . . . , Dm , we derive clause E: H ← c, H1 , . . . , Hm ,
and we get Si+1 = (Si \ {C}) ∪ {E}.
In order to fold clause E4, we introduce two new definitions, one for each
program atom occurring in the body of that clause, as follows (the predicate
names are introduced by our tool):
D2. new 2(A, B, C, D, E, F, G, H, I, J, K, L) ← ordered (A, B), ordered (C, D),
ordered (E, F ), last (A, G, H), first(C, I, J), ord--ins(K, A, C, L, E).
D3. new 19(A, B, C, D) ← ordered (A, B), last (A, C, D), empty--list(A).
Thus, S4 = S0 ∪ {E3, E4, D2, D3}.
Now, we apply Rule R4, and from clause E4 we get:
E5. new 1(A,B,C,D,[E|F ]) ← G & B & ((H &I) ⇒ J ≤ K) & (H ⇒ J ≤ E) ⇒ D,
new 2(L, G, A, B, C, D, H, J, I, K, E, F ), new 19(L, G, H, J).
Then, S5 = S0 ∪ {E3, E5, D2, D3}. Also, query q1 can be folded using definition D1, and we get:
E6. false ← ∼ (B 1 ⇒ B 2), new 1(Xs, B 1, Zs, B 2, Ys).
Thus, S6 = (S0 \ {q1})∪{E3, E5, E6, D2, D3}. Then, the transformation will
continue by looking for the clauses relative to the newly introduced predicates
new 2 (see Definition D2) and new 19 (see Definition D3).
The key for understanding our transformation technique is to observe that in
our Insertion Sort example, the query E6 and the clauses E3 and E5 that define
the new predicate new 1, incorporate the program predicate ins--sort together
with the catamorphisms that are used in q1. The advantage of performing this
transformation is that the solver can look for a model of new 1(Xs,B 1,Zs,B 2,Ys)
10
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
where the constraint B1 ⇒B2 holds, instead of looking in a separate way for
models of ordered (Xs,B1), ordered (Zs,B2), and ins--sort (Xs,Ys,Zs) whose conjunction implies B1 ⇒ B2. Note also that clause E5 has constraints and catamorphisms that come from query-based strengthening. Indeed, E5 is obtained
by folding E4 derived by strengthening E2 using query q2.
The following Theorem 1, whose proof sketch is given in Appendix 1, states
the correctness of the transformation rules.
Theorem 1 (Soundness and Completeness of the Rules). Let S0 Z⇒ S1 Z⇒
. . . Z⇒ Sn be a transformation sequence using rules R1–R4. Then, S0 is satisfiable
if and only if Sn is satisfiable.
Note that the applicability conditions of R3 disallow the application of the
rule to a query. Otherwise, we could easily get a satisfiable clause from an unsatisfiable one. Indeed, we could transform false ← c(Y ), cata(X, Y ), p(X) into
false ← ∼ c(Y ) & c(Y ), cata(X, Y ), p(X). Note also that folding a clause using
itself is not allowed, thus avoiding the transformation of H ← c, Catas, A into
the trivially satisfiable clause H ← c, H.
The applicability conditions of the rules force a sequence of the transformation rules which is fixed, if the new definitions to be introduced are known. The
algorithm that we will present in the next section shows how these definitions
can be introduced in an automatic way.
6
Transformation Algorithm
In this section we present an algorithm, called Tmq , which given a set P of
definite clauses and a set Q of queries, introduces a set of new predicates and
transforms P ∪ Q into a new set P ′ ∪ Q′ such that: (i) P ∪ Q is satisfiable
if and only if P ′ ∪ Q′ is so, and (ii) each new predicate defined in P ′ ∪ Q′ is
equivalent to the conjunction of a program predicate and some catamorphisms
needed for checking the satisfiability of the queries in Q. As an effect of the
application of the query-based strengthening rule, the transformed clauses also
exploit the interdependencies among the queries in Q. This transformation is
effective, in particular, in the presence of mutually recursive predicates, like in
our Insertion Sort example, where we are able to get new clauses for checking the
satisfiability of the query q1 for ins--sort that take into account the constraints
and catamorphisms of the query q2 for ord--ins, and vice versa.
The set of new definitions needed by Tmq is computed as the least fixpoint
of an operator τP,Q that transforms a set ∆ of definitions into a new set ∆′ . For
introducing that operator, we need some preliminary definitions and functions.
Definition 4. A generalization of a pair (c1 , c2 ) of constraints is a constraint,
denoted α(c1 , c2 ), such that D |= ∀(c1 → α(c1 , c2 )) and D |= ∀(c2 → α(c1 , c2 )) [11].
The projection of a constraint c onto a tuple V of variables is a constraint π(c, V )
such that: (i) vars(π(c, V )) ⊆ V and (ii) D |= ∀(c → π(c, V )).
A set ∆ of definitions is monovariant if it contains at most one definition for
each program predicate.
Multiple Query Satisfiability of CHCs
11
Definition 5. Let D1 : newp1(U1 ) ← c1 , Catas 1 , p(Z) and D2 : newp2(U2 ) ←
c2 , Catas 2 , p(Z) be two definitions for the same predicate p. We say that D2 is an
extension of D1 , written D1 ⊑ D2 , if (i) Catas 1 is a subconjunction of Catas 2 ,
and (ii) D |= ∀(c1 → c2 ). Let ∆1 and ∆2 be two monovariant sets of definitions.
We say that ∆2 is an extension of ∆1 , written ∆1 ⊑ ∆2 , if for each D1 in ∆1
there exists D2 in ∆2 such that D1 ⊑ D2 .
Given a set Cls of clauses and a set ∆ of definitions, the Define function (see
Figure 5) derives a set ∆′ of definitions that can be used for folding all clauses
in Cls. If ∆ is monovariant, then also ∆′ is monovariant. In particular, due to
the (Project) case, ∆′ contains a definition for each program predicate occurring
in the body of clauses in Cls. Due to the (Extend) case, ∆ ⊑ ∆′ .
Function Define(Cls, ∆): a set Cls of clauses; a monovariant set ∆ of definitions.
Define(Cls, ∆) returns a monovariant set ∆′ of new definitions computed as follows.
∆′ := ∆;
for each clause C: H ← c, G in Cls do
for each program atom A in G do
let CatasA be the conjunction of every catamorphism atom F in G such that
adt-vars(A) ∩ adt-vars(F ) 6= ∅
• (Skip) if in ∆′ there is a clause newp(U ) ← d, B, A, for any conjunction B
of catamorphism atoms, such that: (i) CatasA is a subconjunction of B, and
(ii) D |= ∀(c → d), then skip;
• (Extend) else if the definition for the predicate of A in ∆′ is the clause
D: newp(U ) ← d, B, A, where B is a conjunction of catamorphism atoms, and
either (i) CatasA is not a subconjunction of B, or (ii) D 6|= ∀(c → d), then
introduce definition ExtD : extp(V ) ← α(d, c), A, B ′ , where: (i) extp is a new
predicate symbol, (ii) V = vars({α(d, c), B ′ , A}), and B ′ is the conjunction of
the distinct catamorphism atoms occurring either in B or in CatasA ;
∆′ := (∆′ \ {D}) ∪ {ExtD };
• (Project) else if there is no clause in ∆′ of the form K ← d, B, A, for any
conjunction B of catamorphism atoms,
then introduce definition D: newp(U ) ← π(c, I), A, CatasA , where: (i) newp
is a new predicate symbol, (ii) I are the input variables of basic sort in
{A, CatasA }, and (iii) U = vars({π(c, I), A, CatasA });
∆′ := ∆′ ∪ {D};
Function Unfold(∆,
S P ): a set ∆ = {D1 ,. . ., Dn } of definitions; a set P of definite clauses.
Unfold(∆, P ) = n
i=1 Ci , where Ci is the set of clauses derived by unfolding Di .
Function Strengthen (Cls, Q): a set Cls = {C1 , . . . , Cn } of clauses; a set Q of catamorphism-based queries, at most one query for each program predicate in Cls.
Strengthen (Cls, Q) = {Ei | Ei is derived from Ci by query-based strengthening using Q}
Function Fold(Cls, ∆): a set Cls = {C1 , . . . , Cn } of clauses; a monovariant set ∆ of
definitions.
Fold (Cls, ∆) = {Ei | Ei is derived from Ci by folding Ci using definitions in ∆}.
Fig. 5: The Define, Unfold , Strengthen, and Fold functions.
12
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
The Unfold and Strengthen functions (see Figure 5) apply the unfolding and
query-based strengthening rules, respectively, to sets of clauses.
Now, we define the operator τP,Q as follows:
(
Define(Q, ∅)
if ∆ = ∅
τP,Q (∆) =
Define(Strengthen(Unfold (∆, P ), Q), ∆)
otherwise
In the case where ∆ is the empty set of definitions, τP,Q (∆) introduces by the
Define function (Project case), a new definition for each program predicate occurring in a query in Q. In the case where ∆ is not empty, τP,Q (∆) is an extension
of ∆ obtained by first unfolding all clauses in ∆, then applying the query-based
strengthening rule to the clauses derived by unfolding, and finally applying the
Define function.
The Define function is parametric with respect to the generalization operator α (see the Extend case). In our implementation we use an operator based on
widening [11] that ensures stabilization, that is, for any infinite sequence c0 , c1 , . . .
of constraints and any sequence defined as (i) d0 = c0 , and (ii) dk+1 = α(dk , ck+1 ),
there exists m ≥ 0 such that dm = dm+1 . The Strengthen function ensures that
there is a bound on the number of catamorphisms that can be present in a definition. Since, as already mentioned, τP,Q is monotonic with respect to ⊑, its
n
least fixpoint lfp(τP,Q ) is equal to τP,Q
(∅), for some finite number n of iterations
of τP,Q . Note that, by construction, lfp(τP,Q ) is monovariant.
Once we have computed the set lfp(τP,Q ) of definitions, we can use them
to fold all clauses derived by unfolding and strengthening by applying the Fold
function (see Figure 5). Thus, the transformation algorithm is defined as follows:
Tmq (P, Q) = Fold Strengthen Unfold (lfp(τP,Q ), P ), Q , lfp(τP,Q )
Termination of Tmq follows immediately from the fact that lfp(τP,Q ) is computed
in a finite number of steps.
Theorem 2 (Termination of Algorithm Tmq ). Let P be a set of definite
clauses and Q a set of catamorphism-based queries. Then, Algorithm Tmq terminates for P and Q.
By the soundness and completeness of the transformation rules (see Theorem 1), we also get the following result.
Theorem 3 (Soundness and Completeness of Algorithm Tmq ). For any
set P of definite clauses and Q of catamorphism-based queries, P ∪Q is satisfiable
if and only if Tmq (P, Q) is satisfiable.
We conclude this section by showing the sequence of definitions for the program predicate snoc computed by iterating the applications of τP,Q in the Insertion Sort example. The definitions in lfp(τP,Q ) are listed in Appendix 2.
new 4(A, B, C, D, E, F, G) ← ordered (A, B), last(A, C, D), ordered (E, F ),
snoc(A, G, E).
new 5(A, B, C, D, E, F, G, H, I, J, K) ← ordered (E, J), last(E, F, G),
ordered (A, D), first (E, H, I), first (A, B, C), snoc(E, K, A).
new 13(A, B, C, D, E, F, G, H, I, J, K, L, M ) ← ordered (A, B), last (A, C, D),
ordered (E, F ), last (E, G, H), first (E, J, K), first (A, L, M ), snoc(A, I, E).
Note that these three definitions are in the ⊑ relation.
Multiple Query Satisfiability of CHCs
7
13
Experimental Evaluation
We have implemented algorithm Tmq in a tool, called VeriCaTmq , which extends
VeriCaT [8] by guaranteeing a sound and complete transformation. VeriCaTmq is
based on (i) VeriMAP [7] for transforming CHCs, and (ii) SPACER (with Z3
4.11.2) to check the satisfiability of the transformed CHCs.
We have considered 170 problems, as sets of CHCs, with 470 queries in total,
equally divided between the class of satisfiable (sat) problems and unsatisfiable
(unsat) ones (85 problems and 235 queries for each class). These problems are
related to programs that manipulate: (i) lists of integers by performing concatenation, permutation, reversal and sorting, and (ii) binary search trees, by
inserting and deleting elements. For list manipulating programs, we have considered properties such as: list length, minimum and maximum element, sum
of elements, list content as sets or multisets of elements, and list sortedness (in
ascending or descending order). For trees, we have considered size, height, minimum and maximum element, tree content and the binary search tree property.
The problems considered here are derived from those of the benchmark set
of previous work [8] with some important differences. We have considered additional satisfiable problems (for instance, those related to Heapsort). In addition
to satisfiable problems, we have also considered unsatisfiable problems that have
been obtained from their satisfiable counterparts by introducing bugs in the
programs: for instance, by not inserting an element in a list, or adding an extra constraint, or replacing a non-empty tree by an empty one. Note also that
the transformed CHCs produced by Tmq contain both basic variables and ADT
variables, whereas those produced by the method presented in previous work [8]
contain basic variables only.
For comparing the effectiveness of our method with that of a state-of-the-art
CHC solver, we have also run SPACER (with Z3 4.11.2) on the original, nontransformed CHCs, in SMT-LIB format. In Table 1 we summarize the results
of our experiments4. The first three columns report the name of the program,
the total number of problems and queries for each program. The fourth and
fifth columns report the number of satisfiable and unsatisfiable problems proved
by SPACER before transformation, whereas the last two columns report the
number of satisfiable and unsatisfiable problems proved by VeriCaTmq .
In summary, VeriCaTmq was able to prove all the 170 considered problems
whereas SPACER was able to prove the properties of 84 ‘unsat’ problems out
of 85, and none of the ‘sat’ problems. The total time needed for transforming
the CHCs was 275 seconds (1.62 s per problem, on average), and checking the
satisfiability of the transformed CHCs took about 174 s in total (about 1s average
time, 0.10 s median time). For comparison, SPACER took 30.27 s for checking
the unsatisfiability of 84 problems (0.36 s average time, 0.15 s median time). The
benchmark and the tool are available at https://fmlab.unich.it/vericatmq.
4
Experiments have been performed on an Intel Xeon CPU E5-2640 2.00GHz with
64GB RAM under CentOS with a time limit of 300s per problem.
14
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
Program
List Membership
List Permutation
List Concatenation
Reverse
Double Reverse
Reverse w/Accumulator
Bubblesort
Heapsort
Insertionsort
Mergesort
Quicksort (version 1)
Quicksort (version 2)
Selectionsort
Treesort
Binary Search Tree
Total
Problems Queries
2
8
18
20
4
6
12
8
12
18
12
12
14
4
20
170
6
24
18
40
12
18
36
48
24
84
38
36
42
20
24
470
SPACER
sat unsat
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
4
8
10
2
3
6
4
6
9
6
6
7
2
10
84
VeriCaTmq
sat unsat
1
4
9
10
2
3
6
4
6
9
6
6
7
2
10
85
1
4
9
10
2
3
6
4
6
9
6
6
7
2
10
85
Table 1: Programs and problems proved by SPACER and VeriCaTmq .
For instance, for all the considered list sorting programs (Bubblesort, Heapsort, Insertionsort, Mergesort, Quicksort, Selectionsort and Treesort), VeriCaTmq
was able to prove properties stating that the output list is sorted and has the
same multiset of elements of the input list. Similarly, VeriCaTmq was able to
prove that those properties do not hold, if extra elements are added to the output list, or some elements are not copied from the input list to the output list,
or a wrong comparison operator is used.
The results obtained by the VeriCaTmq prototype implementation of our
method are encouraging and show that, when used in combination with stateof-the-art CHC solvers, it can greatly improve their effectiveness to prove satisfiability of sets of CHCs with multiple queries, while it does not inhibit their
remarkable ability to prove unsatisfiability, although some extra time due to
transformation may be required.
8
Conclusions and Related Work
Many program verification problems can be translated into the satisfiability
problem for sets of CHCs that include more than one query. A notable example is
the case where we want to verify the correctness of programs made out of several
functions, each of which has its pre-/postconditions [13]. We have proposed an
algorithm, called Tmq , for transforming a set of CHCs with multiple queries into
a new, equisatisfiable set of CHCs that incorporate suitable information about
the set of queries contained in the initial set. The advantage gained is that, in
order to prove the satisfiability of the transformed CHCs, the CHC solver may
exploit the mutual interactions among the satisfiability proofs of the various
queries. We have identified a class of queries that specify program properties
using catamorphisms on ADTs, such as lists and trees, for which Tmq terminates.
Multiple Query Satisfiability of CHCs
15
We have implemented algorithm Tmq and shown that it improves the effectiveness
of the state-of-the-art CHC solver SPACER [18] on a non trivial benchmark.
Algorithm Tmq improves over the transformation algorithm Tcata presented
in a previous paper [8], which works by eliminating ADTs from sets of CHCs.
Instead of the contracts handled by Tcata , algorithm Tmq considers queries, and
thus its input is simply a set of CHCs. More importantly, Tmq is sound and complete, in the sense that the initial and transformed CHCs are equisatisfiable sets,
whereas Tcata is only sound (that is, it can be seen as computing an abstraction
of the initial clauses), and thus if the transformed clauses are unsatisfiable we
cannot infer anything about the satisfiability of the initial CHCs. Completeness
is very important in practice, because proving that a set of clauses is unsatisfiable
and finding a counterexample can help identify a program bug. The experimental
evaluation reported in Section 7 shows that our transformation-based verification technique is able to dramatically improve the effectiveness of the SPACER
solver for satisfiable sets of CHCs (where the results of SPACER are very poor),
while retaining the excellent results of the solver for unsatisfiable sets of CHCs
(for which SPACER is, at least in principle, complete).
Decision procedures for suitable classes of first order formulas defined on
catamorphisms [21, 22] have been used in program verifiers [23]. However, we do
not propose here any specific decision procedure for catamorphisms and, instead,
we transform a set of CHCs with catamorphisms into a new set of CHCs where
catamorphisms are, in a sense, compiled away.
Type-based norms, which are a special kind of integer-valued catamorphisms,
were used for proving termination of logic programs [5] and for resource analysis [1] via abstract interpretation. Similar abstract interpretation techniques are
also implemented in the CiaoPP preprocessor [14] of the Ciao logic programming system. In our approach we do not need to specify a priory any abstract
domain where to perform the analysis, and instead, by transformation, we generate new CHCs which incorporate the relations defined by the constraints on the
catamorphisms. The problem of showing the satisfiability of CHCs defined on
ADTs is a very hot topic and various approaches have been proposed in recent
work, including: (i) a proof system that combines inductive theorem proving
with CHC solving [25], (ii) lemma generation based on syntax-guided synthesis
from user-specified templates [26], (iii) invariant discovery based on finite tree
automata [19], and (iv) use of suitable abstractions [12].
A limitation of our approach is that the effectiveness of the transformation
may depend on the set of properties specified through the queries. For instance,
it may happen that programmers provide partial program specifications (e.g., for
a subset of the program functions), and therefore queries only for some program
predicates, such as the main program predicates (e.g., ins--sort and ord --ins of
our example). In this case, it is essential to have a mechanism that is able to
infer from the queries the unspecified catamorphisms for the remaining program
predicates (e.g., append and snoc which ins--sort and ord --ins depend on). As
future work, we plan to extend Tmq to propagate the catamorphisms specified in
the queries to those program predicates for which no query has been specified.
16
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
References
1. E. Albert, S. Genaim, R. Gutiérrez, and E. Martin-Martin. A transformational
approach to resource analysis with typed-norms inference. Theory Pract. Log.
Program., 20(3):310–357, 2020.
2. C. W. Barrett, R. Sebastiani, S. A. Seshia, and C. Tinelli. Satisfiability modulo theories. In Handbook of Satisfiability, volume 185 of Frontiers in Artificial
Intelligence and Applications, pages 825–885. IOS Press, 2009.
3. N. Bjørner, A. Gurfinkel, K. L. McMillan, and A. Rybalchenko. Horn clause solvers
for program verification. In Fields of Logic and Computation (II), Lecture Notes
in Computer Science 9300, pages 24–51. Springer, 2015.
4. M. Blicha, G. Fedyukovich, A. E. J. Hyvärinen, and N. Sharygina. Transition
power abstractions for deep counterexample detection. In Tools and Algorithms
for the Construction and Analysis of Systems, TACAS ’22, Part I, Lecture Notes
in Computer Science 13243, pages 524–542. Springer, 2022.
5. M. Bruynooghe, M. Codish, J. P. Gallagher, S. Genaim, and W. Vanhoof. Termination analysis of logic programs through combination of type-based norms. ACM
Transactions on Programming Languages and Systems, 29(2):10–es, 2007.
6. E. De Angelis, F. Fioravanti, J. P. Gallagher, M. V. Hermenegildo, A. Pettorossi,
and M. Proietti. Analysis and transformation of constrained Horn clauses for
program verification. Theory and Practice of Logic Programming, 22(6):974–1042,
2022.
7. E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti. VeriMAP: A tool
for verifying programs through transformations. In Tools and Algorithms for the
Construction and Analysis of Systems, TACAS ’14, Lecture Notes in Computer
Science 8413, pages 568–574. Springer, 2014.
8. E. De Angelis, M. Proietti, F. Fioravanti, and A. Pettorossi. Verifying catamorphism-based contracts using constrained Horn clauses. Theory and Practice
of Logic Programming, 22(4):555–572, 2022.
9. S. Etalle and M. Gabbrielli. Transformations of CLP modules. Theoretical Computer Science, 166:101–146, 1996.
10. G. Fedyukovich and P. Rümmer. Competition report: CHC-COMP-21. In 8th
Workshop on Horn Clauses for Verification and Synthesis, volume 344 of EPTCS,
pages 91–108. Open Publishing Association, 2021.
11. F. Fioravanti, A. Pettorossi, M. Proietti, and V. Senni. Generalization strategies
for the verification of infinite state systems. Theory and Practice of Logic Programming, 13(2):175–199, 2013.
12. H. Govind V. K., S. Shoham, and A. Gurfinkel. Solving constrained Horn clauses
modulo algebraic data types and recursive functions. Proceedings of the ACM on
Programming Languages, POPL ’22, 6:1–29, 2022.
13. S. Grebenshchikov, N. P. Lopes, C. Popeea, and A. Rybalchenko. Synthesizing
software verifiers from proof rules. In Conference on Programming Language Design
and Implementation, PLDI ’12, pages 405–416, 2012.
14. M. V. Hermenegildo, G. Puebla, F. Bueno, and P. López-García. Integrated program debugging, verification, and optimization using abstract interpretation (and
the Ciao system preprocessor). Science of Computer Programming, 58(1–2):115–
140, 2005.
15. R. Hinze, N. Wu, and J. Gibbons. Unifying structured recursion schemes. In
International Conference on Functional Programming, ICFP ’13, pages 209–220.
ACM, 2013.
Multiple Query Satisfiability of CHCs
17
16. H. Hojjat and P. Rümmer. The ELDARICA Horn solver. In Formal Methods in
Computer Aided Design, FMCAD ’18, pages 1–7. IEEE, 2018.
17. J. Jaffar and M. Maher. Constraint logic programming: A survey. Journal of Logic
Programming, 19/20:503–581, 1994.
18. A. Komuravelli, A. Gurfinkel, and S. Chaki. SMT-based model checking for recursive programs. Formal Methods in System Design, 48(3):175–205, 2016.
19. Y. Kostyukov, D. Mordvinov, and G. Fedyukovich. Beyond the elementary representations of program invariants over algebraic data types. In Conference on
Programming Language Design and Implementation, PLDI ’21, pages 451–465.
ACM, 2021.
20. E. Meijer, M. M. Fokkinga, and R. Paterson. Functional programming with bananas, lenses, envelopes and barbed wire. In 5th ACM Conference Functional
Programming Languages and Computer Architecture, Lecture Notes in Computer
Science 523, pages 124–144. Springer, 1991.
21. T. Pham, A. Gacek, and M. W. Whalen. Reasoning about algebraic data types
with abstractions. Journal of Automated Reasoning, 57(4):281–318, 2016.
22. P. Suter, M. Dotta, and V. Kuncak. Decision procedures for algebraic data
types with abstractions. In Symposium on Principles of Programming Languages,
POPL ’10, pages 199–210. ACM, 2010.
23. P. Suter, A. S. Köksal, and V. Kuncak. Satisfiability modulo recursive programs.
In Symposium on Static Analysis, SAS ’11, Lecture Notes in Computer Science
6887, pages 298–315. Springer, 2011.
24. H. Tamaki and T. Sato. A generalized correctness proof of the unfold/fold logic
program transformation. Technical Report 86-4, Ibaraki University, Japan, 1986.
25. H. Unno, S. Torii, and H. Sakamoto. Automating induction for solving Horn
clauses. In Computer Aided Verification, CAV ’17, Part II, Lecture Notes in Computer Science 10427, pages 571–591. Springer, 2017.
26. W. Yang, G. Fedyukovich, and A. Gupta. Lemma synthesis for automating induction over algebraic data types. In International Conference on Principles and
Practice of Constraint Programming, CP 2019, Lecture Notes in Computer Science
11802, pages 600–617. Springer, 2019.
18
E. De Angelis, F. Fioravanti, A. Pettorossi, and M. Proietti
Appendix 1
In this appendix we present a proof sketch of Theorem 1 that states the soundness
and completeness of the transformation rules.
Proof sketch. The proof of Theorem 1 is based on the correctness of the transformation rules for (constraint) logic programs [9, 24]. In particular, the addition of
catamorphisms performed by the query-based strengthening rule, is sound and
complete because the catamorphisms are total, functional relations. The correctness of folding is proved by using a method similar to the one introduced by
Tamaki and Sato [24], which relies on two facts: (i) we can associate predicates
with levels where program predicates have a higher level than catamorphisms,
and (ii) only clauses obtained by unfolding with respect to a program atom are
folded.
Appendix 2
In this appendix let us first show the seven definitions that have been introduced
during the transformation of the given set of CHCs presented in Figures 2, 3,
and 4. Note that in our case, the constraints in these definitions are all true.
D1. new 1(A, B, C, D, E) ← ordered (A, B), ordered (C, D), ins--sort(A, E, C).
D2. new 2(A, B, C, D, E, F, G, H, I, J, K, L) ← ordered (A, B), ordered (C, D),
ordered (E, F ), last (A, G, H), first(C, I, J), ord--ins(K, A, C, L, E).
new 6(A, B, C, D) ← ordered (A, B), first(A, C, D).
new 7(A, B, C, D, E, F, G, H, I, J, K, L, M, N ) ← first (A, B, C),
ordered (A, D), last (E, F, G), first(H, I, J), ordered (H, K),
first(E, L, M ), ordered (E, N ), append (E, A, H).
new 13(A, B, C, D, E, F, G, H, I, J, K, L, M ) ← ordered (A, B),
last (A, C, D), ordered (E, F ), last (E, G, H), first(E, J, K),
first(A, L, M ), snoc(A, I, E).
new 17(A, B) ← ordered (A, B).
D3. new 19(A, B, C, D) ← ordered (A, B), last (A, C, D), empty--list(A).
Now we list the final set of CHCs which has been derived by our transformation technique using the above definitions. The first four CHCs are the queries
derived from the queries q1–q4 of Figure 4 denoting the four properties for Insertion Sort we wanted to prove. We have that this final set of clauses is sastisfiable
and thus, the four properties are all valid.
E6. false ← ∼ (A ⇒ B), new 1(C, A, D, B, E).
false ← ∼ ((A & B & ((C & D) ⇒ E ≤ F ) & (C ⇒ E ≤ G)) ⇒ H),
new 2(I, A, J, B, K, H, C, E, D, F, G, L).
false ← ∼ (A & B & ((C & D) ⇒ E ≤ F ) ⇒ G),
new 7(H, D, F, B, I, C, E, J, K, L, G, M, N, A).
false ← ∼ ((A & (B ⇒ C ≤ D)) ⇒ E), new 13(F,A,B,C,G,E,H,I,D,J,K,L,M ).
new 1(A, B, A, B, [ ]) ← new 17(A, B).
E5. new 1(A, B, C, D, [E|F ]) ← (G&B & ((H &I) ⇒ J ≤ K) & (H ⇒ J ≤ E)) ⇒ D,
new 2(L, G, A, B, C, D, H, J, I, K, E, F ), new 19(L, G, H, J).
Multiple Query Satisfiability of CHCs
19
new 2(A, B, [ ], C, D, E, F, G, H, I, J, K) ← C & ∼ H & I = 0 &
((B & (F ⇒ G ≤ J)) ⇒ L) & (L ⇒ E), new 1(M, L, D, E, K),
new 13(A, B, F, G, M, L, N, O, J, P, Q, R, S).
new 2(A, B, [C|D], E, F, G, H, I, J, K, L, M ) ← (L ≤ C) &
(E = (N ⇒ (C ≤ O & P ))) & J & K = C & ((B & (H ⇒ I ≤ L)) ⇒ Q) &
((Q & (R ⇒ S ≤ C)) ⇒ T ) & ((T & P & ((U & N ) ⇒ V ≤ O)) ⇒ W ) &
(W ⇒ G), new 1(X, W, F, G, M ),
new 7(D, N, O, P, Y, U, V, X, Z, A1, W, B1, C1, T ),
new 13(D1, Q, R, S, Y, T, U, V, C, E1, F 1, G1, H1),
new 13(A, B, H, I, D1, Q, R, S, L, I1, J1, K1, L1).
new 2(A, B, [C|D], E, F, G, H, I, J, K, L, M ) ← (L ≥ C +1) &
(E = (N ⇒ (C ≤ O & P ))) & J & K = C & ((B & (H ⇒ I ≤ C)) ⇒ Q) &
((Q & P & (((R & N ) ⇒ S ≤ O) & (R ⇒ S ≤ L))) ⇒ G),
new 2(T, Q, D, P, F, G, R, S, N, O, L, M ),
new 13(A, B, H, I, T, Q, R, S, C, U, V, W, X).
new 6([ ], A, B, C) ← A & ∼ B & C = 0.
new 6([A|B],C,D,E) ← C = (F ⇒ (A ≤ G & H)) & D & E = A, new 6(B,H,F,G).
new 7(A,B,C,D,[ ],E,F,A,B,C,D,G,H,I) ← ∼ E & F = 0 & ∼ G & H = 0 & I,
new6(A, D, B, C).
new 7(A,B,C,D,[E|F ],G,H,[E|I],J,K,L,M,N,O) ← G & H = ite(P, Q, E) &
J & K = E & L = (R ⇒ (E ≤ S & T )) & M & N = E &
O = (U ⇒ (E ≤ V & W )) & ((W & D & ((P & B) ⇒ Q ≤ C)) ⇒ T ),
new7(A, B, C, D, F, P, Q, I, R, S, T, U, V, W ).
new 13([ ], A, B, C, [D], E, F, G, D, H, I, J, K) ← A & ∼ B & C = 0 &
E = (L ⇒ (D ≤ M & N )) & F & G = ite(O, P, D) & H & I = D &
∼ J & K = 0 & N & ∼ L & M = 0 & ∼ O & P = 0.
new 13([A|B],C,D,E,[A|F ],G,H,I,J,K,L,M,N ) ← C = (O ⇒ (A ≤ P & Q)) &
D & E = ite(R, S, A) & G = (T ⇒ (A ≤ U & V )) & H & I = ite(W, X, A) &
K & L = A & M & N = A & ((Q & (R ⇒ S ≤ J)) ⇒ V ),
new13(B, Q, R, S, F, V, W, X, J, T, U, O, P ).
new 17([ ], A) ← A.
new 17([A|B], C) ← C = (D ⇒ (A ≤ E & F )), new 6(B, F, D, E).
new 19([ ], A, B, C) ← A & ∼ B & C = 0.