Top Banner
Retroactive Subsumption-Based Tabled Evaluation of Logic Programs Fl´ avio Cruz and Ricardo Rocha ? CRACS & INESC-Porto LA, Faculty of Sciences, University of Porto Rua do Campo Alegre, 1021/1055, 4169-007 Porto, Portugal {flavioc,ricroc}@dcc.fc.up.pt Abstract. Tabled evaluation is a recognized and powerful implementa- tion technique that overcomes some limitations of traditional Prolog sys- tems in dealing with recursion and redundant sub-computations. Tabling based systems use call similarity to determine if a tabled subgoal will produce their own answers or if it will consume from another subgoal. While call variance has been a very popular approach, call subsumption can yield superior time performance and space improvements as it al- lows greater reuse of answers. However, the call order of the subgoals can greatly affect the success and applicability of the call subsumption technique. In this work, we present an extension, named Retroactive Call Subsumption, that supports call subsumption by allowing full sharing of answers between subsumed/subsuming subgoals, independently on the order in which they are called. Our experiments using the YapTab tabling engine show considerable gains in evaluation time for some applications, at the expense of a very small overhead for the programs that cannot benefit from it. Keywords: Tabled Evaluation, Call Subsumption, Implementation. 1 Introduction Tabling [1] is an implementation technique that solves some of the shortcomings of Prolog systems based on the traditional SLD resolution method. Tabled reso- lution methods can considerably reduce the search space, avoid looping and have better termination properties than SLD resolution based methods. The tabling technique is a refinement of SLD resolution that stems from one simple idea: save intermediate answers from past computations so that they can be reused when a similar call appears during the resolution process. In a nutshell, first calls to tabled subgoals are evaluated as usual, using SLD resolution, but their answers are stored in a global data space, called the table space. Similar calls to tabled subgoals are then resolved by consuming the answers already stored in the table entry for the corresponding similar subgoal, instead of being re-evaluated against the program clauses. Call similarity thus determines if a subgoal will ? This work has been partially supported by the FCT research projects STAMPA (PTDC/EIA/67738/2006) and HORUS (PTDC/EIA-EIA/100897/2008).
13

Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

Mar 05, 2023

Download

Documents

Lindsay Grace
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

Retroactive Subsumption-Based TabledEvaluation of Logic Programs

Flavio Cruz and Ricardo Rocha?

CRACS & INESC-Porto LA, Faculty of Sciences, University of PortoRua do Campo Alegre, 1021/1055, 4169-007 Porto, Portugal

{flavioc,ricroc}@dcc.fc.up.pt

Abstract. Tabled evaluation is a recognized and powerful implementa-tion technique that overcomes some limitations of traditional Prolog sys-tems in dealing with recursion and redundant sub-computations. Tablingbased systems use call similarity to determine if a tabled subgoal willproduce their own answers or if it will consume from another subgoal.While call variance has been a very popular approach, call subsumptioncan yield superior time performance and space improvements as it al-lows greater reuse of answers. However, the call order of the subgoalscan greatly affect the success and applicability of the call subsumptiontechnique. In this work, we present an extension, named Retroactive CallSubsumption, that supports call subsumption by allowing full sharing ofanswers between subsumed/subsuming subgoals, independently on theorder in which they are called. Our experiments using the YapTab tablingengine show considerable gains in evaluation time for some applications,at the expense of a very small overhead for the programs that cannotbenefit from it.

Keywords: Tabled Evaluation, Call Subsumption, Implementation.

1 Introduction

Tabling [1] is an implementation technique that solves some of the shortcomingsof Prolog systems based on the traditional SLD resolution method. Tabled reso-lution methods can considerably reduce the search space, avoid looping and havebetter termination properties than SLD resolution based methods. The tablingtechnique is a refinement of SLD resolution that stems from one simple idea:save intermediate answers from past computations so that they can be reusedwhen a similar call appears during the resolution process. In a nutshell, firstcalls to tabled subgoals are evaluated as usual, using SLD resolution, but theiranswers are stored in a global data space, called the table space. Similar calls totabled subgoals are then resolved by consuming the answers already stored in thetable entry for the corresponding similar subgoal, instead of being re-evaluatedagainst the program clauses. Call similarity thus determines if a subgoal will? This work has been partially supported by the FCT research projects STAMPA

