**Definition 4. (Debugging Scenario of Missing Answers)** *For any given CFLP*(D)*-program* P*:*


Some concrete debugging scenarios have been discussed in Section 2. Assume now that an incompleteness symptom has been observed by the programmer. Since the goal solving system has computed the disjunction of answers *D* = *<sup>i</sup>*∈*<sup>I</sup> Si*, the *aca G* ⇒ *<sup>D</sup>* asserting that the computed answers cover all the solutions of *G* should be derivable from P−. The *Constraint Negative Proof Calculus CNPC*(D) consisting of the inference rules displayed in Fig. 5 has been designed with the aim of enabling logical proofs P<sup>−</sup> �*CNPC*(D) *<sup>G</sup>* ⇒ *<sup>D</sup>* of *aca*s. We use a special operator & in order to express the result of attaching to a given goal *G* a solved goal *S*� resulting from a previous computation, so that computation can continue from the new goal *G* & *S*� .

Formally, assuming *<sup>G</sup>* <sup>=</sup> <sup>∃</sup>*U*. (*<sup>R</sup>* ✷ (<sup>Π</sup> ✷ *<sup>σ</sup>*)) and *<sup>S</sup>*� <sup>=</sup> <sup>∃</sup>*U*� . (Π� ✷ *σ*� ) a solved goal such that *U* \ *dom*(*σ*� ) <sup>⊆</sup> *<sup>U</sup>*� , *σσ*� = *σ*� , and *Sol*D(Π� ) ⊆ *Sol*D(Π*σ*� ), the operation *<sup>G</sup>* & *<sup>S</sup>*� is defined as <sup>∃</sup>*U*� . (*Rσ*� ✷ (Π� ✷ *σ*� )). The inference rule **CJ** infers an *aca* for a goal with composed kernel (*R*<sup>1</sup> ∧ *R*2) ✷ *S* from *aca*s for goals with kernels of the form *R*<sup>1</sup> ✷ *S* and (*R*<sup>2</sup> & *Si*), respectively; while other inferences deal with different kinds of atomic goal kernels.

Any *CNPC*(D)-derivation <sup>P</sup><sup>−</sup> �*CNPC*(D) *<sup>G</sup>* <sup>⇒</sup> *<sup>D</sup>* can be depicted in the form of a *Negative Proof Tree* over D (shortly, *NPT*) with *aca*s at its nodes, such that the *aca* at any node is inferred from the *acas* at its children using some *CNPC*(D) inference rule. We say that a goal solving system for *CFLP*(D) is *admissible* iff whenever finitely many solved goals {*Si*}*i*∈*<sup>I</sup>* are computed as answers for an admissible initial goal *<sup>G</sup>*, one has <sup>P</sup><sup>−</sup> �*CNPC*(D) *<sup>G</sup>* <sup>⇒</sup> *<sup>i</sup>*∈*<sup>I</sup> Si* with some witnessing *NPT*. The next theorem is intended to provide some plausibility to the pragmatic assumption that actual *CFLP* systems such as *Curry* (Hanus, 2003) or T OY (López & Sánchez, 1999) are admissible goal solving systems.

**Theorem 5. (Existence of Admissible Goal Solving Calculi)** *There is an admissible Goal Solving Calculus GSC*(D) *which formalizes the goal solving methods underlying actual CFLP systems such as Curry or* T OY*.*

*Proof.* A more general result can be proved: If (*R* ∧ *R*� ) & *<sup>S</sup>* �∼*<sup>p</sup>* <sup>P</sup>,*GSC*(D) *<sup>D</sup>* (with a partially developed search space of finite size *p* built using the program P, a *Goal Solving Calculus*

(1) The root of AT is the root of T .

*boxed acas* introduced by **(DF)***<sup>f</sup>* inference steps.

of Wrong and Missing Answers in Declarative Constraint Programming

Fig. 6. *NPT* for the declarative diagnosis of missing answers

As already explained, declarative diagnosis methods search a given *CT* looking for a *buggy node* whose result is unexpected but whose children's results are all expected. In our present setting, the *CT*s are *ANPT*s, the "results" attached to nodes are *aca*s, and a given node *N* is *buggy* iff the *aca* at *N* is *invalid* (i.e., it represents an incomplete recollection of computed answers in the intended interpretation IP) while the *aca* at each children node *Ni* is *valid* (i.e., it represents a complete recollection of computed answers in the intended interpretation IP). As a concrete example, Fig. 6 displays a *NPT* which can be used for the diagnosis of missing answers in the Example 2. Buggy nodes are highlighted by encircling the *aca*s attached to them within double boxes. The *CT* shown in Fig. 7 is the *ANPT* constructed from this *NPT*. In this case, the programmer will judge the root *aca* as *invalid* because he did not expect finite failure. Moreover, from him knowledge of the intended interpretation, he will decide to consider the *aca*s for the functions gen, even, and (//) as valid. However, the

(2) The children of any node *N* in AT are the closest descendants of *N* in T corresponding to

<sup>141</sup> A Semantic Framework for the Declarative Debugging

*GSC*(D) inspired in (López et al., 2004), and a certain selection strategy that only selects atoms descendants of the part *<sup>R</sup>*) then P<sup>−</sup> �*CNPC*(D) *<sup>R</sup>* & *<sup>S</sup>* ⇒ *<sup>D</sup>* with some witnessing *NPT*. The proof proceeds by induction on *p*, using an auxiliary lemma to deal with compound goals whose kernel is a conjunction.

