The semantics for cuts in Prolog is largely operational, and is
usually defined based on an ordered traversal of an SLD search tree.
Tabling, of course, has a different operational semantics than Prolog
- it uses SLG trees rather than SLD trees, for instance - so it is
not surprising that the interaction of tabling with cuts is
operational. In Prolog, the semantics for a cut can be expressed in
the following manner: a cut executed in the body of a predicate
frames from the top (youngest end) of the choice point stack down to
and including the call for
. In XSB a cut is allowed to
succeed as long as it does not cut over a choice point for a
non-completed tabled subgoal, otherwise, the computation aborts.
This means, among other matters, that the validity of a cut depends on
the scheduling strategy used for tabling, that is on the
strategy used to determine when an answer is to be returned to a
consuming subgoal. Scheduling strategy was discussed
Section 5.2.2: for now, we assume that XSB's
default local scheduling is used in the examples for cuts.
:- table cut_p/1, cut_q/1, cut_r/0, cut_s/0. cut_p(X) :- cut_q(X), cut_r. cut_r :- cut_s. cut_s :- cut_q(_). cut_q(1). cut_q(2).What solutions are derived for the goal ?- cut_p(X)? Suppose that cut_p/1 were rewritten as
cut_p(X) :- cut_q(X), once(cut_r).How should this cut over a table affect the answers generated for cut_p/1? What happens if you rewrite cut_p/1 in this way and compile it in XSB?
In Exercise 5.2.6, cut_p(1) and cut_p(2) should both be true. Thus, the cut in the literal once(cut_r) must not inadvertently cut away solutions that are demanded by cut_p/1. In the default local scheduling of XSB Version 3.0 tabled subgoals are fully evaluated whenever possible before returning any of their answers. Thus the first call cut_q(X) in the body of the clause for cut_p/1 is fully evaluated before proceeding to the goal once(cut_r). Because of this any choice points for cut_q(X) are to a completed table. For other scheduling strategies, such as batched scheduling, non-completed choice points for cut_p/1 may be present on the choice point stack so that the cut would be disallowed. In addition, it is also possible to construct examples where a cut is allowed if call variance is used, but not if call subsumption is used.
:- table demo/1. demo(true). demo((A,B)) :- !, demo(A), demo(B). demo(C) :- call(C).More elaborate tabled meta-interpreters can be extremely useful, for instance to implement various extensions of definite or normal programs.
In XSB's compilation, the cut above is compiled so that it is valid to use with either local or batched (a non-default) evaluation. An example of a cut that is valid neither in batched nor in local evaluation is as follows.
:- table cut_a/1, cut_b/1. cut_a(X):- cut_b(X). cut_a(a1). cut_b(X):- cut_a(X). cut_b(b1).For this program the goal ?- cut_a(X) produces two answers, as expected: a1 and b1. However, replacing the first class of the above program with
cut_a(X):- once(cut_b(X)).will abort both in batched or in local evaluation.
To summarize, the behavior of cuts with tables depends on dynamic operational properties, and we have seen examples of programs in which a cut is valid in both local and batched scheduling, in local but not batched scheduling, and in neither batched nor local scheduling. In general, any program and goal that allows cuts in batched scheduling will allow them in local scheduling as well, and there are programs for which cuts are allowed in local scheduling but not in batched.
Finally, we note that in Version 3.0 of XSB a ``cut'' over tables implicitly occurs when the user makes a call to a tabled predicate from the interpreter level, but does not generate all solutions. This commonly occurs in batched scheduling, but can also occur in local scheduling if an exception occurs. In such a case, the user will see the warning "Removing incomplete tables..." appear. Any complete tables will not be removed. They can be abolished by using one of XSB's predicates for abolishing tables.