(PTDC/EIA/67738/2006) and HORUS (PTDC/EIA-EIA/100897/2008).

Page 2: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

produce their own answers or if it will consume from another subgoal. In gen-eral, we can distinguish two main approaches to determine similarity betweentabled subgoals: variant-based tabling and subsumption-based tabling.

In variant-based tabling, two subgoals are considered to be similar if theyare the same by renaming the variables. For example, subgoals p(X, 1, Y ) andp(Y, 1, Z) are variants because both can be made identical to p(V AR0, 1, V AR1)through variable renaming. In subsumption-based tabling, two subgoals are con-sidered to be similar if one subgoal subsumes the other. A subgoal R is subsumedby a subgoal S (or a subgoal S subsumes a subgoal R) if R is more specific thanS (or S is more general then R). For example, subgoal p(X, 1, 2) is subsumed bysubgoal p(Y, 1, Z) because there is a substitution {Y = X, Z = 2} that makesp(X, 1, 2) an instance of p(Y, 1, Z). Notice that, if R is subsumed by S, S willcontain in its table entry the full set of answers that also satisfy R and thus, Rcan reuse and consume answers directly from S.

In general, subsumption-based tabling can yield superior time performance,as it allows greater reuse of answers, and better space usage, since the answersets for the subsumed subgoals are not stored. However, the mechanisms toefficiently support subsumption-based tabling are more complex and hard toimplement, which makes variant-based tabling more popular within the availabletabling systems. To the best of our knowledge, until now, XSB Prolog was theunique system supporting subsumption-based tabling. The first implementeddesign was called Dynamic Threaded Sequential Automata (DTSA) [2], but waslater replaced by an alternative table space organization called Time-StampedTrie (TST) [3], that showed better space efficiency than DTSA.

Despite the good results and performance gains obtained with the DTSA andTST designs, both approaches suffer from a major problem: the order in whichsubgoals are called during a particular evaluation can greatly affect the successand applicability of the call subsumption technique. For example, consider againthe subgoals p(X, 1, 2) and p(Y, 1, Z). If p(X, 1, 2) is called after p(Y, 1, Z), thenp(X, 1, 2) will be able to consume answers from p(Y, 1, Z) tables. Otherwise, ifp(X, 1, 2) is called before, then no sharing will be possible, since answer reuseonly happens when more general subgoals appear before specific ones.

In this work, we present an extension to the original TST design, namedRetroactive Call Subsumption (RCS), that supports call subsumption by allowingfull sharing of answers between subsumed/subsuming subgoals, independentlyon the order in which they are called. The RCS proposal implements a strategythat allows retroactive sharing of answers among subgoals by means of selectivelypruning and restarting the evaluation of subsumed subgoals. In order to supportthis, we introduce the following main extensions for subsumption-based tabling:(i) a new algorithm to efficiently traverse the table space searching for subsumedsubgoals; (ii) a new table space organization, based on the ideas of the commonglobal trie proposal [4], where answers are represented only once; and (iii) anew evaluation strategy to selectively prune and restart the evaluation of tablednodes. We will focus our discussion on a concrete implementation, the YapTabsystem [5], but our proposals can be generalized and applied to other tabling

Page 3: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

systems. Notice that, in order to do this work, first we have ported, from XSBProlog to YapTab, the full code that implements the TST design1.

The remainder of the paper is organized as follows. First, we briefly introducethe main background concepts about tabled evaluation in YapTab. Next, wepresent the RCS proposal and discuss the main operational challenges involvedin its design. We then describe how we have extended YapTab to provide enginesupport for it. Finally, we present some experimental results and conclusions.

2 Tabled Evaluation in YapTab

Tabling consists of storing intermediate answers for subgoals so that they can bereused when a similar subgoal appears. Whenever a tabled subgoal is first called,a new entry is allocated in the table space. Table entries are used to keep track ofsubgoal calls and to store their answers. Each time a tabled subgoal is called, weknow if it is a repeated call by inspecting the table space searching for a similarcall. Within this model, the nodes in the search space are classified as either:generator nodes, if they are being called for the first time; consumer nodes, ifthey are repeated calls; or interior nodes, if they are non-tabled subgoals.

To support tabled evaluation, the YapTab design [5] extends the Warren’sAbstract Machine (WAM) [6] execution model with the following four operations:

