On the Nonexistence of Optimal Scheduling Strategies for Tabled Resolution Prasad Rao C.R. Ramakrishnan I.V. Ramakrishnan Department of Computer Science SUNY at Stony Brook Stony Brook, NY 11794-4400
Abstract
Tabled resolution augments Prolog-style SLDNF resolution for evaluating normal logic programs. At a high level the central idea in tabled evaluation is to maintain all the subgoal invocations in a call table and their computed answers in an answer table. By using answer tables for resolving subsumed subgoal invocations (i.e. subgoals that are particular instances of other subgoals in the call table) tabled resolution strategies can prevent in nite looping that happens in Prolog-style evaluation. Thus termination properties of tabled resolution is substantially better than that of Prolog. Moreover, unlike Prolog, tabled resolution can also avoid redundant computations and hence improve the running time of programs. Resolving subsumed subgoals against answers may require accessing answer tables that are either complete or incomplete (i.e., more answers remain to be added). Since it is far more ef cient to retrieve from completed tables, scheduling strategies promote more frequent usage of such tables by exercising control over access to incomplete tables. The net eect is that depending on the scheduling strategy used, tabled logic programs can exhibit substantial variations in performance. In this paper we develop an abstract machine for tabled resolution. Based on this machine we formalize the concept of a scheduling strategy. We show that an optimal scheduling strategy does not exist. Our result has some interesting practical consequences. Firstly, scheduling strategies should be targeted to improve speci c classes of programs by suitably exploiting specialized knowledge of these classes. Secondly, the existence of such classes necessitates development of new compile-time analysis techniques for identifying them. Thirdly, implementations must provide mechanisms to
exibly support several scheduling strategies, each appropriate for some speci c class of programs.
Contact author: Prasad Rao E-mail:
[email protected] Tel: (516) 632-8470 Fax: (516) 632-8334
:- table a/2, p/2. a(X,Y) :- parent(X,Y).
6
p(X,Y) :- a(A,X),a(A,Y), X = Y. parent(1,3). parent(1,4). parent(4,5). parent(2,6). parent(2,7). .
(a)
1 Introduction
:- table p/3. p(A,B,C) :- body of p/3. q(X,Y) :- p(1,X,Y), p(1,X,B), p(A1,A2,A3). q(X,Y) :- p(2,X,Y). . . q(X,Y) :- p(n,X,Y).
(b)
Figure 1: Tabled Logic Programs
The last two decades have witnessed the development and application of numerous logic programming systems based on Prolog. While these systems demonstrate both the power and practicality of logic programming, de ciencies in Prolog's SLD evaluation mechanism (see [4] for introduction to SLD) have limited the full exploitation of the logic programming paradigm. For instance, SLD's susceptibility to in nite looping and redundant subcomputations render Prolog unsuitable as a query language for deductive databases. Prolog's weak termination properties have rendered its negation as failure rule inadequate for non-monotonic reasoning. Tabled resolution methods in logic programming address these shortcomings [2, 12, 3] . At a high level, top-down tabling systems evaluate programs by recording subgoals (referred to as calls ) and their provable instances (referred to as answers ) in a table. Predicates are marked a priori as either tabled or nontabled . Clause resolution, which is the basic mechanism for program evaluation, proceeds as follows. For nontabled predicates the subgoal is resolved against program clauses. For tabled predicates, if the subgoal is \already present" in the table, then it is resolved against the answers recorded in the table; otherwise the subgoal is entered in the table, and its answers, computed by resolving the subgoal against program clauses, are also entered in the table. For both tabled and nontabled predicates, program clause resolution is carried out using SLD. Thus by keeping track of which subgoals have been called along with their computed answers, tabled evaluation terminates on logic programs with nite models as well as avoids redundant subcomputations. Following the original formulation of tabled resolution in [12], we say that a subgoal t1 is present in the table if there exists another subgoal t2 in the table that subsumes t1 , i.e. t1 is an instance of t2 1 (e.g. f(a,Y) is an instance of f(X,Y)). Tabled resolution methods extend the power of logic programming. New applications, especially those involving deductive databases[1], non-monotonic reasoning and problems involving xpoint computations such as program analysis[6] and model checking[5], that were all beyond the reach of Prolog based systems have now been made feasible. Although the concept of tabled evaluation has been around for more than a decade, practical systems based on tabling are only beginning to appear. Early experience with these systems suggest that they are indeed practically viable. In particular the XSB system[10], based on tabled resolution, computes in-memory deductive database queries about an order of magnitude faster than current semi-naive methods, and computes Prolog queries with little loss of eciency when compared to well Implementations of tabled logic programming systems check for the presence of a subgoal in the table by a variant test. We say that two terms t1 and t2 are variants of each other if they are identical up to renaming of their variables. Variant checks are relatively inexpensive when compared to subsumption tests but result in poor reuse of the answer table. 1
1
a(1,Y1 ) 3
a(2,Y2) 6 a(4,Y 3) 5
7 7 4
t 24 t25
4
t 24 t 25
t 17 t 18 (4,3) t 19 t 20 t 21 (6,7) t 22 t 23
a(2,Y 4) 6
17
t18 t 19 (7,6) t 20 t 21 t 22 (6,7) t 23
t 1 p(X,Y) t2 a(A,X) t3 (1,3) t4 a(1,Y ) t5 (1,4) t6 a(1,Y1) t7 (2,6) t8 a(2,Y2) (4,5) t9 t 10 a(4,Y3 ) t 11 (2,7) t 12 a(2,Y4) t 13 3 t 14 4 t 15 (3,4) t 16 3
Increasing time
Increasing time
t 1 p(X,Y) t2 a(A,X) t3 (1,3) t4 a(1,Y ) t5 3 (1,4) t6 t7 t8 t 9 (4,3) (2,6) t 10 t 11 t 12 t 13 (4,5) t 14 t 15 t 16 (2,7) t
(3,4)
(a)
4 6 7 5 6 7
(7,6)
Calls and Answers
Calls and Answers
(b)
Figure 2: (a) Eager Consumption and (b) Delayed Consumption known Prolog systems [11] The relative novelty of table-based logic programming implementation has given rise to a number of both theoretical and practical questions related to improving performance. For a perspective on one such problem, note that there is a degree of freedom when resolving a subgoal against answers in the answer table. One can either resolve it immediately (i.e. as soon as the subgoal is called) against the answers in the table table or one can suspend it and resolve some other subgoal. Such a decision can cause variations in the performance of tabled logic programs as illustrated below.
1.1 Problem Illustration
Consider evaluation of the call p(X,Y) made to the tabled2 predicate shown in Figure 1(a). Figure 2 shows the sequence of calls made (a()'s and p()'s) and answers computed (the integers appearing singly or in pairs) by a tabling system for that call. Note that each column represents a speci c call made at a particular time followed by the sequence of answers computed for that call. For instance, the second column represents the call a(A,X) (made at time t2 ) and its answers (1,3), (1,4), (2,6), (4,5), (2,7) that were computed and recorded in the table at times t3 ; t6; t10; t13 and t16 respectively. Observe that when the call a(1,Y) is made at time t4 , it is subsumed by the call a(A,X) made earlier. Rather than recomputing the answers for a(1,Y) through program clause resolution we now resolve it against the answers computed for the call a(A,X) (the second column). The only answer computed so far for a(A,X) is (1,3) and so we record the rst answer Y=3 for a(1,Y) in its answer table (third column) at time t5 . The rest of the entries in Figure 2(a) are computed similarly. A few points pertaining to accessing answer tables for doing answer resolution deserve mention. Firstly notice that the set of answers to a subsumed call is a subsequence of the answers computed for the more general subsuming call. For instance, answers (Y2=6, Y2=7) to the call a(2,Y2) are 2
The table
a/2
directive in Figure 1(a) denotes that a is tabled
2
obtained from the subsequence of answers ((2,6),(2,7)) for the call a(A,X). Secondly, note that on invoking a subsumed call one can either resolve it immediately against the answers computed for the more general call (in which case the answer tables are eagerly consumed) or we can choose to suspend it (which will result in delayed consumption). Figures 2(a) and 2(b) illustrate the sequence of calls and answers generated by the former and latter choices respectively. A consequence of eager consumption is that incomplete3 answer tables may need to be accessed for performing answer resolution. For example, in Figure 2(a), at time t3 only the rst answer to the call a(A,X) has been computed. At time t4 the call a(1,Y) has to access this incomplete table. Accessing incomplete tables is expensive since answers to a subsumed call are to be retrieved from a dynamically growing answer table associated with the general call4 . On the other hand if we postpone doing answer resolution of a subsumed call until the answer table for the general call is complete then we only need to retrieve the answers from a static set. In fact extant implementations provide ecient retrieval mechanisms for complete tables by dynamically compiling them into code (see [7] for details). Therefore accessing completed tables is substantially less expensive than incomplete tables.(In Figure 2(b) all the calls subsumed by a(A,X) consume answers from its answer table only after it is complete.) So delayed consumption can result in consuming answers from completed tables and thereby improve eciency of table access. However delayed consumption can introduce new program resolution steps and easily oset these gains. For example, consider the calls resulting from the query q(X,W) made to the program in Figure 1(b). Assume that p(1,X,Y) succeeds with X bound to some constant . Suppose we defer the consumption of answers until completion of p(1,X,Y). Observe that we will end up exploring alternative paths of computation which will result in calls to p(2,X,Y), p(3,X,Y), . . . , p(n,X,Y). All of these calls are solved using program clause resolution. On the other hand by letting p(1,,B) eagerly consume answers, p(A1,A2,A3) will be called next. All of the calls p(2,X,Y), p(3,X,Y), . . . , p(n,X,Y) will be made later and will be solved by resolving against answers in the answer table of p(A1,A2,A3). Thus by deferring consumption of answers until completion of the answer table, we have increased the number of program clause resolution steps which could have been avoided by eager consumption. In addition, we also created answer tables for p(2,X,Y), p(3,X,Y), . . . , p(n,X,Y) and thus increased the table space for computing the query q(X,W). Since it is always more ecient to access completed tables, scheduling strategies can be formulated depending on how and when subsumed calls are allowed to access incomplete tables. By exercising control over the degree of access to incomplete tables scheduling strategies promote more frequent usage of completed tables. However, observe from the above examples that the same hprogram,queryi pair evaluated using dierent scheduling strategies can have dierent running times and table space requirements. The interesting question that arises is whether one can construct an optimal scheduling strategy that minimizes the running time (time for program and answer clause resolution) and table space. Our main result is that: such a scheduling strategy does not exist. In the rest of this paper we set up the formal machinery to prove this result. Speci cally in Section 2 we formalize an abstract operational model for an engine that evaluates tabled logic programs. The operational model provides us with (i) a high level view of tabled resolution and, (ii) the machinery to formally de ne a scheduling strategy. Section 3 presents proof of the non-existence of an optimal scheduling strategy. The proof relies on certain properties of the operational model. Discussion appears in Section 4. 3 4
An answer table is incomplete at any given instant if answers could potentially be added to it later. Recent work on ecient data structures for accessing incomplete tables appears in [9]
3
entry-point: Pcr-Loop loop if there are no more instructions to execute then Resume-Tabling-Engine else inst := next instr() case inst of New-Subgoal: invoke tabling engine to execute New-Subgoal with appropriate parameters New-Answer: invoke tabling engine to execute New-Answer with appropriate parameters Do-Completion-Check: invoke tabling engine to execute Do-Completion-Check with appropriate parameters default: execute(inst) endcase forever
The
Interface functions:
entry point: New-Subgoal entry point: New-Answer entry point: Do-Completion-Check entry point: Resume-Tabling-Engine tabling-engine-loop loop pick an action from Pending (* An action either (i) schedules a consumer, or (ii) checks if any more answers remain to be added to the producer's answer table *) execute action forever
()
The
pcr-engine
tabling-engine
Figure 3: An Abstract Machine for Tabled Resolution
1.2 Preliminaries
We assume familiarity with the standard logic programming de nitions of terms, formulas, predicates, clauses, horn clause logic programs, mgu, substitution, uni cation and subsumption[4]. We use t " t0 to say that t and t0 unify. For simplicity of exposition our technical development is based on de nite horn clause programs (i.e. no negative literals in clause bodies). This entails no loss of generality as we will show that our result also holds for normal logic programs. We use the notation ha1; a2; : : :an i to denote the sequence of terms a1 ; a2; : : :an . Following Prolog convention we use uppercase letters to begin variable names and lowercase letters to begin names of constants. The symbol \ " stands for an anonymous variable. a:-a1 ; a2; : : : ; an stands for the sequence of clauses a :- a1 . a :- a2 . . . . a :- an . We need the following concepts { A producer is a call, say p, to a tabled predicate whose answers are computed using program clause resolution. In other words p was not present in the call table at the time it was made. A consumer is a call p to a tabled predicate whose answers are computed using answer resolution. In other words p was subsumed by a more general call in the call table at the time the call to p was made. Each producer is associated with a unique answer table consisting of answers computed for it. We say that an answer table is complete whenever all the answers have been computed for the producer associated with the answer table. We will be interchangeably using producing call (consuming call) with producer (consumer) in this paper.
4
2 An Abstract Machine for Tabled Resolution We now describe an abstract machine for tabled resolution of logic programs. Our description captures the essential operational aspects of extant tabling engines such as those described in [8, 9]. We begin with an operational overview of the machine.
2.1 Operational Overview
Conceptually we can view any engine for evaluating tabled logic programs as having two main components, namely, the pcr-engine and the tabling-engine. The pcr-engine executes program clause resolution steps for nontabled calls as well as for producers. One can view the pcr-engine as a WAM [13] in which the standard instruction set is augmented with additional instructions to invoke the tabling-engine. The two primary functions of the tabling engine are: (i) insert into and retrieve items from the call and answer tables for doing answer resolution and (ii) schedule consumers based on the scheduling strategy. The pcr-engine and the tabling-engine communicate through four interface functions, New-Subgoal, New-Answer, Do-Completion-Check, Resume-Tabling-Engine and Pcr-Loop. The rst four are used only by the pcr-engine to invoke the tabling-engine while the last function is used by the tabling-engine to resume the pcr-engine. The pcr-engine suspends every time the tabling-engine is invoked. The function New-Subgoal is invoked whenever the pcr-engine encounters an instruction that corresponds to a tabled call, while New-Answer is invoked whenever it computes an answer for a producer. The Do-Completion-Check function is called by the pcr-engine when it has backtracked through all the clauses that de ne a tabled predicate. Its purpose is to check if any more answers can be added to the answer table associated with the tabled predicate. When the pcr-engine has nothing left to do, it resumes the tabling-engine invoking Resume-Tabling-Engine. Upon completely executing any of the New-Subgoal, New-Answer, and Do-Completion-Check functions, the tabling-engine can either resume the pcr-engine or execute the tabling-engine-loop. The tabling-engine can in turn resume the pcr-engine from this loop using Pcr-Loop. Recall that a consumer can either consume immediately from the answer table or is suspended and scheduled later on. For scheduling purposes we maintain a data structure called Pending within the tabling-engine. Also ecall that retrieving answers from completed tables is more ecient than accessing incomplete tables. Since the scheduler exercises control over incomplete table access, consumers that consume from completed tables are never suspended and hence never placed in Pending. In fact in implementations such consumers access completed tables via the pcr-engine. So only those consumers that consume from incomplete tables are added to Pending and are removed from it whenever they are scheduled to consume an answer. The tabling-engine marks tables as complete whenever no more answers remain to be added. It is convenient to do such completion checks by by placing the producers in Pending, since a producer is uniquely associated with an answer table. Whenever a producer is removed from Pending a completion check is done on its answer table. The computation halts when the tabling engine nds that Pending is empty. An abstract program corresponding to the above description appears in Figure 3. Note: At this point it is worthwhile highlighting the premise underlying the abstract machine which is: The scheduler only exercises control over access to incomplete tables. The implication is that the scheduler controls only those operations that pending consumers (of incomplete tables) directly depend on.
5
c a s f t
and p denote calls denotes an answer denotes a success continuation denotes a failure continuation denotes a table continuation
Consume-Answer(p,c,s,f,t)
(* c is subsumed by p *)
begin a,t' = next-answer(p,c,t) if(a = ) then Add do-consume(p,c,s,f,t') to Pending
h
Resume-Tabling-Engine() begin tabling-engine-loop() end New-Subgoal(c,s,f): begin p = call-check-insert(c) if( p = ) then (* c is not a producer *) Invoke pcr-engine for program clause resolution of c else (* p subsumes c *) if p's answer table is complete then (*accessing completed tables*) invoke pcr-engine for consuming the answers of c else Add do-consume(p,c,s,f,) to Pending tabling-engine-loop() endif endif end New-Answer(c,a,s,f)
i 6 ?
unify(c; a) Pcr-Loop(s)
else Add do-consume(p,c,s,,t') to Pending Pcr-Loop(f) endif
?
end Check-Complete(c,s)
(* c is a call *)
begin if c is complete then Mark c as completed Delete consumers of c from Pending Pcr-Loop(s) else if there is some pending program clause resolution of a dependent call then Add do-check-complete(c,) to Pending Pcr-Loop(s) else Add do-check-complete(c,s) in Pending tabling-engine-loop() endif endif end
(* a is an answer for c *)
begin if(answer-check-insert(c,a) = ) then Pcr-Loop(f) (* a already exists *) else unify(c,a) Pcr-Loop(s) endif end Do-Completion-Check(c,s) call Check-Complete(c,s)
?
(a)
(b)
Figure 4: Interface Functions (a) and Tabling Operations (b) for Eager Consumption
2.2 Tabling Primitives
The data structures that comprise the tables in the tabling engine are the call table and the answer tables. The call table consists of a set of terms C which represent producing calls. With each producer c 2 C we associate an answer table, denoted by answer table(c) which is the set of answer terms computed for c. We associate with every consuming call, a continuation, denoted table continuation, which is a set of all the answers that it has consumed so far. We impose an ordering on the set of answers in an answer table. This ordering captures the relative times at which answers were recorded 6
in the answer table. For instance a1 a2 means that a1 was inserted before a2 in the answer table. We require that with respect to all the answers in the table continuation of a consumer appear before any of the answers that remain to be consumed. We now de ne the primitives for table access. These primitives form the building blocks for the tabling operations and interface functions.
c): Determines whether a call c is present in the call table. If 9c0 2 C such that c subsumes c then call-check-insert(c) returns c0 else call-check-insert(c) returns ? after inserting c in C . Note that the use of this primitive ensures the uniqueness of call-check-insert( 0
every call in the call table. answer-check-insert(c; a): Determines whether a newly computed answer a for a call c is present in its answer table. If a 62 answer table(c) then answer-check-insert(c; a) succeeds after inserting a in answer table(c) else answer-check-insert(c; a) fails and returns ?. next-answer(p; c; t cont): For a producer p, and a consumer c that consumes from p's answer table and a table continuation t cont, this operation retrieves the next answer from the answer table if it exists, else it returns ?. Let Ap;c denote the set of answers in p's answer table that remain to be consumed by c. Then Ap;c = fa 2 answer table(p) ? t cont j a " cg. 8 if A 6= >> p;c >< hmin(Ap;c); t cont [ fmin(Ap;c)gi next-answer(p; c; t cont) = >
>> otherwise : h?; t conti
Intuitively, this table-primitive returns a pair whose rst component is an answer a which is not yet consumed by c and the second component is an updated continuation that contains a.
2.3 Tabling Operations
We now describe the tabling operations. In this description let prod denote a producer; cons a consumer of prod's answer table; s cont a success continuation; f cont a failure continuation; and t cont a table continuation. The function pick selects either a consumer or a producer from Pending. On selecting a consumer it schedules it for consumption; on picking a producer a completion check is done on its answer table. To do these two operations we need to maintain appropriate information with the producers and consumers in Pending. This is done as follows. Let do-consume(prod, cons, s cont, f cont, t cont) and do-check-complete( prod, s cont) denote a consumer and a producer in Pending augmented with such additional information. The tabling engine operates on these two elements of Pending with the operations Consume-Answer and Check-Complete respectively. For describing the Check-Complete operation we need the following notion. Formally, a call c is said to depend on another call c0 , (denoted by c ! c0), if c0 is called from within the body of c. We term c and c0 mutually dependent (denoted by c $ c0) if c ! c0 and c0 ! c. We denote by (c) the 0 0 set fc j c $ cg ( ! and $ are the transitive closures of ! and $ respectively. De nition 2.1 (Complete) A call c is complete if none of the calls in (c) have either pending program clause or answer clause resolution steps. We describe the two tabling operations below:
Consume-Answer(prod, cons, s cont, f cont, t cont): This operation is done on a do-consume element selected from Pending. The parameters of this operation are components of this
7
element. Consume-Answer enables cons to consume an answer from prod's answer table using t cont. It invokes pcr-engine with s cont or f cont depending on whether the consumption was a success or a failure. Check-Complete( prod, s cont): This operation is done on a do-check-complete element selected from Pending. The parameters of this operation are components of this do-check-complete element. Check-Complete checks if any more answers remain to be computed and added to prod's answer table. If it is complete then prod and its consumers are removed from Pending. So consumers accessing completed tables are never suspended. The pcr-engine is then invoked with s cont. Otherwise the do-check-complete element with updated continuations for prod is put back into Pending and will be tested again at a later time. If the answer table was incomplete due to pending program clause resolution of a producer, it resumes the pcr-engine with s cont, otherwise it executes the tabling-engine-loop. do-consume
2.4 Interface Functions
We now describe the ve interface functions. Let c denote a call; success continuation; f cont a failure continuation.
ans
an answer to c,
s cont
a
New-Subgoal(c, s cont, f cont): Speci es the operations to be performed by the tabling-engine for the tabled call c. The following operations are always done: it checks for the presence of a call c' which subsumes c in the call table using call-check-insert. If such a c' is present and the answer table of c' is incomplete it marks c as a consumer and adds it to Pending; otherwise it accesses the completed answer tables of c' via the pcr-engine. If no such c' is found it marks c as a producer and invokes pcr-engine immediately to compute answers for c. The actions to be taken on computing an answer for c is determined by the scheduling strategy.
New-Answer(c, ans, s cont, f cont): Adds the answer ans to the answer table (if it is not already present). The pcr-engine is invoked with either s cont and f cont depending on the scheduling strategy. Do-Completion-Check(prod, s cont): Invokes the Check-Complete operation with prod and s cont. Resume-Tabling-Engine: calls the tabling-engine-loop in the tabling engine. Pcr-Loop(cont): Resumes the pcr-engine.
2.5 Scheduling Strategies
Observe that only the speci cation of the function pick and certain actions that are taken in the functions New-Subgoal and New-Answer are dependent on the scheduling strategy. By specifying these actions and the function pick we obtain a scheduling strategy. Note that these are the only functions that are involved in determining how and when a consumer is scheduled. All the other interface functions and the tabling operations are independent of the scheduling strategy. We de ne a scheduling strategy as follows: De nition 2.2 (Scheduling Strategy) A Scheduling Strategy is a 3-tuple hP; NS; NAi where P is the rule for selecting an action from Pending, NS is the speci cation of New-Subgoal, NA is the speci cation of New-Answer. 8
One such tabling strategy, called eager is shown in Figures 4(a) and 4(b). It is eager because it never blocks consumers from consuming from incomplete tables. In this strategy the New-Subgoal either invokes program clause resolution for a producer, or places a consumer in Pending; New-Answer succeeds if the answer computed was not present in the answer table and invokes the pcr-engine with its success continuation, else it fails and invokes the pcr-engine with its failure continuation. The function pick is speci ed as follows: Pending is a queue and pick always picks the rst element of the queue.
3 Nonexistence of Optimal Scheduling Strategy We are now ready to prove our main results. For our proof we need to formally establish the following properties of our abstract machine. Lemma 3.1 Program clause resolution for a producer is never suspended within New-Subgoal. The proof immediately follows from the speci cation of New-Subgoal in Section 2.4. Lemma 3.2 Suppose q calls a producer p, and p fails without any answers. Further suppose that no call to any tabled predicate is made in the process of deriving answers for p. Then at the time of failure of p, its answer table is complete. Proof: Since no tabled predicate is called while deriving answers for p, New-Subgoal will not be invoked. Since p fails to produce an answer, New-Answer is not invoked. p fails only after backtracking through all of its clauses at which time the pcr-engine calls Do-Completion-Check. Since no tabled calls were made, (p), the set of calls mutually dependent on p has p as its only member. Clearly p does not have any remaining program or answer clause resolution steps. Hence the completion check on the answer table of p succeeds, and on success of the completion check the pcr-engine is invoked. (See Check-Complete operation in Section 2.3). Our proof technique requires following the concept of a trace generated by a scheduling strategy. De nition 3.1 (Trace) The trace generated by a scheduling strategy S while evaluating query q using program P , denoted tracehS;P;qi , is an ordered sequence of producers hp0 ; p1; : : :; pn i where the call pi is made before pj for all i and j such that i < j The trace of a program evaluation consists of all and only those subgoal invocations that are producers. We use traces to distinguish between scheduling strategies as follows. De nition 3.2 (Trace Equivalence) Let S and S 0 be two scheduling strategies. S and S 0 are trace equivalent i for all programs P and for all queries q , tracehS;P;qi = tracehS ;P;qi : We denote trace equivalence by =trace , i.e. S =trace S 0 means that S and S 0 are trace equivalent. We shall compare two strategies based on the running time and the table-space used for evaluating a query. We shall use timehS;P;qi to denote the time taken by strategy S for evaluating a query q using program P . De nition 3.3 (Uniformly Faster) We say that S is uniformly faster than S 0 if and only if for all programs P and queries q , timehS;P;qi < timehS ;P;qi Our proof relies on the properties of a predicate f de ned below. 0
0
:- table f/1. f(X) :- g(Y),fail.
In the above fragment g is a non-tabled predicate whose rules are a database of facts. Let ng denote the number of g facts is denoted by ng . Assume that f and g are in some program P . We establish the following properties of f . Lemma 3.3 Calls to f (X ) in P ( X is either bound or free) leave Pending unchanged. 9
Proof: If f (X ) is a producer, it fails without any answers and completes ( by Lemma 3.2), leav-
ing Pending unchanged. If f (X ) is a consumer then it accesses an empty complete table. Note that completed tables are accessed by the pcr-engine (see speci cation of Do-Completion-Check in Section 2.3). So it is never put in pending. If f (X ) is a producer, ( where X is either free or bound to some constant) then its evaluation results in completely backtracking through g 's database of facts. Let be the time taken to backtrack through this entire database of facts. is proportional to ng . We can make as large as we want by suitably choosing ng . Now we show that if two strategies are not trace equivalent then neither of them can be uniformly faster than the other. Theorem 3.1 Let S1 and S2 be two scheduling strategies such that S1 6=trace S2 Then neither S1 nor S2 are uniformly faster than each other. Proof: Without loss of generality we prove that S2 is not uniformly faster than S1 since the other case is symmetric. Since S1 6=trace S2 we can nd a program P and query q such that tracehS1 ;P;qi 6= tracehS2 ;P;qi . Either timehS1 ;P;qi < timehS2 ;P;qi or timehS1 ;P;qi timehS2 ;P;qi. In the former case we have nothing left to prove. In the latter case we proceed as follows. Let and be the calls where tracehS1 ;P;qi and tracehS2 ;P;qi rst dier ( is in the trace generated by S1 and is in the trace generated by S2 ). Let AB1 denote tracehS1 ;P;qi where A is the pre x of tracehS1 ;P;qi preceding and B1 is the sux of tracehS1 ;P;qi following . Similarly let tracehS2 ;P;qi be denoted by A B2 . We transform P to P 0 by adding the rules for f , the database of facts for g and two new rules R (based on ) and R (based on ) to P such that tracehS1 ;P ;qi = Af ( )B1 and tracehS2 ;P ;qi = A f (1)f (2) : : :f (k ? 1)f ( )B2 . R and R are so designed that when is called, either R alone is triggered or R is triggered before R ; similarly when is called, R alone is triggered or R is triggered before R. Let 0 denote in which all its variables are bound to new constants not in P (i.e. a ground instance of ). Similarly let 0 denote a ground instance of in which all its variables have been bound to constants not in P or 0 . Let R be the clause 0 :- f ( ) and R be the clause 0 :f (1); f (2); : : : ; f (k1); f ( ). Observe that if subsumes then 0 will not unify with , but uni es with 0 . Symmetrically, if subsumes then 0 will not unify with but 0 will unify with . We add R, R and the clauses of f and g (f and g are assumed to be new symbols that do not occur in P ) to the beginning of program P to get P 0 . To trigger R and R in the right order we place R before R if subsumes , otherwise we place R before R . (Note that if and are incomparable under subsumption then the order of insertion does not matter.) We will prove that (a) tracehS1 ;P ;qi = Af ( )B1 (b) tracehS2 ;P;qi = A f (1)f (2) : : :f (k ? 1)f ( )B2 . (c) is the dominating component in timehS1 ;P ;qi (d) k is the dominating component in timehS2 ;P ;qi 0
0
0
0
0
Proof of (a): In S the call immediately triggers R. This results in a producing call f ( ) 1
which is not postponed (by Lemma 3.1). The call f ( ) fails without computing any answers and returns. The Do-Completion-Check for its answer table succeeds (by Lemma 3.2). The success continuation of this Do-Completion-Check 10
Program P: :- table p/2, q/1. w(X) :- p(X,Y),p(a,W),q(a). p(a,b). p(a,c) :- q(b). q(a).
tracehEagerConsumption;P;w(X )i = hp(X; Y ); ; q(a); : : :i tracehDelayedConsumption;P;w(X )i = hp(X; Y ); q(b); : : :; i
Figure 5: Existence of strategies that are not trace equivalent operation, speci es that backtracking through the program clauses for resume from the next clause of P 0 whose head uni es with . This clause is either the rst clause in the original program P that uni ed with (denoted R0) or R . If this clause happens to be R a sequence of calls of the form f (i) are made. None of these calls are producers, and so do not enter the trace. They are calls which consume from f ( )'s completed table; Thus they are not placed in pending ( By Lemma 3.3). Their answer tables are empty and so each of those calls fails one after another at the end of which is resolved against R0 . (i.e. the point where clause resolution for started in the original program P ) All of the above operations did not change Pending, and hence did not aect the decisions made by the scheduling strategy. If either R or R are triggered after this, they do not aect the trace for the same reasons as given above. Proof of (b): The details of this proof are similar to the proof of (a) and hence omitted. Proof of (c): We can choose ng , the number of facts in the g's database, to make the evaluation of f ( ) the dominant part in timehS1 ;P ;qi. Proof of (d): Observe that f (1),f (2), . . . ,f (k?1),f ( ) are producers in tracehS2 ;P ;qi. Evaluation of each f (i) takes time and there are k such calls. Hence, k is the dominating part of timehS2 ;P ;qi. Hence 0
0
0
From (a), (b), (c) and (d) it follows that timehS2 ;P ;qi > timehS1 ;P ;qi { a contradiction. We have to show: Lemma 3.4 There exists at least two strategies that are not trace equivalent. Proof: Consider the evaluation of the program in Figure 5 for the query w(X) under eager consumption and delayed consumption strategies. When w(X) is called under eager consumption, a call to p(X,Y) results, which succeeds with an answer. Then p(a,W) is called which consumes an answer W = b from the incomplete answer table of p(X,Y). Next q(a) is called. However under delayed consumption, the consumer p(a,W) is postponed. This results in a producer q(b) being invoked from the second clause of p before the producer q(a). At this point their traces dier. Hence eager consumption and delayed consumption are not trace equivalent. Consequently there are at least two strategies that are not trace equivalent. Now we prove our main result. Theorem 3.2 (Nonexistence of Time-Optimal Scheduling Strategy) There exists no strategy S such that for all strategies S 0, S is uniformly faster than S 0 . 0
11
0
Proof: By contradiction. Let us assume there exists a strategy S that is optimal. By Lemma 3.4
we can nd S2 that is not trace equivalent to S . If S is optimal then S is uniformly faster than S2. However this contradicts Theorem 3.1. Finally, we can derive two easy results from the previous two theorems. Firstly we established our result for de nite horn clause logic programs. Since normal logic programs are a superset of de nite clause programs, Theorem 3.2 holds for normal logic programs also. Secondly, from the proof of Theorem 3.1 it is straightforward to show the nonexistence of a table-space-optimal scheduling strategy. We use the transformation in the proof of this theorem to obtain P 0 from P . Observe that the call table that results when S2 evaluates query q using program P 0 contains f (1), f (2),.. . ,f (k ?1). These calls are absent when S1 is used for evaluation instead.
4 Discussion Scheduling strategies are techniques devised to improve the performance of tabled logic programs by controlling access to incomplete tables. We showed that there is no scheduling strategy that can be uniformly better than any other strategy. Our result raises several intriguing questions. Firstly, note that the operation of suspensions and resumptions in constraint logic programming engines bear a certain degree of resemblance to similar operations in our abstract machine. Can one obtain similar results in the context of scheduling constraint logic programs? Our formulation of scheduling strategies is based exclusively on controlling access to incomplete tables since these types of accesses are considerably expensive. While our formulation re ects extant implementations it is conceivable that some other notion of a scheduling strategy can (and should) be used to re ect the needs imposed by other expensive operations (such as disk accesses by deductive databases.) Recall that our scheduling strategy never suspends program clause resolution for producers since the only reasonable argument that can be made for doing so is that another call that subsumes it may be made in the future. But this kind of information is not available at runtime. Availability of such information (obtained perhaps by compile-time analysis) can lead to an entirely new class of scheduling strategies. Finally, a note about variant tabling engines { the cost of accessing complete and incomplete tables are comparable in such machines. Hence it is imperative to identify the dominating costs in a variant engine, model them in an abstract machine along the lines of this paper and de ne a scheduling strategy to optimize such costs.
References [1] K. Apt, H. Blair, and A. Walker. Towards a theory of declarative knowledge. In J. Minker, editor, Foundations of Deductive Databases and Logic Programming, pages 19{88. Morgan Kaufmann, 1988. [2] R. Bol and L. Degerstadt. Tabulated resolution for well-founded semantics. In Proc. of the Symp. on Logic Programming, 1993. [3] W. Chen and D. S. Warren. Tabled evaluation with delaying for general logic programs. JACM, 43(1), 1996. [4] J. W. Lloyd. Foundations of Logic Programming. Springer, 1984. 12
[5] Y. S. Ramakrishna, C. R. Ramakrishnan, I. V. Ramakrishnan, Scott A. Smolka, Terrance Swift, and David S. Warren. Ecient model checking using tabled resolution (submitted to cav'97). Technical report, SUNY at Stony Brook, 1997. [6] C. R. Ramakrishnan, S. Dawson, and D. S. Warren. Practical program analysis using general purpose logic programming systems - a case study. In ACM Symposium on Programming Language Design and Implementation, 1996. [7] I.V. Ramakrishnan, P. Rao, K. Sagonas, T. Swift, and D.S. Warren. Ecient table access mechanisms for logic programs. In International Conference on Logic Programming, 1995. [8] R. Ramesh and W. Chen. A portable method of integrating SLG resolution into Prolog systems. In Proc. of the Symp. on Logic Programming, 1994. [9] P. Rao, C. R. Ramakrishnan, and I. V. Ramakrishnan. A thread in time saves tabling time. In Proc. of the Joint Int'l Conf. and Symp. on Logic Programming, 1996. [10] K. Sagonas, T. Swift, D.S. Warren, J. Friere, S. Dawson, and P. Rao. The XSB Programmer's Manual, 1993. [11] T. Swift and D. S. Warren. Analysis of sequential SLG evaluation. In Proceedings of the Symposium on Logic Programming, pages 219{238, 1994. [12] H. Tamaki and T. Sato. OLDT resolution with tabulation. In Third Int'l Conf. on Logic Programming, pages 84{98, 1986. [13] D. H. D. Warren. An abstract Prolog instruction set. Technical Note 309, SRI International, 1983.
13