=Paper= {{Paper |id=Vol-2970/gdeinvited1 |storemode=property |title=Solving B Constraints with Goal-directed Answer Set Programming |pdfUrl=https://ceur-ws.org/Vol-2970/gdeinvited1.pdf |volume=Vol-2970 |authors=Alexandros Efremidis |dblpUrl=https://dblp.org/rec/conf/iclp/Efremidis21 }} ==Solving B Constraints with Goal-directed Answer Set Programming== https://ceur-ws.org/Vol-2970/gdeinvited1.pdf
       Solving B Constraints with Goal-directed
               Answer Set Programming

                                 Alexandros Efremidis

             Institut für Informatik, Heinrich-Heine-Universität Düsseldorf
                    Universitätsstraße 1, 40225 Düsseldorf, Germany
                                     alefr101@hhu.de



        Abstract. In this paper I explore a further option for solving B con-
        straints. In particular, I develop a framework translating B predicates to
        s(CASP), a goal-directed form of Answer Set Programming. Furthermore,
        the presented framework implements an interface enabling B predicates to
        be solved by the s(CASP) engine within the ProB tool as an additional
        backend. This paper particularly focuses on the translation process and
        on empirically evaluating the framework’s performance by comparing
        it to the native, Kodkod and Z3 backend of ProB. This work poses a
        foundation for future development regarding the translation of B predi-
        cates to goal-directed Answer Set Programming and s(CASP) specifically.
        Further, this framework can be used to aid the verification of other solvers’
        correctness.


1     Introduction and Motivation
This work’s fundamental motivation is to develop zero-defect software with the
help of formal methods. For instance, this is achievable by specifying a system’s
desired behavior with B abstract machines [1] to then be validated by a software
verification tool such as ProB [7, 8]. ProB is an automated analysis toolkit for
the B-method enabling for animation, model checking and constraint solving,
which allows for unveiling possible errors of the underlying specification. In
order to model check a machine and verify its correctness, predicates are usually
evaluated along the way. Therefore, constraint solvers such as the native ProB,
Kodkod [13] and Z3 [5] backend are employed to support the overall verification
process. As they all come with their respective strengths and weaknesses [6,11,12]
it seems natural to explore further options.
    In this paper I aim towards extending the existing base of constraint solvers
for the B-Method, used in the ProB tool, by providing an additional constraint
solving backend. In particular, this work implements a Prolog framework translat-
ing B predicates to Answer Set Programming [9] to then be solved by s(CASP) [2]
within ProB. Furthermore, this paper focuses on the translation process and
on empirically evaluating the framework’s performance by comparing it to the
aforementioned backends of ProB.
    Copyright c 2021 for this paper by its authors. Use permitted under Creative
    Commons License Attribution 4.0 International (CC BY 4.0).
2       A. Efremidis

2   Answer Set Programming and s(CASP)
Answer Set Programming (ASP) is a form of declarative logic programming,
which is primarily oriented towards NP-hard search problems [9]. Due to its
declarative nature ASP poses an attractive alternative to already well-established
constraint solving oriented methodologies and is a paradigm of growing interest
in the recent years. An ASP program P is a finite set of clauses, where each rule
r ∈ P is of the form


                   h ← t1 ∧ · · · ∧ tm ∧ not tm+1 ∧ · · · ∧ not tn              (1)

    with the head h and the body’s literals t1 , . . . , tn being compound terms.
The keyword not expresses default negation. Generally, ASP is concerned with
finding stable models also referred to as answer sets for the underlying problem.
In typical ASP applications an initial grounding phase is introduced in order to
be able to search for answer sets. The grounding phase succeeds only if every
clause of P is safe. A rule is considered as safe in case every variable in its body
occurs in some positive literal thereby specifying the variable’s finite domain. A
rule is deemed unsafe otherwise. However, for this work an ASP implementation
is chosen, which is free of grounding.
    s(CASP) [2] is a novel Answer Set Programming implementation coalescing
stable model semantics and Constraint Logic Programming (CLP). It is build
upon the s(ASP) [10] execution model, an ASP interpreter written in Prolog.
s(CASP) inherits and generalizes s(ASP) while remaining parametric with respect
to CLP. In particular, s(CASP) is a query-driven implementation of Answer Set
Programming. Unlike common ASP systems, s(CASP) does not employ any SAT
based methodology and is not relying on a grounding phase either prior or during
execution. Hence, s(CASP) allows for declaring variables without specifying
their respective domains, whereas classical ASP approaches would consider the
program as unsafe. s(CASP) deploys a top-down, query-driven procedure virtually
an extended version of SLDNF resolution for evaluating programs under the
ASP semantics. By virtue of s(CASP) being goal-directed the engine computes a
partial stable model, which is the portion required for answering the underlying
query.


3   A Constraint Solving Framework
This framework consists of a translator and an interface. The translator obtains
an abstract syntax tree (AST) representing a B predicate emitted by ProB and
generates semantically equivalent s(CASP) code. It is written in SICStus Prolog [4]
to ensure compatibility and is constructed as a loadable extension package of
ProB. The interface establishes the connection between the translator and the
s(CASP) engine. s(CASP) is written in Ciao Prolog [3], hence an interface links
the two Prolog implementations together enabling for solving a B predicate by
s(CASP) within ProB.
         Solving B Constraints with Goal-directed Answer Set Programming         3

   The overall workflow is illustrated in Figure 1. An AST is expected as input
by the framework, hence ProB parses the predicate prior to the translation.
This initial process is depicted as a black box in the flowchart. Thereafter, the
translator generates a s(CASP) file containing executable code. The translator
gradually walks over the AST and computes for each encountered B node a
semantically equivalent s(CASP) component. Through this process a s(CASP)
program is recursively build. When the generation of the translation is completed,
the interface calls the s(CASP) engine and obtains the result. Lastly, some
post-processing is applied and the result is returned back to ProB.




                   Fig. 1: The framework’s general workflow.



4   Translating B Predicates to s(CASP)

In this section I give an overview of the translation process. The following
designations are used for B code throughout this translation. Designations P, Q
denote predicates; E, F denote expressions; x, y denote single variables; z denotes
a list of variables; S, D denote set expressions; U denotes a set of sets and m,
n denote integer expressions. Furthermore, for any B code A, TA denotes the
translation of A in s(CASP). For the sake of simplicity the designations of B
identifiers are also used for their s(CASP) representatives. For a B expression E
the variable VE is unified with the evaluation of TE . Lastly, Tmp denotes a fresh
internal temporary variable.
    The vast majority of B predicates is covered. However, a few restrictions are
introduced as this framework is still under development. Predicates such as set
summation, set product, iteration, closure, projection, lambda abstraction and
the support of sequences are not incorporated. Furthermore, infinite domains of
the form a ∈ N or b ∈ Z are not considered. Lastly, in pure logic the order of P
and Q is irrelevant for the semantics of a conjunction. However, conjunctions are
4      A. Efremidis

currently straightforwardly translated. Therefore, the case that a ground value is
needed for evaluating TP , which remains unbound until TQ is evaluated, is gener-
ally not supported. Nevertheless, s(CASP)’s CLP library allows for supporting
arithmetical expressions.

Primitive expressions: Identifiers, booleans, integers and strings are straight-
forwardly translated.
Conjunction: P & Q is translated to TP , TQ .
Disjunction: P or Q introduces a goal subconst(x1 ,...,xk ) with x1 ,...,xk
being the variables occurring in P and Q. For both predicates a new rule is added
to the code with the aforementioned goal as its head and with TP , TQ as its body
respectively. Hence, the new goal establishes a choice point, effectively creating a
disjunction.
Negation: Let x1 ,...,xk be the variables occurring in P. not P introduces the
goal not subconst(x1 ,...,xk ) with the rule of the form
subconst(x1 ,...,xk ) :- TP .
Implication: P => Q is resolved as not P or Q.
Equivalence: P <=> Q is resolved as P => Q & Q => P.
Existential quantification: By virtue of s(CASP) operating query-driven,
#(z).(P & Q) can be resolved as P & Q.
Equality, inequality and comparison operators: This translation applies
to the operators =, 6=, <, >, ≤, ≥. Without loss of generality, equality is selected
to describe how the aforementioned operators are translated. As E = F may
contain nested expressions or function calls the translator analyzes the AST to
gather information about E and F. The translator operates with a look-ahead of
one and introduces an internal temporary variable Ve if necessary. Depending on
E and F the framework distinguishes between the following cases.

 1. If E and F are primitive: TE = TF .
 2. If E is primitive and F is not: TF , TE = VF .
 3. If E is non-primitive and F is primitive: TE , VE = TF .
 4. If E and F are both non-primitive: TE , TF , VE = VF .

Furthermore, the operators 6=, <, >, ≤, ≥ are translated to \=, #<, #>, #=<,
#>= respectively. Thus, in case of arithmetical expressions s(CASP)’s CLP backend
takes care of the aforementioned temporal challenges related to conjunctions.
Empty set: Sets are represented by lists, hence {} is translated to [].
Singelton set: Similar to equality, for a singleton set of the form {E} the
translator analyzes E to decide whether the expression is primitive. Consequently,
the translator produces Tmp = [TE ] if E is primitive and TE , Tmp = [VE ] vice
versa. Via unification the framework takes care to link the freshly introduced
temporary variable to the identifier or expression it is meant to be assigned to.
Set enumeration: A set of arbitrary cardinality of the form {E, F, ...} follows
the pattern of the singleton set, which is expressed by recursive application.
Ordered pair: The framework distinguishes between four cases for an ordered
pair E |-> F.
         Solving B Constraints with Goal-directed Answer Set Programming                   5

 1. If E and F are primitive: Tmp = t(TE , TF ).
 2. If E is primitive and F is not: TF , Tmp = t(TE , VF ).
 3. If E is non-primitive and F is primitive: TE , Tmp = t(VE , TF ).
 4. If E and F are both non-primitive: TE , TF , Tmp = t(VE , VF ).

Set comprehension: Let x1 ,...,xi be all variables occurring in P and let z =
z1 ,...,zj be the list of variables constrained by P. Let y1 ,...,yk with i = j+k
denote external variables that occur in P but not in z. The set comprehension
{z|P} is the set of every value of z that satisfies P and is translated to the
goal subconst1(Tmp, y1 ,...,yk ). Figure 2 shows the two introduced rules.
subconst1/k+1 creates a local scope, where the variables of z are unable to clash
with the variables of the parent scope. s(CASP)’s built-in predicate findall/3
is used to store in Tmp every instance of Ψ satisfying the condition TP . Ψ is an
ordered pair of the form t(z1 , t(z2 , t(..., zj ))) or scalar if |z| = 1.



                 s u b c o n s t 1 (Tmp, y1 ,...,yk ) :−
                   f i n d a l l ( Ψ , s u b c o n s t 2 ( x1 ,...,xi ) , Tmp ) .
                 s u b c o n s t 2 ( x1 ,...,xi ) :− TP .


     Fig. 2: The two introduced rules for the set comprehension predicate.




Universal quantification: Let z = z1 ,...,zk be the list of variables con-
strained by P. Further, let p1 ,...,pi and q1 ,...,qj be the external variables
that occur in P and Q respectively but do not occur in z. The predicate !(z).(P
=> Q) is translated to subconst1(p1 ,...,pi , q1 ,...,qj ). As this framework
is restricted to finite domain declarations, it allows for using set comprehensions
to express that Q is satisfied for each value of z satisfying P. Figure 3 depicts
the three freshly introduced rules, where Ψ ’s definition is the same as for set
comprehensions.



            s u b c o n s t 1 ( p1 ,...,pi , q1 ,...,qj ) :−
              f i n d a l l ( Ψ , s u b c o n s t 2 ( p1 ,...,pi , z1 ,...,zk ) , Tmp) ,
              f o r a l l (Tmp, q1 ,...,qj ) .
            s u b c o n s t 2 ( p1 ,...,pi , z1 ,...,zk ) :− TP .
            f o r a l l ( [ ] , q1 ,...,qj ) .
            f o r a l l ( [ Ψ |Tmp] , q1 ,...,qj ) :−
              TQ ,
              f o r a l l (Tmp, q1 ,...,qj ) .


 Fig. 3: The three introduced rules for the universal quantification predicate.
6         A. Efremidis



Arithmetical evaluation: This translation applies to the arithmetical operators
+, −, ∗, /, mod . Without loss of generality, addition is selected to describe how the
aforementioned operators are translated. s(CASP)’s CLP library is used in order
to omit temporal restraints of conjunctions. The predicate #=/2, which subsumes
and extends is/2, is used instead. The framework distinguishes between four
cases for m + n.
 1. If m and n are primitive: Tmp #= Tm + Tn .
 2. If m is primitive and n is not: Tn , Tmp #= Tm + Vn .
 3. If m is non-primitive and n is primitive: Tm , Tmp #= Vm + Tn .
 4. If m and n are both non-primitive: Tm , Tn , Tmp #= Vm + Vn .


Union: S \/ D is translated to TS , TD , union(VS , VD , Tmp). Except for the
predicates genreal union and general intersection all other predicates are trans-
lated in the same way as union, i.e. intersection, difference, cartesian product,
powerset, cardinality, (not) member, (not) (strict) subset, minimum, maximum,
interval, relations, domain, range, composition, identity, domain/range restric-
tion/subtraction, inverse, relational image, override, direct/parallel product,
partial/total functions/injections/surjections, bijections and function application.
For predicates of arity two, merely the translation of one of the arguments is
omitted. The corresponding predicates are provided in an external file1 .
General union & general intersection: Essentially, the translator stacks suc-
cessively as many union/3 calls as necessary to compute the generalized union
of the form union(U). The code for a general intersection inter(U) is generated
analogously. The framework distinguishes between three cases.
 1. If U = {S}, then resolve S as a singleton set.
 2. If U = {S, D}, then treat it as S \/ D.
 3. If n ≥ 3, then resolve S1 , S2 ∈ U as S1 \/ S2 obtaining Tmp1 and continue
    resolving Tmpi and the next set Si+2 with i < n-1 as TSi+2 , union(Tmpi ,
    VSi+2 , Tmpi+1 ) until the final result Tmpn-1 is computed.


5      Empirical Evaluation
In this section I aim towards empirically evaluating the presented framework’s
capabilities by comparing benchmark performances of the new backend to the
native ProB, Kodkod and Z3 backend. Regarding the translation’s correctness
test cases are embedded in ProB consisting of numerous exemplary expressions,
which cover the supported predicates. For each test the s(CASP) backend first
solves the underlying predicate obtaining a result, which is afterwards validated
by ProB. Of course, this does not prove the backend’s correctness.
    In Figure 4 the runtime performances for the supported B predicates are
presented. The result for a benchmark is obtained by solving and measuring the
 1
     https://github.com/Alexandros31/B-to-sCASP/blob/main/preliminaries.pl
          Solving B Constraints with Goal-directed Answer Set Programming      7

runtime of three separate synthetic B expressions on each backend (if available)
via the ProB REPL. Additionally, the runtime of the plain s(CASP) engine
is measured to gain more insight into s(CASP)’s performance by omitting the
surrounding overhead introduced by the framework’s processes. Each computation
is executed three times with a one minute threshold on a freshly initialized
REPL to counter inaccuracies in the measurements. The environment of this
evaluation is a macOS 10.14.6 machine operating on a 7th generation i5 Intel
processor at 3.1GHz. The displayed value representing a predicate’s performance
in milliseconds is obtained by averaging over the results of all three exemplary
expressions, where every individual value is rounded half away from zero. The
designation n.a. indicates that either a timeout or an “unsupported predicate
exception” occurred. The benchmarks along with all performance measures for
each run can be found on GitHub2 .


 Predicate          Native ProB    Kodkod Z3       s(CASP)     Plain s(CASP)
 Comprehension      78             39     84       263         16
 Univ. Quantifier 96               40     84       257         2
 Union              67             53     71       310         47
 Intersection       70             52     69       323         38
 Difference         72             54     72       319         42
 Cart. Product      76             40     137      293         5
 Powerset           74             n.a.   126      1820        88
 Cardinality        50             n.a.   59       241         1
 Gen. Union         55             42     75       302         52
 Gen. Intersection 56              50     71       311         61
 Relations          94             n.a.   n.a.     698         39
 Domain/Range       55             31     66       260         15
 Composition        55             30     68       245         1
 Identity           67             n.a.   81       249         0
 Restrict/Subtract 54              30     67       256         14
 Inverse            54             41     73       244         0
 Relational Image 56               42     72       245         4
 Override           51             n.a.   84       352         113
 Direct Product     54             n.a.   70       249         6
 Parallel Product 55               n.a.   106      280         12
 Partial Functions 76              n.a.   n.a.     885*        333*
 Total Functions 75                n.a.   n.a.     414*        161*
 Partial Injections 83             n.a.   n.a.     537*        311*
 Total Injections 77               n.a.   n.a.     1639*       1354*
 Part. Surjections 77              n.a.   n.a.     379*        142*
 Total Surjections 78              n.a.   n.a.     496*        256*
 Bijections         76             n.a.   n.a.     2402*       2246*
 Fun. Application 54               n.a.   77       241         0

     Fig. 4: Comparison of predicate performances measured in milliseconds.
2
    https://github.com/Alexandros31/B-to-sCASP/blob/main/eval.md
8       A. Efremidis

    The performance measurements of Figure 4 indicate that the native ProB,
Kodkod and Z3 backend perform better compared to the s(CASP) backend, as
their runtimes are generally faster. However, s(CASP) is able to obtain a result
in some cases where Kodkod and Z3 are unable to follow. Furthermore, the plain
s(CASP) engine’s performances seem to be reasonable, as the corresponding
runtimes are noticeably low in many cases. This suggests that the framework’s
overhead is considerably prevalent. On my machine I recorded an average startup
time of 130 milliseconds for the Ciao engine. Compared to the best performing
predicates the time of initialization renders roughly half of the entire process.
However, these benchmarks are rather small compared to real-world examples.
Hence, the time loss of the Ciao engine’s initialization is more apparent.
    In the following I express my thoughts on the gathered results. Note that
these performances are heavily dependent on the efficiency of the custom predi-
cates that are used for this translation, for instance member/2 or union/3. The
predicates set comprehension, universal quantifier, cartesian product, cardinality,
domain/range, composition, identity, domain/range restriction/subtraction, in-
verse, relational image, direct product, parallel product and function application
share the fastest runtimes among this evaluation as they succeed in under 300
milliseconds. Cartesian product, cardinality, composition, identity, inverse, rela-
tional image, direct product, parallel product and function application merely
iterate over a list without any demanding additional task along the way, which
presumably leads to consuming less time. The predicates domain/range and
domain/range restriction/subtraction make use of member/2 and set comprehen-
sion and universal quantification use s(CASP)’s built-in findall/3 predicate. I
assume that these specific benchmarks are not particularly challenging as further
analysis suggests that the usage of member/2 and findall/3 leads to weaker
performances.
    Since s(CASP) lacks the cut operator, additional rules containing the goal
not member/2 are needed to correctly express some predicate’s behavior such
as union/3 in this implementation. Consequently, in the instance of an element
not being a member of the underlying list the rule invoking the negated goal is
called nevertheless. This may induce further loss of time, especially for large lists.
The other predicates, which mainly rely on member/2 are union, intersection,
difference, general union, general intersection and override. These predicates
perform solidly relative to the aforementioned better performing ones.
    The remaining predicates, i.e. powerset, relations, partial functions, total func-
tions, partial injections, total injections, partial surjections, total surjections and
bijections all invoke findall/3. These results show that the usage of findall/3
poses a considerable bottleneck for this framework’s performance. The asterisk
indicates that the benchmark’s largest expression is not succeeding for the given
threshold of one minute. For these particular benchmarks only the remaining
two expressions are used including ProB. Considering the lacking efficiency
the framework offers a run option called “optimize”, which lets ProB evaluate
ground expressions before passing them to the framework.
         Solving B Constraints with Goal-directed Answer Set Programming        9

    Predicate   Native ProB     Kodkod Z3        s(CASP)     Plain s(CASP)
    4-Queens    115             36     282       369         31
    5-Queens    112             36     285       438         37
    6-Queens    117             37     1081      4927        3101
    7-Queens    107             39     1262      30507       5190

    Fig. 5: Comparison of n-queens performances measured in milliseconds.


     Figure 5 shows the performances of various ProB backends dealing with
different sizes of the n-queens problem. Since this implementation seems to
struggle with the computation of functions, these measurements are supported
by ProB with the “optimize” feature enabled.
     Overall, the s(CASP) backend’s performance is not on par with the other ones.
In particular, the s(CASP) backend is outclassed by the native ProB, Kodkod
and Z3 backend in every single benchmark. Nevertheless, in some cases s(CASP)
succeeds while Kodkod and Z3 are unable to solve the given constraint. Yet, even
in those instances the native ProB backend poses a superior option. However,
one needs to consider that this framework hardly incorporates any optimizations,
i.e. predicates are straightforwardly translated in most cases.


6    Future Work and Conclusion
Even though the presented framework is capable of translating a large portion
of the B realm to s(CASP), there are some predicates left to be supported.
Predicates such as iteration, closure, projection, lambda abstraction and the
support of sequences should be included. Also enabling one to assign variables to
infinite domains is imperative to be able to express more complex constraints. As
s(CASP) offers a CLP backend and shares similarities with Prolog, this probably
could be done similarly to how ProB handles those instances. Furthermore,
it is desirable to extend this framework so that the order of predicates in a
conjunction is irrelevant. This could be done by analyzing the underlying AST
within the framework, and thus generate appropriate code that is solely reliant
on already evaluated predicates. Moreover, this work’s evaluation indicates that
improving the framework as a whole to reduce its surrounding overhead may
lead to better performances. Reimplementing parts of the custom predicates that
utilize findall/3 in a more efficient way should also lead to a more promising
backend in general.
    In conclusion, this work poses a foundation for translating B constraints to
s(CASP). The empirical results indicate that the implemented backend is not
quite on par with the other ones. However, I assume that this backend could be
rendered more beneficial with further development. Furthermore, the presented
backend can be used for verification of other employed solvers. Similar to how the
s(CASP) backend is tested by ProB, ProB’s and other solver’s answers could
thus be verified by s(CASP). Especially, for predicates that are solely supported
by the native backend, the s(CASP) backend can be applied.
10      A. Efremidis

References
 1. Abrial, J.R.: The B-Book: Assigning Programs to Meanings. Cambridge University
    Press, New York, NY, USA (1996)
 2. Arias, J., Carro, M., Salazar, E., Marple, K., Gupta, G.: Constraint answer set
    programming without grounding. Theory and Practice of Logic Programming
    18(3-4), 337–354 (2018)
 3. Bueno, F., Cabeza, D., Carro, M., Hermenegildo, M., López-Garcıa, P., Puebla,
    G.: The Ciao prolog system. Reference Manual. The Ciao System Documentation
    Series–TR CLIP3/97.1, School of Computer Science, Technical University of Madrid
    (UPM) 95, 96 (1997)
 4. Carlsson, M., Widen, J., Andersson, J., Andersson, S., Boortz, K., Nilsson, H.,
    Sjöland, T.: SICStus Prolog User’s Manual, vol. 3. Swedish Institute of Computer
    Science, Kista, Sweden (1988)
 5. De Moura, L., Bjørner, N.: Z3: An efficient SMT solver. In: International conference
    on Tools and Algorithms for the Construction and Analysis of Systems. pp. 337–340.
    Springer (2008)
 6. Krings, S., Leuschel, M.: SMT solvers for validation of B and Event-B models. In:
    International Conference on Integrated Formal Methods. pp. 361–375. Springer
    (2016)
 7. Leuschel, M., Butler, M.: ProB: A model checker for B. In: FME 2003: Formal
    Methods. vol. 2805, pp. 855–874. Springer, Berlin, Heidelberg (Sep 2003)
 8. Leuschel, M., Butler, M.: ProB: An automated analysis toolset for the B method.
    International Journal on Software Tools for Technology Transfer 10(2), 185–203
    (Mar 2008)
 9. Lifschitz, V.: Answer set programming. Springer Berlin (2019)
10. Marple, K., Salazar, E., Chen, Z., Gupta, G.: The s(ASP) predicate answer set
    programming system. The Association for Logic Programming Newsletter (2017)
11. Plagge, D., Leuschel, M.: Validating B, Z and TLA+ using ProB and Kodkod. In:
    International Symposium on Formal Methods. pp. 372–386. Springer (2012)
12. Schmidt, J., Leuschel, M.: Improving SMT solver integrations for the validation
    of B and Event-B models. In: International Conference on Formal Methods for
    Industrial Critical Systems. pp. 107–125. Springer (2021)
13. Torlak, E., Jackson, D.: Kodkod: A relational model finder. In: International
    Conference on Tools and Algorithms for the Construction and Analysis of Systems.
    pp. 632–647. Springer (2007)