Tabled Subgoal Call: this operation searches the table space looking for asubgoal S similar to the current subgoal C being called. If such subgoal isfound, C will be resolved using answer resolution and for that it allocatesa consumer node and starts consuming the set of available answers fromS. If not, C will be resolved using program clause resolution and for that itallocates a generator node, adds a new entry to the table space and initializesit with an empty set AC of answers.

New Answer: this operation checks whether a newly found answer a for agenerator node C is already in its table entry. If a is a repeated answer, theoperation fails. Otherwise, a new answer set A′

C = AC ∪ a is generated.Answer Resolution: this operation checks whether a consumer node C has

new answers available for consumption. If no answers are available, C issuspended and execution proceeds using a specific strategy [7]. Consumersmust suspend because new answers may still be found by the correspondingvariant/subsuming call S. Otherwise, given C’s last consumed answer, wedetermine the unconsumed answer set UC ⊆ AS and consume the next one.

Completion: this operation determines whether a subgoal S is completely eval-uated. If this is not the case, this means that there are still consumers withunconsumed answers and execution thus proceeds to one of such consumers.Otherwise, the operation closes S’s table entry, meaning that the full setof answers AS was found, and future variant/subsumed calls to S can thenreuse AS without the need to suspend.

1 We would like to thank Terrance Swift for his help in introducing us the XSB Prologcode that implements the TST design.

Page 4: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

In YapTab, tabled nodes are implemented as WAM choice points extendedwith some extra fields. Furthermore, YapTab associates a data structure, namedsubgoal frame, to generator nodes and another, named dependency frame, to con-sumer nodes. Each subgoal frame stores information about the subgoal, namelythe entry point to its answer set. Each dependency frame stores informationabout the consumer node, namely information for detecting completion. Bothsets of subgoal and dependency frames are connected in creation time orderforming a doubly-linked list.

3 Retroactive Call Subsumption

In this section, we present the RCS proposal in more detail, focusing the discus-sion on the new evaluation strategy that allows retroactive sharing of answersamong subgoals by means of selectively pruning and restarting the evaluation ofsubsumed subgoals. Pruning the evaluation of a subsumed subgoal R requiresknowing the parts of the execution stacks and respective choice points involvedin its computation, and then transforming R’s generator choice point in sucha way that it can consume the answers from the subsuming subgoal S, insteadof continuing its normal execution. We argue that there are two main types ofpruning situations from where any other situation can be derived. The first typeis external pruning and occurs when the subsuming subgoal S is an externalsubgoal to the evaluation of R. The second type is internal pruning and occurswhen S is an internal subgoal to the evaluation of R. Although the two basecases are very distinct, they share some side-effects, which we discuss next.

3.1 External Pruning

Consider the program that follows and the query goal ‘?- a(X), p(Y,Z)’.

:- use_subsumptive_tabling p/2.

a(X) :- p(1,X). p(1,3).a(X) :- ... p(X,Y) :- ...

Initially, a(X) calls p(1,X) which succeeds with {X=3}, and in the continu-ation p(Y,Z) is called (Fig. 1(a)). The call to p(Y,Z) then checks if there aremore specific subgoals being evaluated and it finds p(1,X). The subgoal framefor p(1,X) is thus marked as a consumer subgoal frame and its producer sub-goal field is set to point to the subgoal frame for p(Y,Z). Next, the choice pointfor p(1,X) is transformed from a generator node to a retroactive node, whichamounts to pruning p(1,X)’s current evaluation by updating the continuationalternative choice point field to a pseudo-instruction called retroactive resolution(Fig. 1(b)). Upon backtracking, this instruction will allow the retroactive nodeto transform itself in other types of nodes, as we will see.

After p(Y,Z) has completed, the evaluation backtracks to p(1,X) and, byexecuting the retroactive resolution instruction, it is detected that the producer

Page 5: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

(a) (b) (c)

a(X) Int

Choice PointStack

p(1,X) Loa

a(X), p(Y,Z)

p(1,X), p(Y,Z)

p(Y,Z)

X=3

a(X) Int

Choice PointStack

...

p(1,X) Ret

p(Y,Z) Gen

a(X), p(Y,Z)

p(1,X), p(Y,Z)

p(Y,Z)

X=3

a(X)

...

Int

Choice PointStack

...

p(1,X) Gen

p(Y,Z) Gen

...