We have also proved the following theorem, showing that any *aca* which has been derived by means of a *NPT* is a logical consequence of the negative theory associated to the corresponding program. This result will be used below for proving the correctness of our diagnosis method of missing answers.

**Theorem 6. (Semantic Correctness of the** *CNPC*(D) **Calculus)** *Let G* ⇒ *D be any aca for a given CFLP*(D)*-program* <sup>P</sup>*. If* <sup>P</sup><sup>−</sup> �*CNPC*(D) *<sup>G</sup>* <sup>⇒</sup> *D then G* <sup>⇒</sup> *D is a logical consequence of* <sup>P</sup><sup>−</sup> *in the sense of Definition 2.*

### **6.1 Declarative diagnosis of missing answers using negative proof trees**

We are now prepared to present a declarative diagnosis method for missing answers which is based on *NPT*s and leads to correct diagnosis for any admissible goal solving system. First, we show that incompleteness symptoms are caused by incomplete program rules. This is guaranteed by the following theorem:

**Theorem 7. (Missing Answers are Caused by Incomplete Program Rules)** *Assume that an incompleteness symptom has been observed for a given CFLP*(D)*-program* P *as explained in Definition 4, with intended interpretation* IP*, admissible initial goal G, and finite disjunction of computed answers D* = *<sup>i</sup>*∈*<sup>I</sup> Si. Assume also that the computation has been performed by an admissible goal solving system. Then there exists a defined function symbol f such that the axiom* (*f*)− <sup>P</sup> *for f in* <sup>P</sup><sup>−</sup> *is not valid in* IP*, so that f 's definition as given in* P *is incomplete with respect to* IP*.*

*Proof.* Because of the admissibility of the goal solving system, we can assume P<sup>−</sup> �*CNPC*(D) *G* ⇒ *D*. Then the *aca G* ⇒ *D* is a logical consequence of P<sup>−</sup> because of Theorem 6. By Definition 2, we conclude that *Sol*<sup>I</sup> (*G*) ⊆ *Sol*D(*D*) holds for any model I of P−. However, we also know that *Sol*IP (*G*) *Sol*D(*D*), because the disjunction *<sup>D</sup>* of computed answers is an incompleteness symptom with respect to IP. Therefore, we can conclude that IP is not a model of P−, and therefore the completeness axiom (*f*)<sup>−</sup> <sup>P</sup> of some defined function symbol *<sup>f</sup>* must be invalid in IP.

The previous theorem does not yet provide a practical method for finding an incomplete function definition. As explained in Section 2, a declarative diagnosis method is expected to find the incomplete function definition by inspecting a *CT*. We propose to use abbreviated *NPT*s as *CT*s. Note that **(DF)***<sup>f</sup>* is the only inference rule in the *CNPC*(D) calculus that depends on the program, while all the other inference rules are correct with respect to arbitrary interpretations. For this reason, abbreviated proof trees will omit the inference steps related to the *CNPC*(D) inference rules other than **(DF)***<sup>f</sup>* . More precisely, given a *NPT* T witnessing <sup>a</sup> *CNPC*(D) proof <sup>P</sup><sup>−</sup> �*CNPC*(D) *<sup>G</sup>* <sup>⇒</sup> *<sup>D</sup>*, its associated *Abbreviated Negative Proof Tree* (shortly, *ANPT*) AT is constructed as follows:

(1) The root of AT is the root of T .

20 Will-be-set-by-IN-TECH

*GSC*(D) inspired in (López et al., 2004), and a certain selection strategy that only selects atoms descendants of the part *<sup>R</sup>*) then P<sup>−</sup> �*CNPC*(D) *<sup>R</sup>* & *<sup>S</sup>* ⇒ *<sup>D</sup>* with some witnessing *NPT*. The proof proceeds by induction on *p*, using an auxiliary lemma to deal with compound goals

