Linear Tabulated Resolution Based on Prolog Control Strategy

Department of Computing Science, University of Alberta, Edmonton, Alberta, Canada
Theory and Practice of Logic Programming (Impact Factor: 1.05). 04/2000; 1(1). DOI: 10.1017/S1471068400001010
Source: CiteSeer
ABSTRACT
Infinite loops and redundant computations are long recognized open problems in Prolog. Two ways have been explored to resolve these problems: loop checking and tabling. Loop checking can cut infinite loops, but it cannot be both sound and complete even for function-free logic programs. Tabling seems to be an effective way to resolve infinite loops and redundant computations. However, existing tabulated resolutions, such as OLDT-resolution, SLG-resolution, and Tabulated SLS-resolution, are non-linear because they rely on the solution-lookup mode in formulating tabling. The principal disadvantage of non-linear resolutions is that they cannot be implemented using a simple stack-based memory structure like that in Prolog. Moreover, some strictly sequential operators such as cuts may not be handled as easily as in Prolog. In this paper, we propose a hybrid method to resolve infinite loops and redundant computations. We combine the ideas of loop checking and tabling to establish a linear tabul...

Full-text

Available from: Li-Yan Yuan, Oct 21, 2012
arXiv:cs/0003046v1 [cs.AI] 9 Mar 2000
Linear Tabulated Resolution Based on Prolog Control Strategy
Yi-Dong Shen
Department of Computer Science, Chongqing University, Chongq ing 4000 44, P.R.China
Email: ydshen@cs.ualberta.ca
Li-Yan Yuan and Jia-Huai You
Department of Computing Science, University of Alb e rta, Edmonton, Alberta, Canada T6G 2H1
Email: {yuan, you}@cs.ualberta.ca
Neng-Fa Zhou
Department of Computer a nd Information Science, Brooklyn College
The City University of New York, New York, NY 11210-2889, USA
Email: zhou@sci.broo klyn.cuny.edu
Abstract
Infinite loops and redundant computations are long recognized op e n problems in Prolog. Two
ways have been explored to resolve these problems: loop checking and tabling. Loop checking
can cut infinite loops, but it cannot be both sound and co mplete even for function-free logic
programs. Tabling seems to be an effective way to resolve infinite loops and redundant com-
putations. However, existing tabulated resolutions, such as OLDT-resolution, SLG-resolution,
and Tabulated SLS-resolution, are non-linear because they rely on the solution-loo kup mode in
formulating tabling. The principal disadvantage of non-linear r e solutions is that they cannot be
implemented using a simple stack-based memory structure like that in Prolog. Moreover, some
strictly sequential operators such as cuts may not be handled as easily as in Prolog.
In this paper, we propo se a hybrid method to resolve infinite loops and redundant com-
putations. We combine the ideas of loop checking and tabling to establish a linear tabulated
resolution called TP-re solution. TP-resolution has two distinctive features: (1) It makes lin-
ear tabulated derivations in the same way as Prolo g except that infinite loops are broken and
redundant c omputations are reduced. It handles cuts as effectively as Prolog. (2) It is sound
and complete for positive logic programs with the bounded-term-size prop e rty. The underlying
algorithm can be implemented by an extension to any existing Prolog abstract machines such
as WAM or ATOAM.
Keywords: Ta bling, loop checking, res olution, Prolog.
Work performed during a visit at Department of Computing Science, University of Alberta, Canada.
1
Page 1
1 Introduction
While Prolog has many distinct advantages, it suffers from some serious problems, among the best-
known of which are infinite loops and redundant computations. Infinite loops cause users (especially
less skilled users) to lose confidence in writing terminating Prolog programs, whereas redu ndant
computations greatly reduce the efficiency of Prolog. The existing appr oaches to resolving th ese
problems can be classified into two categories: loop checking and tabling.
Loop checkin g is a direct way to cut infinite loops. It locates nodes at which SLD-derivations
step into a loop and prunes them from SLD-trees. In formally, an SLD-derivation G
0
C
1
1
G
1
...
C
i
i
G
i
...
C
k
k
G
k
... is said to step into a loop at a node N
k
labeled with a goal G
k
if there is a node N
i
(0 i < k) labeled with a goal G
i
in the derivation such that G
i
and G
k
are sufficiently similar. Many loop ch ecking mechanisms have been presented in the literature (e.g.
[2, 7, 8, 14 , 16, 18 , 20]). However, no loop checking mechanism can be both (weakly) sound and
complete because the loop checking problem itself is undecidable in general even for function-free
logic programs [2].
The main idea of tabling is that during top-down query evaluation, we store intermediate
results of some subgoals and look them u p to solve variants of the su bgoals that occur later. Since
no variant subgoals will be recomputed by applying the same set of program clauses, in finite loops
can be avoided. As a result, termination can be guaranteed for bounded-term-size programs and
redundant computations substantially reduced [4, 6, 17, 20, 22].
There are many ways to f ormulate tabling, each leading to a tabulated resolution (e.g. OLDT-
resolution [17], SLG-resolution [6], Tabulated SLS-resolution [4], etc.). However, although existing
tabulated resolutions differ in one aspect or another, all of them rely on the so called solution-lookup
mode. That is, all nodes in a search tree/forest are partitioned into two subsets, solution nodes
and lookup nodes; solution nodes produce child nodes using program clauses, whereas lookup nodes
produce child nodes using answers in tables.
Our investigation s hows that the pr incipal disadvantage of the solution-lookup mode is th at it
makes tabulated resolutions non-linear. Let G
0
C
1
1
G
1
...
C
i
i
G
i
be the current derivation
with G
i
being the latest generated goal. A tabu lated resolution is said to be linear
1
if it makes the
next d erivation step either by expanding G
i
by resolving a subgoal in G
i
against a program clause
or a tabled answer, which yields G
i
C
i+1
i+1
G
i+1
, or by exp anding G
i1
via backtracking. It
is due to such non-linearity th at the underlying tabulated resolutions cannot be implemented in
the same way as SLD-resolution (Prolog) u s ing a simple stack-based memory stru cture. Moreover,
some strictly sequential operators such as cuts (!) may not be handled as easily as in Prolog. For
instance, in the well-known tabulated resolution system XSB, clauses like
p(.) ..., t(.), !, ...
1
The concept of “linear” here is different from the one used for SL-resolution [9].
2
Page 2
where t(.) is a tabled subgoal, are n ot allowed because the tabled predicate t occurs in the scope
of a cut [11, 13].
The objective of our research is to establish a hybrid approach to resolving infinite loops and
redundant computations and develop a linear tabulated Prolog system. In this paper, we establish a
theoretical framework for such a system, focusing on a linear tabulated resolution TP-resolution
for positive logic programs (TP for Tabulated Prolog).
Remark 1.1 In th is paper we will use the prefix TP to name some key concepts such as TP-
strategy, TP-tree, TP-d erivation and TP-resolution, in contrast to the standard Prolog control
strategy, Prolog-tree (i.e. SLD-tree generated under Prolog-strategy), Prolog-derivation an d Prolog-
resolution (i.e. SLD-resolution controlled by Prolog-strategy), respectively.
In TP-resolution, each node in a search tree can act n ot only as a solution node but also
as a lookup node, regardless of when and where it is generated. In fact, we do not distinguish
between solution and lookup nodes in TP-resolution. This shows an essential d ifference from
existing tabulated resolutions using the solution-lookup mode. The main idea is as follows: for any
selected tabled subgoal A at a node N
i
labeled with a goal G
i
, it always first uses an answer I in
a table to generate a child node N
i+1
(N
i
acts as a lookup node), which is labeled by the resolvent
of G
i
and I; if no new answers are available in the table, it resolves against program clauses to
produce child nodes (N
i
then acts as a solution node). The order in which an s wers in a table are
used is based on first-generated-first-use and the order in which program clauses are applied is from
top to bottom except for the case where the derivation steps into a loop at N
i
. In such a case, the
subgoal A s k ips the clause th at is being used by its closest ancestor subgoal that is a variant of A.
Like OLDT-resolution, TP-r esolution is sound and complete for positive logic programs with the
bounded-term-size property.
The plan of this paper is as follows. In Section 2 we pr esent a typical example to illustrate
the main idea of TP-resolution and its key differences from existing tabulated resolutions. In
Section 3, we formally d efi ne TP-resolution. In Section 3.1 we discuss how to represent tables and
how to operate on tables. In Section 3.2 we first introdu ce the so called P MF mode for resolving
tabled subgoals with program clauses, which lays the basis for a linear tabulated resolution. We
then define a tabulated control strategy called TP-strategy, which enhances Prolog-strategy with
proper policies for the selection of answers in tables. Next we present a constructive definition (an
algorithm) of a TP-tree based on TP-strategy. Finally, based on TP-trees we define TP-derivations
and TP-resolution.
Section 4 is devoted to showing some major characteristics of TP-resolution, including its
termination property and soundness and completeness. We also discuss in detail how TP-resolution
deals with the cut operator.
We assume familiarity with the basic concepts of logic programming, as presented in [10]. Here
3
Page 3
and throughout, variables begin with a capital letter, and predicates, functions and constants with
a lower case letter. By
~
E we denote a list/tuple (E
1
, ..., E
m
) of elements. Let
~
X = (X
1
, ..., X
m
)
be a list of variables and
~
I = (I
1
, ..., I
m
) a list of terms. By
~
X/
~
I we denote a substitution
{X
1
/I
1
, ..., X
m
/I
m
}. By p(.) we refer to any atom with the predicate p and by p(
~
X) to an atom
p(.) that contains the list
~
X of distinct variables. For instance, if p (
~
X) = p(W, a, f(Y ), W ), then
~
X = (W, Y ). Let G = A
1
, ..., A
m
be a goal and B a subgoal. By G + B we denote the goal
A
1
, ..., A
m
, B. By a variant of an atom (resp. a subgoal or a term) A we mean an atom (resp.
a subgoal or a term) A
that is the same as A up to variable ren amin g.
2
Let V be a set of atoms
(resp. subgoals or terms) that are variants of each other; then they are called variant atoms (resp.
variant subgoals or variant terms). Moreover, clauses with the same head predicate p are numbered
sequentially, with C
p
i
referring to its i-th clause (i > 0). Finally, unless otherwise stated, by a
(logic) program we refer to a positive logic program with a nite set of clauses.
2 An Illustrative Example
We use th e following simple program to illustrate the basic idea of the TP approach. For conve-
nience of presentation, we choose OLDT-resolution [17] for a side-by-side comparison (other typical
tabulated resolutions, su ch as SLG-resolution [6] and Tabulated SLS-resolution [4], have similar
effects).
P
1
: reach(X, Y ) reach(X, Z), edge(Z, Y ). C
r
1
reach(X, X). C
r
2
reach(X, d). C
r
3
edge(a, b). C
e
1
edge(d, e). C
e
2
Let G
0
= reach(a, X) be the query (top goal). Then Prolog will step into an infinite
loop right after the application of the firs t clause C
r
1
. We now show how it works using OLDT-
resolution (under the depth-first control strategy). Starting from the root node N
0
labeled with the
goal reach(a, X), the application of the clause C
r
1
gives a child node N
1
labeled with the goal
reach(a, Z), edge(Z, X) (see Figure 1). Since the subgoal reach(a, Z) is a variant of reach(a, X)
that occurred earlier, it is suspended to wait for reach(a, X) to produce answers. N
0
and N
1
(resp. reach(a, X) and reach(a, Z)) are then called solution and lookup nodes (resp. subgoals),
respectively. So the derivation goes back to N
0
and resolves reach(a, X) with th e second clause
C
r
2
, which gives a sibling node N
2
labeled with an empty clause 2. Since reach(a, a) is an answer
to the subgoal r each(a, X), it is memorized in a table, say T B(reach(a, X)). The derivation then
jumps back to N
1
and uses the answer reach(a, a) in the table to resolve with the lookup subgoal
2
By this definition, A is a variant of itself.
4
Page 4
reach(a, Z), which gives a new n ode N
3
labeled with edge(a, X). Next, the node N
4
labeled
with 2 is derived from N
3
by resolving the subgoal edge(a, X) with the clause C
e
1
. So the answer
reach(a, b) is added to the table T B(reach(a, X)). After these s teps, the OLDT-derivation evolves
into a tree as depicted in Figure 1, which is clearly not linear.
?
?
?
P
P
P
P
Pq
C
e
1
Z = a (Get reach(a, a) from the table)
C
r
1
C
r
2
(Add reach(a, b) to the table)N
4
: 2
(Add reach(a, a) to the table)
N
0
: reach(a, X)
N
1
: reach(a, Z), ed ge(Z, X) N
2
: 2
N
3
: edge(a , X)
Figure 1: OLDT-derivation.
We now explain how TP-resolution works. Starting from the root node N
0
labeled with the
goal reach(a, X) we apply the clause C
r
1
to derive a child node N
1
labeled with the goal
r each(a, Z), edge(Z, X) (see Figure 2). As the subgoal reach(a, Z) is a variant of reach(a, X)
and the latter is an ancestor of the former (i.e., the derivation steps into a loop at N
1
[14]), we
ch oose C
r
2
, the clause from the backtracking point of the subgoal reach(a, X), to resolve with
reach(a, Z), which gives a child node N
2
labeled with edge(a, X). Since reach(a, a) is an answer
to the subgoal reach(a, Z), it is memorized in a table T B(reach(a, X)). We th en resolve the subgoal
edge(a, X) against the clause C
e
1
, which gives the leaf N
3
labeled with 2. So the answer reach(a, b)
to the subgoal reach(a, X) is added to the table T B(reach(a, X)). After these steps, we get a path
as shown in Figure 2, which is clearly linear.
?
?
?
C
e
1
C
r
2
(Add reach(a, a) to the table)
C
r
1
(Add reach(a, b) to the table)N
3
: 2
N
0
: reach(a, X)
N
1
: reach(a, Z), ed ge(Z, X)
N
2
: edge(a , X)
Figure 2: TP-derivation.
Now consider b acktracking. Remember that after the above derivation steps, the table T B(
reach(a, X)) consists of two answers, reach(a, a) and reach(a, b). For the OL DT approach, it first
backtracks to N
3
and then to N
1
(Figure 1). Since the subgoal reach(a, Z) has used the first answer
in the table before, it resolves with the second, reach(a, b), which gives a new node labeled with the
goal edge(b, X). Obviously, this goal will fail, so it backtracks to N
1
again. This time no new
5
Page 5
answers in the table are available to the subgoal reach(a, Z), so it is suspended and th e derivation
go es to the solution node N
0
. The third clause C
r
3
is then selected to resolve with the s ubgoal
reach(a, X), yielding a new answer reach(a, d), which is added to the table. The derivation then
go es back to N
1
where the new answer is used in the same way as described before.
The TP approach does backtracking in the same way as the OL DT app roach except for
the following key differences: (1) Because we do not distinguish between solution and lookup
nodes/subgoals, when no new answers in the table are available to the subgoal reach(a, Z) at N
1
,
we b acktrack the subgoal by resolving it against the next clause C
r
3
. This guarantees that TP-
derivations are always linear. (2) S ince there is a lo op between N
0
and N
1
, before failing the subgoal
reach(a, X) at N
0
via backtracking we need to be sure that the subgoal has got its complete set of
answers. This is achieved by performing answer iteration via the loop. That is, we regenerate the
loop to see if any new answers can be derived until we reach a fixpoint. Figure 3 shows the rst
part of TP-resolution, where the following answers to G
0
are derived: X = a, X = b, X = d and
X = e. Figure 4 shows the part of answer iteration. Since no new answer is derived during the
iteration (i.e. no answer is added to any tables), we fail the subgoal reach(a, X) at N
0
.
? ?
?
9
Q
Q
Qs
=
X
X
X
X
X
X
X
X
X
X
X
Xz
C
e
1
C
e
2
N
0
: reach(a, X)
C
r
1
(Add reach(a, e))
N
1
: reach(a, Z), edge(Z, X)
C
r
2
(Add reach(a, a))
N
7
: edge(e , X)
Get reach (a, b) C
r
3
(Add reach(a, d))
N
5
: edge(d, X)N
4
: edge(b, X)
Get reach (a, e)
N
2
: edge(a, X)
(Add reach(a, b)) N
6
: 2N
3
: 2
Figure 3: TP-derivations of P
1
{G
0
}.
? ?
?
9
Q
Q
Qs
=
X
X
X
X
X
X
X
X
X
X
X
Xz
C
e
1
C
e
2
N
0
: reach(a, X)
C
r
1
N
8
: reach(a, Z), edge(Z, X)
N
14
: edge(e , X)
Get reach(a, b) Get reach(a, d)
N
12
: edge(d, X)N
11
: edge(b, X)
Get reach(a, e)
N
9
: edge(a, X)
N
13
: 2
Get reach(a, a)
N
10
: 2
Figure 4: Answer iteration via a loop.
Remark 2.1 From the above illustration, we see that in OL DT-resolution, solution nodes are
those at which the left-most subgoals are generated earliest among all their variant s ubgoals. In
SLG-resolution, however, solution nodes are roots of trees in a search forest, each labeled by a
special clause of the form A A [5]. In Tabulated SLS-resolution, any root of a tree in a forest is
6
Page 6
itself labeled by an instance, say A B
1
, ..., B
n
(n 0), of a program clause and no nodes in the
tree will produce child nodes using program clauses [3]. However, for any atom A we can assume
a virtual super-root labeled with A A, which takes all the roots in the forest lab eled by A ...
as its child nodes. In this sense, the search forest in Tabulated SLS-resolution is the same as that
in SLG-resolution for positive logic programs. Therefore, we can consider all virtual super-roots as
solution nodes.
3 TP-Resolution
This section formally defines the TP approach to tabulated resolution, mainly in cluding th e rep-
resentation of tables, the strategy for controlling tabulated derivations (TP-strategy), and the
algorithm for making tabulated derivations based on the control strategy (TP -trees).
3.1 Tabled Predicates and Tables
Predicates in a program P are classified as tabled predicates an d non-tabled predicates. The classi-
fication is made based on a dependency graph [1]. Informally, for any predicates p and q, there is
an edge p q in a dependency graph G
P
if there is a clause in P of the form p(.) ..., q (.), ...
Then a predicate p is to be tabled if G
P
contains a cycle with a node p.
Any atom/subgoal with a tabled predicate is called a tabled atom/subgoal. During tabulated
resolution, we will create a table for each tabled subgoal, A. Apparently, the table must contain A
(as an index) and have space to store intermediate answers of A. Note that in our tabling approach,
any tabled subgoal can act both as a solution subgoal and as a lookup subgoal, so a table can be
viewed as a blackboard on which a set of variant subgoals will read and write answers. In order to
guarantee not losing answers for any tabled su bgoals (i.e. the table should contain all answers that
A is supposed to have by applying its related clauses), while avoiding redun dant computations (i.e.
after a clause has been used by A, it should not be re-used by any other variant subgoal A
), a
third component is needed in the table that keeps the status of the clauses related to A. Therefore,
after a clause C
i
has been used by A, we change its status. Then when evaluating a new subgoal
A
that is a variant of A, C
i
will be ignored because all answers of A derived via C
i
have already
been stored in the table. For any clause whose head is a tabled atom, its status can be “no longer
available” or “still available.” We say that C
i
is “no longer available” to A if all answers of A
through the application of C
i
have already been stored in the table of A. Otherwise, we say C
i
is
“still available” to A. Finally, we need a flag variable COM P in the table to indicate if all answers
through the application of all clauses related to A have been completely stored in the table. This
leads to the following.
Definition 3.1 Let P be a logic program and p(
~
X) a tabled subgoal. Let P contain exactly
7
Page 7
M clauses, C
p
1
, ..., C
p
M
, with a head p(.). A table for p(
~
X), denoted T B(p(
~
X)), is a four-tuple
(p(
~
X), T, C, COM P), where
1. T consists of tuples that are instances of
~
X, each
~
I of which represents an answer, p(
~
X)
~
X/
~
I,
to the subgoal.
2. C is a vector of M elements, with C[i] = 0 (resp. = 1) representing that the status of C
p
i
w.r.t. p(
~
X) is “no longer available” (resp. “still available”).
3. COMP {0, 1}, w ith COMP = 1 indicating that the answers of p(
~
X) have been completed.
For convenience, we use T B(p(
~
X)) answer
tuple[i] to refer to the i-th answer tu ple in T ,
T B(p(
~
X)) clause
status[i] to the status of C
p
i
w.r.t. p(
~
X), and T B(p(
~
X)) COMP to the
flag COMP.
Example 3.1 Let P be a logic program that contains exactly three clauses, C
p
1
, C
p
2
and C
p
3
, with
a head p(.). The table
T B(p(X, Y )) : (p(X, Y ), {(a, b), (b, a), (b, c)}, (1, 0, 0), 0)
represents that there are three answers to p(X, Y ), namely p(a, b), p(b, a) an d p(b, c), and that C
p
2
and C
p
3
have already been used by p(X, Y ) (or its variant subgoals) and C
p
1
is still available to
p(X, Y ). Obviously, the answers of p(X, Y ) have not yet been completed. The table
T B(p(a, b)) : (p(a, b), {()}, (0, 1, 1), 1)
shows that p(a, b) has been proved true after applying C
p
1
. Note that since p(a, b) contains no
variables, its answer is a 0-ary tuple. Finally, the table
T B(p(a, X)) : (p(a, X), {}, (0, 0, 0), 1)
represents that p(a, X) has no answer at all.
Before introducing operations on tables, we define the structure of nodes used in TP-resolution.
Definition 3.2 Let P be a logic program and G
i
a goal p(
~
X), A
2
, ..., A
m
. By “register a node
N
i
with G
i
we do the following: (1) label N
i
with G
i
, i.e. N
i
: p(
~
X), A
2
, ..., A
m
; and (2) create
the following structure for N
i
:
answer
ptr, a pointer that points to an answer tuple in T B(p(
~
X)).
clause
ptr, a pointer that points to a clause in P with a head p(.).
clause
SUSP (initially =0), a flag used for the update of clause status.
node
LOOP (initially = 0), a flag showing if N
i
is a loop node.
node
IT ER (initially =0), a flag showing if N
i
is an iteration node.
node ANC (initially =1), a flag showing if N
i
has any ancestor variant subgoals.
8
Page 8
For any field F in the structure of N
i
, we refer to it by N
i
F . The meaning of N
i
answer
ptr and N
i
clause p t r is obvious. The remaining fields w ill be defined by Definition 3.8
followed by the procedu re nodetype
update(.). We are now ready to define operations on tables.
Definition 3.3 Let P be a logic program with M clauses with a head p(.) and N
i
a n ode labeled by
a goal p(
~
X), ..., A
m
. Let NEW be a global flag variable used for answer iteration (see Algorithm
2 for details). We have the following basic operations on a table.
1. create(p(
~
X)). C reate a table T B(p(
~
X)) : (p(
~
X), T, C, COM P), with T = {}, COMP = 0,
and C[j] = 1 for all 1 j M.
2. memo(p(
~
X),
~
I), where
~
I is an instance of
~
X. When
~
I is not in T B(p(
~
X)), add it to the end
of the table, set N EW = 1, and if
~
I is a variant of
~
X, set T B(p(
~
X)) COMP = 1.
3. lookup(N
i
,
~
I
i
). Fetch the next answer tuple in T B(p(
~
X)), which is pointed by N
i
answer ptr,
into
~
I
i
. If there is no next tuple,
~
I
i
= null.
4. memo
look(N
i
, p (
~
X),
~
I, θ
i
). It is a compact operator, which combines memo(.) and lookup(.).
That is, it first performs memo(p(
~
X),
~
I) and then gets the next answer tuple
~
F from T B(p(
~
X)),
which together with
~
X forms a substitution θ
i
=
~
X/
~
F . If there is no next tuple, θ
i
= null.
First, the procedure create(p(
~
X)) is called only when the subgoal p(
~
X) occurs the rst time
and no variant subgoals occurred before. Therefore, up to the time when we call create(p(
~
X)), no
clauses with a h ead p(.) in P have been selected by any variant subgoals of p(
~
X), so their status
should be set to 1. Second, whenever an answer p(
~
I) of p(
~
X) is derived, we call the procedu re
memo(p(
~
X),
~
I). If the answer is new, it is appended to the end of the table. Th e flag NEW is
then set to 1, showing that a new answer has been derived. If the new tuple
~
I is a variant of
~
X, which m eans that p(
~
X) is true for any instances of
~
X, the answers of p(
~
X) are completed so
T B(p(
~
X)) COMP is set to 1. Finally, lookup(N
i
,
~
I
i
) is used to fetch an answer tup le from the
table f or the subgoal p(
~
X) at N
i
.
memo(.) and lookup(.) can be used independently. They can also be used in pairs, i.e.
memo(.) immediately followed by lookup(.). In the latter case, it would be more convenient to
use memo
look(.).
3.2 TP-Strategy and TP-Trees
In this subsection, we introduce the tabulated control strategy and the way to make tabulated
derivations based on this strategy. We begin by discussing how to resolve subgoals with program
clauses and answers in tables.
Let N
i
be a node labeled by a goal G
i
= A
1
, ..., A
m
with A
1
= p(
~
X) a tabled subgoal.
Consider evaluating A
1
using a program clause C
p
= A B
1
, ..., B
n
(n 0), where A
1
θ =
9
Page 9
.
3
If we use SLD-resolution, we would obtain a new node labeled with the goal G
i+1
=
(B
1
, ..., B
n
, A
2
, ..., A
m
)θ, where the mgu θ is consumed by all A
j
s (j > 1), although the proof of
A
1
θ has not yet been completed (produced). In ord er to avoid such kind of pr e-consumption, we
propose the so called PMF (for Prove-Memorize-Fetch) mode for resolving tabled subgoals with
clauses. That is, we first prove (B
1
, ..., B
n
)θ. If it is true with an mgu θ
1
, which means A
1
θθ
1
is
true, we memorize the answer A
1
θθ
1
in the table T B(A
1
) if it is new. We then fetch an answer
from T B(A
1
) to apply to the remaining subgoals of G
i
. Obviously modifying SLD-resolution by
the PMF mode preserves the original answers to G
i
. Moreover, since only new answers are added
to T B(A
1
), all repeated answers of A
1
will be precluded to apply to th e remaining subgoals of G
i
,
so that redundant computations are avoided.
The PMF mode can readily be realized by using the two table procedures, memo(.) and
lookup(.), or using the compact operator memo
look(.). That is, after resolving the subgoal A
1
with the clause C
p
, N
i
gets a child node N
i+1
labeled with the goal
G
i+1
= (B
1
, ..., B
n
)θ, memo
look(N
i
, p (
~
X),
~
Xθ, θ
i
), A
2
, ..., A
m
.
Note that the application of θ is blocked by the subgoal memo
look(.) because th e consumption
(fetch) must follow the production (prove and memorize). We now explain how it works.
Assume that after some resolution steps from N
i+1
we reach a node N
k
that is labeled by the
goal G
k
= memo
look(N
i
, p (
~
X),
~
Xθθ
1
, θ
i
), A
2
, ..., A
m
. This means that (B
1
, ..., B
n
)θ has been
proved true with the mgu θ
1
. That is, A
1
θθ
1
is an ans wer of A
1
. By the left-most computation
rule, memo
look(N
i
, p (
~
X),
~
Xθθ
1
, θ
i
) is executed, which adds to the table TB(A
1
) the answer tuple
~
Xθθ
1
if it is new, gets from T B(A
1
) the next tuple
~
I, and then sets θ
i
=
~
X/
~
I. Since A
1
θ
i
is an
answer to the subgoal A
1
of G
i
, the mgu θ
i
needs to be applied to the remaining A
j
s of G
i
. We
distinguish between two cases.
(1) From A
2
to A
m
, A
j
= memo
look(N
f
, B, , θ
f
) is the rst subgoal of the f orm memo look(.).
According to the PMF mode, there must be a n ode N
f
, which occurred earlier than N
i
,
labeled with a goal G
f
= B, A
j+1
, ..., A
m
such that B is a tabled subgoal and A
j
=
memo look(N
f
, B, , θ
f
) resulted from resolving B with a program clause. This means that
the proof of B is now redu ced to the proof of (A
2
, ..., A
j1
)θ
i
. Therefore, by the PMF mode
θ
i
should be ap plied to the subgoals A
2
until A
j
. That is, N
k
has a child node N
k+1
labeled
with a goal G
k+1
= (A
2
, ..., A
j
)θ
i
, A
j+1
, ..., A
m
.
(2) For no j 2 A
j
is of the form memo look(.). This m eans that no A
j
is a descendant of
any tabled subgoal, so the mgu θ
i
should be applied to all the A
j
s. That is, G
k+1
=
(A
2
, ..., A
m
)θ
i
.
Note that by Definition 3.3 the atom p(
~
X) in memo(p(
~
X),
) and memo look( , p(
~
X), , )
is merely used to index the table T B(p(
~
X)), so it cannot be instantiated during the resolution.
3
Here and throughout, we assume that C
p
has been standardized apart to share no variables with G
i
.
10
Page 10
That is, for any mgu θ, memo(p(
~
X),
~
I)θ = memo(p(
~
X),
~
Iθ) and memo look(N
i
, p (
~
X),
~
I, θ
i
)θ =
memo
look(N
i
, p (
~
X),
~
Iθ, θ
i
)
The above discussion shows how to resolve the tabled subgoal A
1
at N
i
against a program
clause using the PMF mode. T he same prin ciple can be applied to resolve A
1
with an answer tuple
~
I in T B(A
1
) and to resolve A
1
with a program clause when A
1
is a non -tabled subgoal. Therefore,
we have the following defin ition of resolvents for TP-resolution.
Definition 3.4 Let N
i
be a node lab eled by a goal G
i
= A
1
, ..., A
m
(m 1).
1. If A
1
is m emo
look(N
h
, p (
~
X),
~
I, θ
h
), then the resolvent of G
i
and θ
h
(θ
h
6= null) is the goal
G
i+1
= (A
2
, ..., A
k
)θ
h
, A
k+1
, ..., A
m
, where A
k
(k > 1) is the left-most subgoal of the form
memo
look(.).
Otherwise, let A
1
= p(
~
X) and C
p
be a program clause A B
1
, ..., B
n
with = A
1
θ.
2. If A
1
is a non-tabled subgoal, the resolvent of G
i
and C
p
is the goal G
i+1
= (B
1
, ..., B
n
,
A
2
, ..., A
k
)θ, A
k+1
, ..., A
m
, where A
k
is the left-most subgoal of the f orm memo look(.).
3. If A
1
is a tabled subgoal, the resolvent of G
i
and C
p
is the goal G
i+1
= (B
1
, ..., B
n
)θ,
memo
look(N
i
, p (
~
X),
~
Xθ, θ
i
), A
2
, ..., A
m
.
4. If A
1
is a tabled subgoal, let
~
I (
~
I 6= nul l) be an answer tuple in T B(A
1
), then the resolvent
of G
i
and
~
I is the goal G
i+1
= (A
2
, ..., A
k
)
~
X/
~
I, A
k+1
, ..., A
m
, where A
k
is the left-most
subgoal of the form memo
look(.).
We now discuss tabulated control strategies. Recall that Prolog implements SLD-resolution
by sequentially searching an SLD-tree using the Prolog control strategy (Prolog-strategy, for short):
Depth-first (for goal selection) + Left-most (for subgoal selection) + Top-down (for clause
selection) + Last-first (for backtracking). Let “register a node N
i
with G
i
be as defined by
Definition 3.2 except that the structure of N
i
only contains the pointer clause
ptr. Let return(
~
Z)
be a procedure that returns
~
Z when
~
Z 6= () and YES otherwise. Then the way that Prolog makes
SLD-derivations based on Prolog-strategy can be formulated as follows .
Definition 3.5 (Algorithm 1) Let P be a logic program and G
0
a top goal with the list
~
Y of
variables. Th e Prolog-tree T
G
0
of P {G
0
} is constructed by recursively performing the following
steps until the answer NO is returned.
1. (Root node) Register the root N
0
with G
0
+ return(
~
Y ) and goto 2.
2. (Node expansion) Let N
i
be the latest registered node labeled by G
i
= A
1
, ..., A
m
(i
0, m > 0). Register N
i+1
as a child of N
i
with G
i+1
if G
i+1
can be obtained as f ollows.
11
Page 11
Case 1: A
1
is return(.). Execute the p rocedure return(.), set G
i+1
= 2 (an empty
clause), and goto 3 with N = N
i
.
Case 2: A
1
is an atom. Get a program clause A B
1
, ..., B
n
(top-down via the pointer
N
i
clause
ptr) such that A
1
θ = . If no such a clause exists, then goto 3 with
N = N
i
; else set G
i+1
= (B
1
, ...B
n
, A
2
, ..., A
m
)θ and goto 2.
3. (Backtracking) If N is the root, then return NO; else goto 2 with its parent node as the latest
registered node.
Let ST
G
0
be the SLD-tree of P {G
0
} via the left-most computation rule.
4
It is easy to
prove that when P has the bounded-term-size property [19] and ST
G
0
contains no infinite loops,
Algorithm 1 is sound and complete in that T
G
0
= ST
G
0
. Moreover, Algorithm 1 has the following
distinct advantages: (1) since S LD-resolution is linear, Algorithm 1 can b e efficiently implemented
using a simple stack-based memory structure; (2) due to its linearity and regular sequentiality,
some useful control mechanism s, such as the well-known cut operator !, can be used to heuristically
reduce search space. Unfortunately, Algorithm 1 suffers from two serious problems. One is that it
is easy to get into infinite loops even for very simple programs such as P = {p(X) p(X)}, which
makes it incomplete in many cases. The second problem is that it unnecessarily re-applies the same
set of clauses to variant subgoals such as in the query p(X), p(Y ), which leads to unacceptable
performance.
As tabling has a distinct advantage of resolving infinite loops and redundant derivations, one
interesting question then arises: Can we enhan ce Algorithm 1 with tabling, making it free from
infinite loops and red undant computations while preserving the above two advantages? In the rest
of this subsection, we give a constructive answer to this question. We first discuss how to enhance
Prolog-strategy with tabling.
Observe that in a tabling system, we will have both pr ogram clauses and tables. For conve-
nience, we refer to answer tuples in tables as tabled facts. Therefore, in addition to the existing
policies in Prolog-strategy, we need to have the following two additional policies: (1) when both
program clauses and tabled facts are available, first use tabled facts (i.e. Table-first for program
and table selection); (2) when there are more than one tabled fact available, first use the one that
is earliest memorized. Since we always add new answers to the end of tables (see Definition 3.3
for memo(.)), policy (2) amounts to saying Top-down selection for tabled facts. This leads to the
following control strategy for tabulated derivations.
Definition 3.6 By TP-strategy we mean: Depth-firs t (for goal selection) + Left-most (for subgoal
selection) + Table-first (for program and table selection) + Top-down (for the selection of tabled
facts and program clauses) + Last-first (for b acktracking).
4
In [17], it is called an OLD-tree.
12
Page 12
Our goal is to extend Algorithm 1 to make linear tabulated derivations based on TP-strategy.
To this end, we need to review a few concepts concerning loop checking.
Definition 3.7 ([14] with slight modification) An ancestor list AL
A
of pairs (N, B) is associ-
ated with each tabled subgoal A at a n ode N
i
in a tree (see the TP-tree below), w hich is defined
recursively as follows.
1. If A is at the root, then AL
A
= {}.
2. If A inherits a subgoal A
(by copying or instantiation) from its parent node, then AL
A
=
AL
A
.
3. Let A be in the resolvent of a subgoal B at N
f
against a clause B
A
1
, ..., A
n
with Bθ = B
θ
(i.e. A = A
i
θ for some 1 i n). If B is a tabled subgoal, AL
A
= AL
B
∪{(N
f
, B)}; otherwise
AL
A
= {}.
We see that for any tabled subgoals A and A
, if A is in the ancestor list of A
, i.e. (
, A) AL
A
,
the proof of A needs the proof of A
. Particularly, if (
, A) AL
A
and A
is a variant of A, the
derivation goes into a loop . This leads to the following.
Definition 3.8 Let G
i
at N
i
and G
k
at N
k
be two goals in a derivation and A
i
and A
k
be the
left-most subgoals of G
i
and G
k
, respectively. We s ay A
i
(resp. N
i
) is an ancestor subgoal of A
k
(resp. an ancestor node of N
k
) if (N
i
, A
i
) AL
A
k
. If A
i
is both an ancestor subgoal and a variant,
i.e. an ance stor variant su bgoal, of A
k
, we say the derivation goes into a loop, denoted L(N
i
, N
k
).
Then, N
k
and all its ancestor n odes involved in the loop are called loop nodes. N
i
is also called the
top loop node of the loop. Finally, a lo op node is called an iteration node if by the time the node
is about to fail through backtracking, it is the top loop nod e of all loops containing the node that
were generated before.
Example 3.2 Figure 5 s hows four loops, L
1
, ..., L
4
, with N
1
, ..., N
4
their resp ective top loop
nodes. We see that only N
1
and N
4
are iteration no des.
Information about the ty pes and ancestors of nodes is the basis on which we make tabulated
resolution. Such information is kept in the structure of each node N
i
(see Definition 3.2). Th e
flag N
i
node
LOOP = 1 shows that N
i
is a loop node. The flag N
i
node IT ER = 1 shows
that N
i
is an (candidate) iteration node. Let A
1
= p(
~
X) be the left-most subgoal at N
i
. The flag
N
i
node
ANC = 1 represents that it is unknown whether A
1
has any ancestor variant subgoal;
N
i
node
ANC = 0 shows that A
1
has no ancestor variant subgoal; and N
i
node ANC = j
(j > 0) indicates that A
1
has ancestor variant subgoals and that C
p
j
is the clause that is being used
13
Page 13
d
d
d
dd
d
d
d
d
d
?
?
Q
Q
Qs
=
Q
Q
Qs
Q
Q
Qs
.
.
.
.
.
.
.
.
.
.
.
.
.
.
X
X
X
X
Xz
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
N
1
N
2
N
3
N
4
L
1
L
3
L
4
L
2
Figure 5: Loops, top loop nod es and iteration nodes.
by its closest ancestor variant subgoal (i.e., let A
h
at N
h
be the closest ancestor variant subgoal of
A
1
, then N
i
node
ANC = j represents that N
i
is derived from N
h
via C
p
j
).
Once a loop, say L(N
1
, N
m
), of the form
(N
1
: A
1
, ...)
C
p
j
1
(N
2
: A
2
, ...) ... (N
m
: A
m
, ...)
occurs, where all N
i
s (i < m) are ancestor nodes of N
m
and A
1
= p(
~
X) is the closest ancestor
variant subgoal of A
m
, we update the flags of all nodes, N
1
, ..., N
m
, involved in the loop by calling
the following procedure.
Procedure nodetype
update(L(N
1
, N
m
))
(1) For all i > 1 set N
i
node
LOOP = 1 and N
i
node IT ER = 0.
(2) If N
1
node
LOOP = 0, set N
1
node LOOP = 1 and N
1
node IT ER = 1.
(3) Set N
m
node
ANC = j.
(4) For all i < m set N
i
clause
SUSP = 1.
Point (1) is straightforward, where since N
1
is the top loop node of L(N
1
, N
m
), all the remaining
nodes in the loop cannot be an iteration node (see Definition 3.8).
If N
1
node
LOOP = 0, meaning that N
1
is not involved in any loop that occurred before,
N
1
is considered as a candidate iteration node (point (2)). A candidate iteration node becomes an
iteration node if the node keeps its candidacy by the time it is about to fail through backtracking
(by that time it must be the top loop node of all previously generated loops containing it).
Since A
1
is the closest ancestor variant s ubgoal of A
m
and C
p
j
is the clause that is being used
by A
1
, we set the flag N
m
node
ANC = j (point (3)).
As mentioned in Section 2, during TP-resolution w hen a loop L(N
1
, N
m
) occurs, where the
left-most subgoal A
1
= p(
~
X) at N
1
is the closest ancestor variant subgoal of the left-most subgoal
14
Page 14
A
m
at N
m
, A
m
will skip the clause C
p
j
that is being used by A
1
. In order to ensure that su ch a skip
will not lead to loss of answers to A
1
, we will do answer iteration before failing N
1
via backtracking
until we reach a fixpoint of answers. Answer iteration is done by regenerating L(N
1
, N
m
). This
requires keeping the status of all clauses being used by the loop nodes to “still available” dur ing
backtracking. Point (4) is used for such a purpose. After the flag N
i
clause SUSP is set to 1,
which indicates that N
i
is currently involved in a loop, the status of the clause being currently used
by N
i
will not be set to “no longer available” when backtracking on N
i
(see Case B3 of Algorithm
2).
Remark 3.1 We do answer iteration only at iteration nodes because they are the top nodes of all
loops involving them. If we did answer iteration at a non-iteration loop node N, we would have to
do it again at some top loop node N
top
of N , in order to reach a xpoint at N
top
(see Figure 5).
This would certainly lead to more redundant computations.
We are now in a position to define the TP-tree, which is constructed based on the TP-strategy
using the following algorithm.
Definition 3.9 (Algorithm 2) Let P be a logic program and G
0
a top goal with the list
~
Y of
variables. The TP-tree T P
G
0
of P {G
0
} is constructed by recursively performing the following
steps until the answer NO is returned.
1. (Root node) Register the root N
0
with G
0
+ return(
~
Y ), set NEW = 0, and goto 2.
2. (Node expansion) Let N
i
be the latest registered node labeled by G
i
= A
1
, ..., A
m
(m > 0).
Register N
i+1
as a child of N
i
with G
i+1
if G
i+1
can b e obtained as follows.
Case 1: A
1
is return(.). Execute the p rocedure return(.), set G
i+1
= 2 (an empty
clause), and goto 3 with N = N
i
.
Case 2: A
1
is memo
look(N
h
, p (
~
X),
~
I, θ
h
). Execute the procedure.
5
If θ
h
= null then
goto 3 with N = N
i
; else set G
i+1
to the resolvent of G
i
and θ
h
and goto 2.
Case 3: A
1
is a non-tabled subgoal. Get a clause C whose head is unifiable with A
1
.
6
If no such a clause exists then goto 3 with N = N
i
; else set G
i+1
to the resolvent of G
i
and C and goto 2.