Fig. 1. The base case for external pruning

subgoal has already completed. The choice point for p(1,X) is then converted toa loader node2 (Fig. 1(c)) in order to load from p(Y,Z) all the answers relevantto p(1,X) minus the answers previously found when the choice point was agenerator node (answer {X=3} in Fig. 1), therefore avoiding repeated answers.

In the previous example, the pruned evaluation of p(1,X) do not includedother choice points, just the generator node for p(1,X). The following examplemixes subsumptive with variant checks and introduces pruning over choice pointsbelonging to the subsumed subgoal.

:- use_variant_tabling [a/2, b/1], use_subsumptive_tabling p/2.

a(X,Y) :- p(1,X), b(Y). p(1,X) :- a(_,X).a(X,Y) :- ... p(1,X) :- b(X).b(1). b(2). p(X,Y) :- ...

The query goal to consider is ‘?- a(X,Y), p(Z,W)’ and the first part of theevaluation is illustrated in Fig. 2.

p(V0,V1)

top_gen

b(V0)

top_gen

SubgoalFrames

DependencyFrames

a(X,Y) Gen

Choice PointStack

p(1,X) Gen

a(_,X) Con

b(X) Gen

b(Y) Con

p(Z,W) Gen

a(V0,V1)

top_gen

p(1,V0)

top_gen

a(_,X)

top_gen

b(Y)

top_gen

a(X,Y), p(Z,W)

p(1,X), b(Y), p(Z,W)

a(_,X), b(Y), p(Z,W)

...

...

b(X), b(Y), p(Z,W)

X=1...

b(Y), p(Z,W)

Y=1...

p(Z,W)

Fig. 2. Before external pruning over choice points belonging to the subsumed subgoal

2 At the engine level, a loader node is implemented as a consumer node but withouta dependency frame, since loader nodes do not need to suspend.

Page 6: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

Execution starts by storing generator nodes for a(X,Y) and p(1,X). Next,the first clause of p/2 is executed and a consumer node for a( ,X) is allocated. Asno answers for this variant subgoal exist, a( ,X) is suspended and the executionbacktracks to p(1,X). The second clause of p/2 is then executed and subgoalb(X) is called, allocating a new generator node. In the continuation, a firstanswer for b(X) and p(1,X) is found, {X=1}, and execution proceeds with acall to b(Y). As subgoal b(Y) is a variant of b(X), a consumer node is createdand the answer {X=1} is consumed, thus generating a first answer for a(X,Y),{X=1,Y=1}. Finally, subgoal p(Z,W) is called and we proceed as in the previousexample for the subsumed subgoal p(1,X). But now, as the evaluation of p(1,X)includes other choice points, a( ,X) and b(X), they should be pruned. Figure 3shows the state of the computation after pruning. The prune action depends onthe choice point type and is discussed next in more detail.

Pruning Interior Nodes Interior nodes are related to normal Prolog execu-tion and can be easily pruned by ignoring them altogether. This approach, whilesimple, suffers from the problem of trapped choice points. A more complex solu-tion would involve modifications to the WAM garbage collector to collect unusedspace on the choice point stack.

Pruning Internal Consumers The consumer node for a( ,Y) must be explic-itly pruned as otherwise it might be resumed, if new answers are to be consumed,and incorrectly reactivate the pruned branch of p(1,X). For each pruned internalconsumer, we must thus delete its corresponding dependency frame.

Pruning Internal Generators The generator node for b(X) must be explicitlypruned as otherwise it might be incorrectly completed. For each pruned internal

p(V0,V1)

top_gen

SubgoalFrames

DependencyFrames

a(X,Y) Gen

Choice PointStack

p(1,X) Ret

a(_,X)

b(X)

b(Y) Ret

p(Z,W) Gen

a(V0,V1)

top_gen

b(Y)

top_gen

a(X,Y), p(Z,W)

p(1,X), b(Y), p(Z,W)

...

X=1

b(Y), p(Z,W)

Y=1...

p(Z,W)

Fig. 3. After external pruning over choice points belonging to the subsumed subgoal

Page 7: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

generator, we must thus remove its corresponding subgoal frame from the subgoalframes stack and alter its state to pruned.

