Computational Logic:
(Constraint) Logic Programming
Theory, practice, and implementation
Abstract Specialization
and its Applications
- Many techniques exist for program specialization which provide
useful optimizations:
- Partial Evaluation has received considerable attention and has
been proved of interest in many contexts.
- Supercompilation is another very powerful technique for program
specialization.
- Abstract Specialization (the topic of this talk!)
- Its main features are
- the knowledge
which is exploited is the so-called
static data, which corresponds to (partial) knowledge at
specialization (compile) time about the input data.
- Data which is
not known at specialization time is called dynamic.
- The program is optimized by performing at specialization time
those parts of the program execution which only depend on static
data.
- Has been applied to many programming languages and paradigms
- Two basic approaches have been addressed:
- On-line techniques
- Off-line techniques
- We have proposed Abstract Specialization, whose main ingredients
are:
- Abstract Interpretation for
- allowing abstract information
- performing fixpoint computations for computing (safe
approximations of) success substitutions.
- Abstract Executability for optimizing program literals
- Using the program induced by polyvariant abstract interpretation
- Minimizing the number of versions
- It is a generic technique. Different abstract domains can be
used which allow different information and optimizations.
- All four ingredients above are essential. Our system provides
the first practical implementation of a system with all the features
above.
- Abstract interpretation obtains information about the
run-time behavior of the program by
- simulating the execution using an abstract
domain which is simpler than the concrete one,
- performing fixpoint computations for recursive calls.
- An abstract domain
is the set of all possible
abstract semantic values.
- Values in the abstract domain are finite representations of a,
possibly infinite, set of values in the concrete domain (
).
and
are related via a pair of monotonic
mappings
:
- abstraction
- concretization
such that:
, and
.
i.e.,
conform a Galois insertion over
and
.
- Consider the Prolog program below
plus1(X,Y):- ground(X), Y is X + 1.
plus1(X,Y):- var(X), X is Y - 1.
- It defines the relation that the second argument is the first
argument plus one.
- It can be used when at least one of its arguments is
instantiated.
- Example executions:
- The call plus1(5, Result) computes the addition of 1 and
5 and assigns it to Result .
- The call plus1(Num, 3) determines which is the number
Num such that when added to 1 returns 3 (i.e., Num
= 3 - 1).
- The call plus1(3, 8) fails.
- Suppose we want to specialize the program below for the
initial query ?- p(2,Res).
p(Value,Res):- Tmp is Value * 3, plus1(Tmp,Res).
plus1(X,Y):- ground(X), Y is X + 1.
plus1(X,Y):- var(X), X is Y - 1.
- Using an appropriate unfolding rule, a partial evaluator would
compute the following specialized program:
p(2,7).
in which all computation has been performed at analysis time.
- Imagine we want to specialize the same program (repeated below)
but now for the initial query ?- p(Value,Res).
p(Value,Res):- Tmp is Value * 3, plus1(Tmp,Res).
plus1(X,Y):- ground(X), Y is X + 1.
plus1(X,Y):- var(X), X is Y - 1.
- Since Value is dynamic, we cannot compute Tmp
at specialization time.
- As a result, the call plus1(Tmp,Res) cannot be
optimized.
- Using a sensible unfolding rule, the specialized program
corresponds to the original one.
p(Value,Res) :-
true(( term(Value), term(Res), term(Tmp) )),
Tmp is Value * 3,
true(( arithexpression(Value), term(Res), num(Tmp) )),
plus1(Tmp,Res),
true((arithexpression(Value), arithexpression(Res),num(Tmp))).
plus1(X,Y) :-
true(( num(X), term(Y) )),
ground(X),
true(( num(X), term(Y) )),
Y is X+1,
true(( num(X), num(Y) )).
plus1(X,Y) :-
true(( num(X), term(Y) )),
var(X),
true(( num(X), term(Y) )),
X is Y-1,
true(( num(X), arithexpression(Y) )).
- The optimization above is based on abstract execution
- A literal
in a program
can be reduced to
the value
- true if its execution can be guaranteed to succeed only
once with the empty computed answer
- false if its execution can be guaranteed to finitely
fail.
- Consider program below with query ?- p(Res). and
plus1/2 is defined as usual. Note that the execution tree
of even/1 is infinite.
p(Res):- even(Tmp), plus1(Tmp,Res).
even(0).
even(E):- even(E1), E is E1 + 2.
- In order to compute some approximation of the success
substitution for even(Tmp) a fixpoint computation is
required.
- The information can be used to optimize the program as follows:
p(Res):- even(Tmp), Res is Tmp + 1.
even(0).
even(E):- even(E1), E is E1 + 2.
- The approach just shown is simple and can achieve relevant
optimizations
- However, opportunities for optimization quickly disappear if
polyvariance is not used
- Consider the following program:
p(Value,Res):-
plus1(Tmp, Value), Tmp2 is Tmp * 3, plus1(Tmp2,Res).
- note that two different calls for plus1/2 appear.
- The analysis information we now get is:
plus1(X,Y) :-
true(( term(X), term(Y) )),
ground(X),
true(( term(X), term(Y) )),
Y is X+1,
true(( arithexpression(X), num(Y) )).
plus1(X,Y) :-
true(( term(X), term(Y) )),
var(X),
true(( term(X), term(Y) )),
X is Y-1,
true(( num(X), arithexpression(Y) )).
- which no longer allows abstractly executing either of the two
tests.
- This can be solved by having two separate versions for predicate plus/3.
p(Value,Res):-
plus1_1(Tmp, Value), Tmp2 is Tmp + 3, plus1_2(Tmp2,Res).
plus1_1(X,Y):- ground(X), Y is X + 1.
plus1_1(X,Y):- var(X), X is Y - 1.
plus1_2(X,Y):- ground(X), Y is X + 1.
plus1_2(X,Y):- var(X), X is Y - 1.
- which allows optimizing each version separately as
plus1_1(X,Y) :- X is Y-1.
plus1_2(X,Y) :- Y is X+1.
- And even unfolding the calls to plus1/2 in the first
clause, resulting in:
p(Value,Res) :-
Tmp is Value -1, Tmp2 is Tmp+3, Res is Tmp2 + 1.
- Though in the example above it seems relatively easy,
- It is not straightforward in general to decide when to generate
additional versions.
- This problem is often referred to as ``Controlling
Polyvariance''.
- It has received considerable attention in different contexts:
program analysis, partial evaluation, etc.
- We have to enable as many optimizations as possible, but we have
to avoid:
- code-explosion
- or even non-termination!
- Naive heuristics: generate one version per call to
the predicate.
- Consider the following program:
p(Value,Res):-
plus1(Tmp, Value), plus1(Tmp,Tmp1), plus1(Tmp1,Tmp2),
plus1(Tmp2,Tmp3), plus1(Tmp3,Res).
- By generating multiple versions of plus1/2 we can
optimize them. Otherwise it is not possible.
- However, the expanded program would have 5 different
versions for plus1/2, when in fact only two of them are
needed.
- This shows that we have to avoid generating spurious versions.
- Consider the following program:
p(Value,Res):- q(Tmp, Value), Tmp2 is Tmp + 3, q(Tmp2,Res).
q(A,B):-
% may do other things as well
other(A,B), plus1(A,B).
other(A,B):- write(A), write(B).
- By using the naive approach only one version of plus1/2
will be generated. As a result, it cannot be optimized.
- The solution lies in generating two versions of q/2 in
order to create a ``path'' to the now separately specialized versions.
- This shows that we may need more versions than calls in the program.
- The expanded program is shown below:
p(Value,Res):-
q_1(Tmp, Value), Tmp2 is Tmp + 3, q_2(Tmp2,Res).
q_1(A,B):- other(A,B), plus1_1(A,B).
q_2(A,B):- other(A,B), plus1_2(A,B).
- This program can now be optimized to:
p(Value,Res) :-
q_1(Tmp,Value), Tmp2 is Tmp+3, q_2(Tmp2,Res).
q_1(A,B) :- other(A,B), A is B - 1.
q_2(A,B) :- other(A,B), B is A + 1.
<<580>>
- Goal-Dependent abstract interpretation aims at computing
both call and success abstract patterns
- In order to achieve as much accuracy as possible, most
(goal-dependent) abstract interpreters are polyvariant.
- Different call patterns for the same procedure are treated
separately.
- Different levels of polyvariance can be used with different
degrees of accuracy and efficiency (trade-off)
- In spite of analysis being polyvariant, the usual approach is to
``flatten'' the information corresponding to different versions
prior to using it to optimize the program.
- Many of the existing abstract interpreters for logic programs
are based on an and-or tree semantics a la Bruynooghe.
- There, analysis builds an and-or graph in which:
- or-nodes represent atoms (procedure calls). They are
adorned with a call and a success substitution.
- and-nodes represent clauses and are adorned with the
head of the clause they correspond to.
- The and-or graph is often not explicitly computed for
efficiency reasons.
- Thus, most optimizing compilers do not use the full and-or graph
but rather a description of procedures as call and success pairs.
- This eliminates multiple specialization, losing opportunities for
optimization.
- Since polyvariant analysis considers several versions of
procedures, this in effect corresponds to a polyvariant program:
- Each pair (procedure, call pattern) corresponds to a different
version.
- The call pattern for each literal uniquely determines the
version to use.
- Thus, the ``polyvariant'' program can be materialized.
- Each version is implemented with a different procedure name
- Renaming is performed so that no run-time overhead is incurred
to select versions.
- Even for relatively small programs, the number of versions
generated by analysis can be very large.
- It does not depend on whether the additional versions lead to
additional optimizations or not.
- Our systems includes a minimizing algorithm which guarantees that:
- the resulting program is minimal
- while not losing any opportunities for specialization
- In our experience, using the minimization algorithm the size of
the polyvariant program increases w.r.t. the original one, but does
not explode.
- Other possibilities need to be explored.
<<609>>
<605>>
- Parallelization process starts with
dependency graph:
- edges exist if there can be a dependency,
- conditions label edges if the dependency can be removed.
- Global analysis:
reduce number of checks in conditions (also to true and false).
- Annotation: encoding of parallelism in the target parallel
language:
g
(...), g
(...), g
(...)
figure=par_process_wide.ps,height=0.4
- Example:
qs([X|L],R) :- part(L,X,L1,L2),
qs(L2,R2), qs(L1,R1),
app(R1,[X|R2],R).
Might be annotated in &-Prolog (or Ciao Prolog), using local analysis, as:
qs([X|L],R) :-
part(L,X,L1,L2),
( indep(L1,L2) ->
qs(L2,R2) & qs(L1,R1)
; qs(L2,R2) , qs(L1,R1) ),
app(R1,[X|R2],R).
Global analysis would eliminate the indep(L1,L2) check.
figure=/home/clip/Slides/nmsu_lectures/par/Figs/apcompiler.ps,width=0.7
<583>>
- Dynamic scheduling allows dynamically ``delaying'' some calls
until their arguments are sufficiently instantiated.
- Dynamic scheduling increases the expressive power of
programs but it also has some time and space overhead.
- We aim at reducing as much as possible this additional overhead,
while preserving the semantics of the original program.
- We present two classes of program transformations:
- simplification of delay conditions.
- reordering delaying literals later in their rule body.
- Our aim is not to produce an order for the literals in a clause
such that dynamic scheduling is not needed anymore.
- Our aim is to reorder literals when:
- it does not alter the program semantics (search space)
- it reduces scheduling cost
- The search space of the reordered program may be larger than
that of the original program.
- At the limit, reordering may transform a finite, successful
computation into an infinite failure.
- Reordering a literal which definitely delays at the point where it is
may introduce an unbounded amount of slow-down.
- Consider the following example program and the query
?- delay_until(ground(Y),p(Y)), q(Y,Z).
q(Y,Z) :- Y=2, long_computation(Z).
q(Y,Z) :- Y=3, Z=5.
p(Y) :- Y=3.
- p(Y) delays in its position in the query.
- If we reorder the query, p(Y) does not delay after q(Y,Z). We can eliminate its delay condition.
- The reordered query ?- q(Y,Z), p(Y) performs the
long_computation while the original query does not.
- In on-line PE propagation of values and program transformation
are performed simultaneously.
- Done by means of unfolding, which has two effects:
- transforms the program,
- propagates the values of variables computed during the
transformation to other atoms in the node.
- Propagation can only be achieved through unfolding but:
- Unfolding is not always a good idea.
- Unfolding is not always possible.
The SLD tree may be infinite and we have to stop at some point.
- As soon as we stop unfolding, separate SLD trees are required.
- Thus, for most programs, several SLD trees exist.
- However, in PE there is no propagation between separate SLD trees.
- In summary, we would like to improve the propagation capabilities
of PE by allowing:
- propagation without transformation,
- propagation among different SLD trees (residual atoms).
- The advantages of And-Or graphs w.r.t. SLD trees are:
- Propagation does not require transformation. Success
substitutions are computed all over the graph.
- Even infinite computations are approximated using fixpoint
computations.
- There is only one global graph and propagation among different
atoms is possible and natural.
- In addition to concrete values, it can also work with other
interesting properties: types, modes, aliasing, etc.
- The advantages of SLD trees w.r.t. And-Or graphs are:
- Simpler to build. No abstract domain, no fixpoint required.
- Code-generation is straightforward.
- In order to integrate PE into AI we need
- an abstract domain (and widening operator) which captures concrete values,
- an algorithm for code generation from the and-or graph,
- a way of performing unfolding steps when profitable.
- The first two points are fully achieved.
- Several alternatives exist for the third one (see the paper).
- The currently implemented approach is very simple.
- More powerful unfolding mechanisms have to be tested.
<584>>
- From a partial evaluation perspective, both in logic
[GallagherCS88,Gallagher92] and functional programming [ConselK93].
- From an abstract interpretation perspective in [GiannottiH91] and
the first complete framework in [Winsborough92]. The first
implementation and evaluation in [PueblaH95].
- The drawbacks of PE for propagation are identified in
[LeuschelS96] and a study of advantages of the integration
presented in [Jones97].
- A first integration of AI and PE can be found in[PueblaHG97]
- An alternative formulation can be found in [Leuschel98]. Uses
the notions of Abstract Unfolding and Abstract
resolution.
- A general framework for the integration of abstract
interpretation and program transformation can be found in
[Cousot02].
- Use Abstract Specialization for compile-time assertion
checking.
- Use Abstract Specialization as a front end for an optimizing
compiler in the Ciao system.
- Further explore the application of Abstract Specialization for
Partial Evaluation tasks.
- Use our abstract interpreters for performing Binding Time
Analysis for off-line partial evaluation.
- The ASAP IST-2001-38059 FET project: Advanced
Specialization and Analysis for Pervasive Computing.
- In collaboration with Southampton and Bristol (UK) and Roskilde
(DK).
- Basic idea: use automated techniques for reusing
existing code in order to deploy it in resource-bounded systems.
- Program specialization has to be ``resource-aware''.
- The cost-benefit relation of optimizations has to be taken into
account.
- First result: An integrated system with the most advanced
specialization and analysis techniques in the (C)LP community.
| Feature |
PE |
AS |
| Information captured |
concrete |
abstract |
| Propagation of information |
unfolding |
abstract interpretation |
| Polyvariance control |
global control |
abstract domain |
| Guaranteeing termination |
generalization |
widening |
| Version selection |
renaming |
renaming |
| Materializing optimizations |
unfolding |
abstract executability |
| Fixpoint computations |
no |
yes |
| Propagation among atoms |
no |
yes |
| Infinite failure |
non observable |
observable |
| Low level optimization |
non-applicable |
applicable |
| Minimization of versions |
no/yes |
yes |
- Abstract Specialization is generic. Can be used for many
different kinds of information and optimization.
- Propagation of information is independent from performing the
optimizations
- Not restricted to source to source optimizations:
- abstract specialization generates the expanded program
- which can then be combined with a low level optimizer
- It allows achieving an appropriate level of polyvariance
- minimization allows reducing unnecessary polyvariance much
- this allows ``tentative'' polyvariance which can be backtracked.
- A fully fledged integration of traditional partial evaluation
and abstract specialization is most promising.
- 1
-
F. Bueno, D. Cabeza, M. Carro, M. Hermenegildo, P. López-García, and
G. Puebla.
The Ciao Prolog System. Reference Manual.
The Ciao System Documentation Series-TR CLIP3/97.1, School of
Computer Science, Technical University of Madrid (UPM), August 1997.
System and on-line version of the manual available at
http://clip.dia.fi.upm.es/Software/Ciao/.
- 2
-
F. Bueno, D. Cabeza, M. Hermenegildo, and G. Puebla.
Global Analysis of Standard Prolog Programs.
In European Symposium on Programming, number 1058 in LNCS,
pages 108-124, Sweden, April 1996. Springer-Verlag.
- 3
-
F. Bueno, M. García de la Banda, M. Hermenegildo, K. Marriott, G. Puebla,
and P. Stuckey.
A Model for Inter-module Analysis and Optimizing
Compilation.
In Logic-based Program Synthesis and Transformation, number
2042 in LNCS, pages 86-102. Springer-Verlag, March 2001.
- 4
-
M. Hermenegildo, G. Puebla, and F. Bueno.
Using Global Analysis, Partial Specifications, and an
Extensible Assertion Language for Program Validation and
Debugging.
In K. R. Apt, V. Marek, M. Truszczynski, and D. S. Warren, editors,
The Logic Programming Paradigm: a 25-Year Perspective,
pages 161-192. Springer-Verlag, July 1999.
- 5
-
M. Hermenegildo, G. Puebla, F. Bueno, and P. López-García.
Abstract Verification and Debugging of Constraint Logic
Programs.
In Recent Advances in Constraints, number 2627 in LNCS, pages
1-14. Springer-Verlag, January 2003.
- 6
-
M. Hermenegildo, G. Puebla, F. Bueno, and P. López-García.
Program Development Using Abstract Interpretation (and
The Ciao System Preprocessor).
In 10th International Static Analysis Symposium
(SAS'03), number 2694 in LNCS, pages 127-152. Springer-Verlag, June 2003.
- 7
-
M. Hermenegildo, G. Puebla, K. Marriott, and P. Stuckey.
Incremental Analysis of Logic Programs.
In International Conference on Logic Programming, pages
797-811. MIT Press, June 1995.
- 8
-
G. Puebla, F. Bueno, and M. Hermenegildo.
A Generic Preprocessor for Program Validation and
Debugging.
In P. Deransart, M. Hermenegildo, and J. Maluszynski, editors, Analysis and Visualization Tools for Constraint Programming,
number 1870 in LNCS, pages 63-107. Springer-Verlag, September 2000.
- 9
-
G. Puebla, F. Bueno, and M. Hermenegildo.
An Assertion Language for Constraint Logic Programs.
In P. Deransart, M. Hermenegildo, and J. Maluszynski, editors, Analysis and Visualization Tools for Constraint Programming,
number 1870 in LNCS, pages 23-61. Springer-Verlag, September 2000.
- 10
-
G. Puebla, F. Bueno, and M. Hermenegildo.
Combined Static and Dynamic Assertion-Based Debugging of
Constraint Logic Programs.
In Logic-based Program Synthesis and Transformation
(LOPSTR'99), number 1817 in LNCS, pages 273-292. Springer-Verlag, March
2000.
- 11
-
G. Puebla, M. García de la Banda, K. Marriott, and P. Stuckey.
Optimization of Logic Programs with Dynamic Scheduling.
In 1997 International Conference on Logic Programming, pages
93-107, Cambridge, MA, June 1997. MIT Press.
- 12
-
G. Puebla, J. Gallagher, and M. Hermenegildo.
Towards Integrating Partial Evaluation in a Specialization
Framework based on Generic Abstract Interpretation.
In M. Leuschel, editor, Proceedings of the ILPS'97 Workshop on
Specialization of Declarative Programs, October 1997.
Post ILPS'97 Workshop.
- 13
-
G. Puebla and M. Hermenegildo.
Implementation of Multiple Specialization in Logic
Programs.
In Proc. ACM SIGPLAN Symposium on Partial Evaluation and
Semantics Based Program Manipulation, pages 77-87. ACM Press, June
1995.
- 14
-
G. Puebla and M. Hermenegildo.
Automatic Optimization of Dynamic Scheduling in Logic
Programs.
In Programming Languages: Implementation, Logics, and Programs,
number 1140 in LNCS, Aachen, Germany, September 1996. Springer-Verlag.
Poster abstract.
- 15
-
G. Puebla and M. Hermenegildo.
Abstract Specialization and its Application to Program
Parallelization.
In J. Gallagher, editor, Logic Program Synthesis and
Transformation, number 1207 in LNCS, pages 169-186. Springer-Verlag, 1997.
- 16
-
G. Puebla and M. Hermenegildo.
Abstract Multiple Specialization and its Application to
Program Parallelization.
J. of Logic Programming. Special Issue on Synthesis,
Transformation and Analysis of Logic Programs, 41(2&3):279-316, November
1999.
- 17
-
G. Puebla and M. Hermenegildo.
Some Issues in Analysis and Specialization of Modular
Ciao-Prolog Programs.
In Special Issue on Optimization and Implementation of
Declarative Programming Languages, volume 30 of Electronic Notes in
Theoretical Computer Science. Elsevier - North Holland, March 2000.
- 18
-
G. Puebla and M. Hermenegildo.
Abstract Specialization and its Applications.
In ACM Partial Evaluation and Semantics based Program
Manipulation (PEPM'03), pages 29-43. ACM Press, June 2003.
Invited talk.
- 19
-
G. Puebla, M. Hermenegildo, and J. Gallagher.
An Integration of Partial Evaluation in a Generic
Abstract Interpretation Framework.
In O Danvy, editor, ACM SIGPLAN Workshop on Partial Evaluation
and Semantics-Based Program Manipulation (PEPM'99), number NS-99-1 in BRISC
Series, pages 75-85. University of Aarhus, Denmark, January 1999.
- Downloading ciao, ciaopp,
lpdoc, and other CLIP software:
Last modification: Thu Nov 23 00:08:03 CET 2006 <webmaster@clip.dia.fi.upm.es>