Efficient Leftmost Unfolding with Ancestor Stacks

The most successful unfolding rules used nowadays in partial evaluation of logic programs are based on well founded orders (wfo) or well quasi orders (wqo) applied over (covering) ancestors, i.e., a subsequence of the atoms selected during a derivation. The use of ancestor (sub)sequences improves the specialization power of unfolding while still guaranteeing termination and also reduces the number of atoms for which the wfo or wqo has to be checked. Unfortunately, maintaining the structure of the ancestor relation introduces a high operational cost during unfolding. In an attempt to facilitate the uptake of partial evaluation techniques, we herein present a very efficient unfolding based on the notion of covering ancestors which can be used in combination with any wfo or wqo as long as leftmost unfolding is performed, i.e., the leftmost atom of the goal is always selected for further unfolding. Our implementation technique is able to handle large unfolding trees more efficiently than existing state-ofthe-art partial evaluation systems. We believe that our approach makes well-known orderings, like homeomorphic embedding, more practically applicable. 1 Background and Motivation The main purpose of partial evaluation is to specialize a given program w.r. t. part of its input data—hence it is also known as program specialization. Essentially, partial evaluators are non-standard interpreters which evaluate expressions while enough information is available and residualize them otherwise. The partial evaluation of logic programs is usually known as partial deduction (PD) [11]. Informally, the PD algorithm proceeds as follows. Given an input program and a set of atoms, the first step consists in applying an unfolding rule to compute finite (possibly incomplete) SLD trees for these atoms; it returns the set of resultants (or residual rules), i.e., a program, associated to the root-to-leaf derivations of these trees. Then, an abstraction operator is applied to properly add the terms in the right-hand sides of resultants to the set of terms to be partially evaluated; the abstraction phase yields a new set of terms some of which may need further evaluation and, thus, the process is iteratively repeated while new terms are introduced. Following the terminology of [5], the so-called local control defines an unfolding rule which determines when and how to terminate the construction of the SLD trees. The global control defines an abstraction operator which guarantees that the number of trees is kept finite. This extended abstract is centered around the local control only (we refer to [9] for a survey on both control issues). In order to ensure the local termination of the PD algorithm while producing useful specializations, the unfolding rule must incorporate some mechanism to stop the construction of SLD trees. Nowadays, well-founded orderings (wfo) [4, 12] and well-quasi orderings (wqo) [14, 8] are broadly used in the context of online partial evaluation techniques (see, e.g., [5, 10, 14]). Intuitively, derivations are expanded as long as there is some evidence that interesting computations are performed but also guaranteed to terminate (according to the selected ordering). For instance, consider the following program which implements the wellknown “qsort” algorithm using difference lists. Given an initial query of the form ←qsort(List,Result,Cont), where List is a list of numbers, the algorithm returns in Result a sorted difference list which is a permutation of List and such that its continuation is Cont. For example, for the query ← qsort([1, 1, 1], L, []), the program should compute L=[1,1,1]. qsort([],R,R). qsort([X|L],R,R2) :partition(L,X,L1,L2), qsort(L2,R1,R2), qsort(L1,R,[X|R1]). partition([],_,[],[]). partition([E|R],C,[E|Left1],Right) :E <= C, partition(R,C,Left1,Right). partition([E|R],C,Left,[E|Right1]) :E > C, partition(R,C,Left,Right1). Fig. 1 illustrates an incomplete SLD-derivation for the above program and query, where predicates qsort and partition are abbreviated as qs and p, respectively. Each atom is labeled with a number (an identifier) and a superscript for future references. Further resolution steps are allowed as long as new selected atoms are strictly smaller—according to the homeomorphic embedding order [8]—than any previously selected atom in the same derivation. Therefore, the derivation stops prematurely when the atom 9, i.e., p([1], 1, L, L2), is found for the second time, since it is not strictly smaller than the atom 6 selected in the third step (indeed they are equal modulo renaming). State-of-the-art unfolding rules allow performing ordering comparisons over subsequences of the full sequence of the selected atoms of a derivation, achieving further specialization in many cases. To do so, they maintain dependencies over the selected atoms which are chosen in such a way that only a subsequence of 3 By abuse of notation, we keep the same number for each atom throughout the derivation although it may be further instantiated (and thus modified) in subsequent steps. This will become useful for continuing the example later.