Generally, when pruning internal generators, we have two situations: (i) thegenerator does not have consumers that are external to the computation of thesubsumed subgoal; or (ii) the generator has external consumers. The formersituation does not introduce any problem, but the latter origins orphaned con-sumers. In our example, the consumer node for b(Y) is external to the evaluationof p(1,X) and when pruning b(X), b(Y) becomes orphan.

Usually, a pruned generator is called again, during the evaluation of the sub-suming subgoal, and before the computation reaches any of the orphaned con-sumers. Once reactivated, the subgoal frame for the pruned generator is pushedagain into the top of the subgoal frame stack and its state altered to evaluat-ing. Then, the new generator node starts by consuming the previously generatedanswers and only then executes the program clauses.

Orphaned Consumers To deal with orphaned consumers, we use the samestrategy as for subsumed subgoals and transform them into retroactive nodes.Upon backtracking, they then become either: (i) a loader node, if the prunedgenerator was reactivated and has completed; (ii) a consumer node, if the prunedgenerator was reactivated but has not completed yet; or (iii) a generator node,if the pruned generator was not reactivated until then. This latter situation onlyoccurs in variant-based tabling, since in subsumption-based tabling, when thesubsuming call is executed it will necessarily either call the same or a moregeneral subgoal, reactivating a new producer for the orphaned consumers.

By default, orphaned consumers always keep their frames on the dependencyframe stack. The frame is only removed if the retroactive node turns into aloader or a generator node. If the retroactive node turns again into a consumernode, lazy removal of dependency frames allows us to avoid removing and allo-cating a new frame and the potentially expensive operation of inserting it on thedependency frame stack in the correct order (ordered by choice point address).

Lost Consumers A lost consumer is a retroactive node that will not be re-sumed through standard tabled evaluation, i.e., through backtracking or throughanswer resolution. When a lost consumer is not resumed, we might lose answersand incorrectly detect completion. As we will see next, to avoid that, we mustensure that all retroactive nodes are always resumed. While in the example ofFig. 3, both p(1,X) and b(Y) will be resumed by means of backtracking, thismay not be always the case. Consider, for example, the program on Fig. 4 andthe query goal ‘?- a(X,Y)’.

In this example, when the subsuming call p(X,Y) is executed, the generatornode b(1,X) will be pruned and the external consumer b(1,Y) (the center nodein the gray oval box) will be turned into a retroactive node and became a lostconsumer. Notice that b(1,Y) will be resumed neither trough backtracking, sinceit is not on the current branch, nor through answer resolution, since its prunedgenerator will not be reactivated.

Page 8: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

:- use_variant_tabling [a/2, b/2].:- use_subsumptive_tabling p/2.

a(X,0) :- p(1,X).a(0,Y) :- b(1,Y).a(X,Y) :- p(X,Y).

b(1,Y) :- a(_,Y).b(2,1).

p(X,Y) :- b(X,Y).a(_,Y)

top_gen

DependencyFrames

p(1,X)

top_gen

b(1,Y)

top_gen

a(X,Y)

p(1,X) b(1,Y)

b(1,X)

a(_,X)

p(X,Y)

b(X,Y)

a(_,Y)

X=0Y=0

X=1

true

X=2 Y=1

pruned by

Fig. 4. A lost consumer after an external pruning

Hence, when later the computation backtracks to a(X,Y) to attempt com-pletion, b(1,Y) still remains as a retroactive node. Clearly, to correctly detectcompletion, we must resume it in order to generate the answers {X=0,Y=0} and{X=0,Y=1}, as otherwise they will be lost. Therefore, to ensure that all retroactivenodes are resumed, we extended the completion operation to, while traversingthe dependency frame stack checking for new answers, also check for retroactivenodes, and resume the corresponding consumer node in both cases.

A more tricky situation may occur when a pruned subsumed subgoal R isalso a leader node3. In such situations, R will not attempt completion and wewill not be able to use the completion operation, as described above, to resumeany potential lost consumer. Instead, when resuming the computation in R, ifR is to be transformed into a loader node (this means that R is a pseudo-leadersince no dependencies to upper nodes exist), we also traverse the dependencyframe stack looking for younger retroactive nodes with unconsumed answers and,when that is the case, execution is first resumed in those nodes.

With these two simple extensions, our strategy is able to ensure that allretroactive nodes are always resumed.