We have also proved the following theorem, showing that any *aca* which has been derived by means of a *NPT* is a logical consequence of the negative theory associated to the corresponding program. This result will be used below for proving the correctness of our

**Theorem 6. (Semantic Correctness of the** *CNPC*(D) **Calculus)** *Let G* ⇒ *D be any aca for a given CFLP*(D)*-program* <sup>P</sup>*. If* <sup>P</sup><sup>−</sup> �*CNPC*(D) *<sup>G</sup>* <sup>⇒</sup> *D then G* <sup>⇒</sup> *D is a logical consequence of* <sup>P</sup><sup>−</sup> *in*

We are now prepared to present a declarative diagnosis method for missing answers which is based on *NPT*s and leads to correct diagnosis for any admissible goal solving system. First, we show that incompleteness symptoms are caused by incomplete program rules. This is

**Theorem 7. (Missing Answers are Caused by Incomplete Program Rules)** *Assume that an incompleteness symptom has been observed for a given CFLP*(D)*-program* P *as explained in Definition 4, with intended interpretation* IP*, admissible initial goal G, and finite disjunction of computed*

*Proof.* Because of the admissibility of the goal solving system, we can assume P<sup>−</sup> �*CNPC*(D) *G* ⇒ *D*. Then the *aca G* ⇒ *D* is a logical consequence of P<sup>−</sup> because of Theorem 6. By Definition 2, we conclude that *Sol*<sup>I</sup> (*G*) ⊆ *Sol*D(*D*) holds for any model I of P−. However, we also know that *Sol*IP (*G*) *Sol*D(*D*), because the disjunction *<sup>D</sup>* of computed answers is an incompleteness symptom with respect to IP. Therefore, we can conclude that IP is not a

The previous theorem does not yet provide a practical method for finding an incomplete function definition. As explained in Section 2, a declarative diagnosis method is expected to find the incomplete function definition by inspecting a *CT*. We propose to use abbreviated *NPT*s as *CT*s. Note that **(DF)***<sup>f</sup>* is the only inference rule in the *CNPC*(D) calculus that depends on the program, while all the other inference rules are correct with respect to arbitrary interpretations. For this reason, abbreviated proof trees will omit the inference steps related to the *CNPC*(D) inference rules other than **(DF)***<sup>f</sup>* . More precisely, given a *NPT* T witnessing <sup>a</sup> *CNPC*(D) proof <sup>P</sup><sup>−</sup> �*CNPC*(D) *<sup>G</sup>* <sup>⇒</sup> *<sup>D</sup>*, its associated *Abbreviated Negative Proof Tree* (shortly,

*<sup>i</sup>*∈*<sup>I</sup> Si. Assume also that the computation has been performed by an admissible goal*

<sup>P</sup> *for f in* <sup>P</sup><sup>−</sup> *is*

<sup>P</sup> of some defined function symbol *<sup>f</sup>*

**6.1 Declarative diagnosis of missing answers using negative proof trees**

*solving system. Then there exists a defined function symbol f such that the axiom* (*f*)−

*not valid in* IP*, so that f 's definition as given in* P *is incomplete with respect to* IP*.*

model of P−, and therefore the completeness axiom (*f*)<sup>−</sup>

whose kernel is a conjunction.

*the sense of Definition 2.*

*answers D* =

must be invalid in IP.

*ANPT*) AT is constructed as follows:

diagnosis method of missing answers.

guaranteed by the following theorem:

(2) The children of any node *N* in AT are the closest descendants of *N* in T corresponding to *boxed acas* introduced by **(DF)***<sup>f</sup>* inference steps.

Fig. 6. *NPT* for the declarative diagnosis of missing answers

As already explained, declarative diagnosis methods search a given *CT* looking for a *buggy node* whose result is unexpected but whose children's results are all expected. In our present setting, the *CT*s are *ANPT*s, the "results" attached to nodes are *aca*s, and a given node *N* is *buggy* iff the *aca* at *N* is *invalid* (i.e., it represents an incomplete recollection of computed answers in the intended interpretation IP) while the *aca* at each children node *Ni* is *valid* (i.e., it represents a complete recollection of computed answers in the intended interpretation IP).

