Definite programs, also called Horn Clause Programs, are those
programs without negation -- In XSB, this means without the
\+
/1, fail_if/1, not/1 or tnot/1 operators.
Consider the Prolog program
path(X,Y) :- path(X,Z), edge(Z,Y). path(X,Y) :- edge(X,Y). |
A number of approaches have been developed to address this problem by
reusing partial answers to the query path(1,Y)
[17,43,3,45,46]. The ideas behind these
algorithms can be described in the following manner. First, the
implementation keeps track of all calls to tabled predicates, (or
tabled subgoals such as path(1,Y) in the above example.
Whenever a new tabled subgoal is called, a check is first made to
see whether
is in the table. If so,
is resolved against
answers in the table; if not
is entered into the table and the
subgoal is resolved against program clauses, as in Prolog. Answers
are handled in the same way. When an answer to a tabled subgoal
is derived a check is made against the table for
to see if the
answer is there. If the answer isn't in the table for
, the answer
is added and scheduled to be returned to all instances where
has
been called; if the answer is already in the table, the evaluation
simply fails and backtracks to generate more answers.
Predicates can be declared tabled in a variety of ways. A common form
is the compiler directive
$XSB_DIR/examples
contains all code for the running examples in
this section. Consult the file into XSB and type the query
?- path(1,Y).and continue hitting semi-colons until you have exhausted all answers. Type the query again. Can you guess why the order of answers is different? Now type
?- abolish_all_tables.and retry the path query.
<ctrl>-C
if you go into an infinite loop).The return of answers in tabling aids in filtering out redundant computations - indeed it is this property which makes tabling terminate for many classes of programs. The same generation program furnishes a case of the usefulness of tabling for optimizing a Prolog program.
$XSB_DIR/examples
directory using the command.
?- load_dync(cyl.P).and then type the query
?- same_generation(X,X),fail.Now rewrite the same_generation/2 program so that it does not use tabling and retry the same query what happens? (Be patient -- or use
<ctrl>-C
).The examples stress two differences between tabling and SLD resolution beyond termination properties. First, that each solution to tabled subgoal is returned only once -- a property that is helpful not only for path/2 but also for same_generation/2 which terminates in Prolog. Second, because answers are sometimes obtained using program clauses and sometimes using answers, answers may be returned in an unaccustomed order.
In the language of tabling, the first instance of a tabled subgoal
is called a
subgoal, and is expanded using program clauses
as in SLD resolution (Prolog). Subsequent instances of
are
referred to as
subgoals and are expanded using answers in
the table for
instead of program clauses. Because
subgoals resolve against unique answers rather than repeatedly against
program clauses, tabling will terminate whenever (1) a finite number
of subgoals are encountered in query evaluation, (2) each of these
subgoals have a finite number of answers. Indeed, it can be proven
that for any program with the bounded term depth property
(roughly, where all terms generated in a program have a maximum
depth), SLG computation will terminate. These programs include the
important class of Datalog programs.