Frontier Node A frontier node is a choice point that is external to the com-putation of a subsumed subgoal R but that is chained to a choice point that isinternal to the computation of R. In the example of Fig. 2, the choice point ofb(Y) is a frontier node. In order to avoid execution to step into the pruned branchof a subsumed subgoal R upon backtracking, in general, a frontier node mustbe updated and linked to R. In the example of Fig. 3, the choice point of b(Y)is linked to p(1,X). However, for cases where the subsumed subgoal appearsoutside the branch of the subsuming subgoal, there is no need to update thefrontier node. This is safe, because the branch including the subsumed subgoalwill only be resumed on consumers during completion and thus no backtrackingto previous choice points will occur as they were fully explored before.

3 The youngest generator node which does not depend on older generators is calledthe leader node. A leader node defines the next completion point.

Page 9: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

3.2 Internal Pruning

Internal pruning occurs when the subsuming subgoal S is internal to the evalu-ation of the subsumed subgoal R. In this type of pruning we want to keep onepart of R running, the one that computes S.

Our approach involves computing S using local scheduling4 [7], but withoutreturning answers to the environment of R, as it has been pruned. Instead, wejump directly to the choice point of R, which was transformed into a retroactivenode, and resume the computation there in order to consume the matchinganswers found by S. When resuming the retroactive node for R, it can becomeeither: (i) a loader node, if S has completed; or (ii) a consumer node, if S hasnot completed because it is not the leader node, i.e., the leader node is above R.

Notice that, when the completion operation is later attempted at the leadernode, the computation can still be resumed, as usual and without any specialhandling, at R or at the internal consumers of S, until no unconsumed answersare available. Moreover, the effects of pruning involving internal generators andexternal consumers discussed for external pruning, still apply to internal pruning.

Our engine also supports multiple internal pruning. Consider, for instance,that a subgoal R1 calls recursively internal subgoals R2, .., Rn until a subgoal Sis called that subsumes R1, R2, ..., Rn. In such cases, we ignore all intermediatesubgoals and answers are only pushed from S to R1, the top subgoal. For anexample, consider the query goal ‘?- p(1,X)’ and the following program:

:- use_subsumptive_tabling p/2.

p(1,X) :- p(2,X).p(2,X) :- p(X,_).p(X,Y) :- ....

Execution starts by storing generator nodes for p(1,X) and p(2,X), and thenp(2,X) calls p(X, ) that subsumes both p(1,X) and p(2,X). Pruning is donebetween the top subsumed subgoal p(1,X) and the subsuming subgoal p(X, )and the node for p(2,X) is ignored (Fig. 5(a)). The choice point for p(1,X) istransformed into a retroactive node and execution proceeds by applying localscheduling to evaluate p(X, ) (Fig. 5(b)).

Later, if p(X, ) completes, the computation is resumed at p(1,X) and theretroactive node is transformed into a loader node, thus loading the matchinganswers from p(X, ). If p( ,X) could not complete because it is not the leadernode, the evaluation still resumes at p(1,X) and the retroactive node is trans-formed into a consumer node, and for that it allocates a new dependency frameand inserts it in the proper order in the dependency frame stack.

4 Local scheduling is a scheduling strategy that tries to evaluate subgoals as inde-pendently as possible. The key idea is that whenever new answers are found, theyare added to the table space as usual but execution fails. Hence, answers are onlyreturned when all program clauses for the subgoal at hand were fully explored.

Page 10: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

(a) (b)

LocalScheduling

p(1,X) Ret

Choice PointStack

p(2,X)

p(X,_) Gen

p(1,X)

p(X,_)

p(1,X) Gen

Choice PointStack

p(2,X) Gen

p(X,_) Gen

p(1,X)

p(2,X)

...

...

p(X,_)

Fig. 5. Multiple internal pruning

4 Implementation Details

In this section, we describe implementation details worthy of note. First, we willdescribe some other topics related to pruning, next we present how the tablespace is organized, and, then, we give a brief overview of the algorithm used tosearch for subsumed subgoals.

From Consumers to Generators In order to be able to transform a consumernode into a retroactive node and then into a generator node, all consumer choicepoints are allocated, by default, as generator choice points. We are studying amore sophisticated solution that will uniformize the choice point representationof tabled nodes in order to simplify this problem.