As a concrete example, Fig. 6 displays a *NPT* which can be used for the diagnosis of missing answers in the Example 2. Buggy nodes are highlighted by encircling the *aca*s attached to them within double boxes. The *CT* shown in Fig. 7 is the *ANPT* constructed from this *NPT*. In this case, the programmer will judge the root *aca* as *invalid* because he did not expect finite failure. Moreover, from him knowledge of the intended interpretation, he will decide to consider the *aca*s for the functions gen, even, and (//) as valid. However, the

terminology of Definition 4) and type the command /missing at the system prompt in order to initiate a *debugging session*. The debugger proceeds carrying out the following steps:

<sup>143</sup> A Semantic Framework for the Declarative Debugging

1. The object program P.*pl* is transformed into a new Prolog program PT. *pl*. The debugger can safely assume that P.*pl* already exists because the tool is always initiated *after* some missing answer has been detected by the user. The transformed program P<sup>T</sup> behaves almost identically to P, being the only difference that it produces a suitable *trace* of the computation in a text file. For instance here is a fragment of the code for the function even

4 write(' begin('), write(' even,'), writeq(N), write(','), 5 write(R), write(', '), writeq(IC), write(').'), nl, 6 % evenBis corresponds to the original predicate for even

9 write(' output('), write(' even,'), writeq(N), write(','),

As the example shows, the code for each function now displays information about the values of the arguments and the contents of the constraint store at the moment of invoking any user defined function (lines 4-5). Then the predicate corresponding to the original function, now renamed with the Bis suffix, is called (line 7). After any successful function call the trace displays again the values of the arguments and the result, which may have changed, and the contents of the output constraint store (lines 9, 10). A second clause (lines 12-15) displays the value end when the function has exhausted its possible outputs. The clause fails in order to ensure that the program flow is not changed. The original code for each function is kept unaltered in the transformed program except for the renaming (evenBis instead of even in the example, line 16). This ensures that the program will behave equivalently to the original program, except for the trace produced as a side-effect. 2. In order to obtain the trace file, the debugger repeats the computation of all the answers for the goal *G* with respect to P<sup>T</sup> . After each successful computation, the debugger enforces a fail in order to trigger the backtracking mechanism and produces the next solution for

10 write(R), write(', '), writeq(OC), write(').'), nl. 11 % when all the possible outputs have been produced

16 evenBis(N,R,IC,OC) :- ... original code for even ... .

the goal. The program output is redirected to a file, where the trace is stored.

*Computation Tree* (an *ANPT*), which is displayed by a *Java graphical interface*.

3. The trace file is then analyzed by the *CT builder* module of the tool. The result is the

4. The tree can be navigated by the user either manually, providing information about the validity of the *aca*s contained in the tree, or using any of the automatic strategies included in the tool which try to minimize the number of nodes that the user must examine (see (Silva, 2006) for a description of some strategies and their efficiency). The process ends when a buggy node is found and the tool points to an incomplete function definition, as

of our running example in the transformed program:

of Wrong and Missing Answers in Declarative Constraint Programming

2 even(N,R,IC,OC):-

12 even(N,R,IC,OC):-

14 !, 15 fail.

7 evenBis(N,R,IC,OC),

8 % display an output result

13 nl, write(' end(even).'), nl,

1 % this clause wraps the original predicate

3 % display the input values for even

*aca* fDiff (2:2:1:G) → *F*<sup>2</sup> ⇒ (*F*<sup>2</sup> �→ ⊥) asserts that the *undefined value* ⊥ is the only possible result for the function call fDiff (2:2:1:G), while the user expects also the result 2. Therefore, the user will judge this *aca* as invalid. The node where it sits (enclosed within a double box in Fig. 7) has no children and thus becomes buggy, leading to the diagnosis of fDiff as incomplete. This particular incompleteness symptom could be mended by placing the third rule for fDiff within the program. Our last result is a refinement of Theorem 7. It

Fig. 7. *CT* for the declarative diagnosis of missing answers

guarantees that declarative diagnosis with *ANPT*s used as *CT*s leads to the correct detection of incomplete program functions.

**Theorem 8. (***ANPT***s Lead to the Diagnosis of Incomplete Functions)** *As in Theorem 7, assume that an incompleteness symptom has been observed for a given CFLP*(D)*-program* P *as explained in Definition 4, with intended interpretation* IP*, admissible initial goal G, and finite disjunction of answers D* = *<sup>i</sup>*∈*<sup>I</sup> Si, computed by an admissible goal solving system. Then* P<sup>−</sup> �*CNPC*(D) *<sup>G</sup>* ⇒ *D, and the ANPT constructed from any NPT witnessing this derivation, has some buggy node. Moreover, each such buggy node points to an axiom* (*f*)− <sup>P</sup> *which is incomplete with respect to the user's intended interpretation* IP*.*