External or Internal Each subsumptive subgoal frame was extended with twonew fields: start code and end code, that initially are standard WAM variables.The start code field is bound to an arbitrary value when the subgoal startsexecuting and unbound when the subgoal backtracks, therefore allowing us toeasily detect if the subgoal is in the current branch. The end code field is boundwhen a new answer is found, i.e., when the code has reached the end of a programclause, thus allowing us to easily detect if a pruned subgoal is external or internal.

To reconstruct the dependency tree of generators and consumers, we extendedboth subgoal and dependency frames with a new top gen field (see Figs 2 and 3).When a new frame is created, this field is set to point to the subgoal framecorresponding to the generator node whose code is in execution, if any. Thissubgoal frame is represented by a global variable that is updated when a newgenerator is called or when it reaches the end of a program clause. Dependencyframes save the value of this global variable in order to correctly restore it whena consumer node is resumed.

In order to detect if a subgoal S is external or internal to another subgoalR, the top gen links are traversed until: (i) R is reached and, in this case, S isinternal; or (ii) we reach a subgoal older than R and, in this case, S is external.

Page 11: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

Table Space In our subsumptive engine, all answers for a tabled predicate arestored in a Single Time Stamped Trie (STST) that is common to all subgoalscalls for the predicate. This approach reduces memory usage, allows easy sharingof answers between different subgoals and, in particular, allows us to efficientlyload answers from subsumed/subsuming subgoals. The STST keeps a time stampfor the last answer inserted and each subgoal frame keeps a time stamp for thelast answer generated or consumed. This time stamps are then used to easilycompute the answers to be considered when pruning a subsumed subgoal.

This approach also allows reusing the answers on the STST when a newsubgoal is called. As an example, consider that two unrelated (no subsumptioninvolved) subgoals S1 and S2 are fully evaluated. If a subgoal S is then called,it is possible that some of the answers on the STST match S even if S neithersubsumes S1 nor S2. Hence, instead of eagerly running the predicate clauses,we start by loading the matching answers already on the STST, which can beenough if, for example, S gets pruned by a cut. While this approach has someadvantages, it can lead to redundant computations if later, when running theprogram clauses, S generates more general answers than the ones initially loaded.

Searching Subsumed Subgoals Each subgoal trie node was extended witha new field called in eval which stores the number of subgoals, represented be-low the node, that are in evaluation. The subgoal trie path is incremented ordecremented when the subgoal enters or exists the computation, respectively.Our algorithm for searching subsumed subgoals then uses this field to quicklydiscard irrelevant trie branches as it descends the trie. The search is done bymatching the subgoal arguments through backtracking along the subgoal trie.On a successful match, the algorithm stores a continuation for an alternativenode before descending into the next trie level. If a match fails, a continuation ispopped from the continuation stack and the state of the computation is restored(bindings and the trie node). The matching works by the following rules. A non-variable term argument must always match with a non-variable trie symbol.Unbound variable term arguments can match any trie symbol and are bound tothe symbol before descending. When a variable term bounds to a trie variable,it must always match against the same trie variable on the following matches.

5 Experimental Results

In this section, we present some experimental results comparing our new RCSproposal with traditional call subsumption. The environment for our experimentswas an Intel Core(TM) 2 Quad 2.66 GHz with 4 GBytes of memory and runningthe Linux kernel 2.6.31 with YapTab 6.0.3 and XSB Prolog 3.2.

First, we measured the RCS overhead for programs that do not take advan-tage of it, i.e., programs that never call more general subgoals after specific ones,and for that we used a set of benchmark programs downloaded from the XSBProlog repository5 with different configurations of data (see Table 1).5 http://xsb.cvs.sourceforge.net/viewvc/xsb/xsbtests

Page 12: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

Program/Data RCS CS/RCS XSB/RCS

right first

binary tree 170 0.94 0.96chain 2,900 0.99 1.10grid 14,456 1.18 1.20

pyramid 11,520 1.00 1.01

left last

binary tree 146 0.93 0.96chain 3,068 0.93 1.24grid 13,356 1.00 1.28

pyramid 3,260 1.08 0.90

double lastbinary tree 952 0.94 1.03

chain 2,912 0.90 1.41

samegenbinary tree 8,272 0.97 1.20

chain 44 1.18 0.64

Average 1.00 1.08Table 1. RCS running times on programs that do not benefit from it

Table 1 shows the running time, in milliseconds, for YapTab using RCS (col-umn RCS), and its ratio compared with traditional call subsumption for bothYapTab (column CS/RCS) and XSB Prolog (column XSB/RCS). Our resultsshow that, for this set of programs, RCS support adds a very small overhead torunning time when compared with traditional call subsumption, and for someprograms it can even run faster, probably due to cache behavior effects.

Next, we tried some benchmarks where RCS was expected to perform better.We used a path/2 program, left and doubly recursive variants, to compute thequery goal ‘?- path(X,1)’ and also experimented a reach/2 program with threedifferent transition relation graphs used in model-checking applications.

From Table 2, we can observe that for some path/2 benchmarks, RCS per-forms worse, possibly because the time saved by pruning evaluation branchesdoes not pay the incurred overhead in traversing the new STST table organiza-tion to collect relevant answers. For the model-checking benchmarks, RCS per-formance is notoriously better than traditional call subsumption, with speedupsreaching 2.18 for YapTab and 4.33 for XSB. For these benchmarks, the perfor-mance impact of using the STST is much smaller when compared to the timesaved by pruning evaluation branches of subsumed subgoals.

6 Conclusions and Further Work

We have presented a new tabling extension called Retroactive Call Subsumptionthat supports full sharing of answers between subsumptive subgoals, regardlessof the order in which they are called, and we have described the main conceptsand operational challenges of its design in the context of the YapTab system.

Initial experiments comparing our proposal with traditional call subsumptionsemantics, showed low overheads when executing standard programs and goodresults when applied to tabled programs that can benefit from it. Further workinvolves refining the system, testing it against more real-world applications, andstudying the impact on performance and memory usage of new data structures,like the Single Time Stamped Trie.

Page 13: Retroactive Subsumption-Based Tabled Evaluation of Logic Programs

Program/Data RCS CS/RCS XSB/RCS

left first

binary tree 156 1.18 1.18chain 44 1.00 1.18grid 40 1.20 1.40

pyramid 200 0.92 0.96

double first

binary tree 784 1.62 1.46chain 2,916 0.95 1.24grid 2,132 0.97 1.30

pyramid 12,004 1.01 1.19

reach firstiproto 2,244 1.54 2.77leader 3,152 1.92 3.82sieve 19,997 1.94 1.96

reach lastiproto 2,300 1.51 2.77leader 3,128 1.94 4.33sieve 17,693 2.18 2.97

Average 1.42 2.01Table 2. RCS running times on programs that are expcted to benefit from it

As argued by Johnson et al. [3], for some programs it may be useful to losesome goal directness by means of call abstraction and, instead of calling a goalG, we may decide to call a more general goal G′ and then reuse the answers fromG′ to solve G. Our implementation already includes all the machinery necessaryto do that, which makes it a good framework to further support call abstractionby devising various analysis techniques of call patterns.

References

1. Chen, W., Warren, D.S.: Tabled Evaluation with Delaying for General Logic Pro-grams. Journal of the ACM 43(1) (1996) 20–74

2. Rao, P., Ramakrishnan, C.R., Ramakrishnan, I.V.: A Thread in Time Saves TablingTime. In: Joint International Conference and Symposium on Logic Programming,The MIT Press (1996) 112–126

3. Johnson, E., Ramakrishnan, C.R., Ramakrishnan, I.V., Rao, P.: A Space EfficientEngine for Subsumption-Based Tabled Evaluation of Logic Programs. In: Fuji In-ternational Symposium on Functional and Logic Programming. Number 1722 inLNCS, Springer-Verlag (1999) 284–300

4. Costa, J., Rocha, R.: Global Storing Mechanisms for Tabled Evaluation. In: Interna-tional Conference on Logic Programming. Number 5366 in LNCS, Springer-Verlag(2008) 708–712

5. Rocha, R., Silva, F., Santos Costa, V.: On applying or-parallelism and tabling tologic programs. Theory and Practice of Logic Programming 5(1 & 2) (2005) 161–205

6. Warren, D.H.D.: An Abstract Prolog Instruction Set. Technical Note 309, SRIInternational (1983)

7. Freire, J., Swift, T., Warren, D.S.: Beyond Depth-First: Improving Tabled LogicPrograms through Alternative Scheduling Strategies. In: International Symposiumon Programming Language Implementation and Logic Programming. Number 1140in LNCS, Springer-Verlag (1996) 243–258