Tabled Prolog - The University of Texas at Dallas

advertisement
Tabled Prolog
David S. Warren
XSB, Inc.
Stony Brook University
Outline
• Introduction
– Symmetric, Transitive Relations
• Basic Tabling Uses
–
–
–
–
Databases (and Datalog)
Grammars
Automata Theory
Dynamic Programming
• Advanced Tabling
– Evaluating Recursive Definitions
– Program Processing
• Interpreters
• Abstract Interpreters
• Beyond Simple Tabling
– Negation
– Aggregation
– Constraints
Family Relations
• Siblings in my family:
sibling(nancy,david).
sibling(david,jane).
sibling(jane,rick).
sibling(rick,emily).
• If my sister is my sibling, then I’m hers:
sibling(X,Y) :- sibling(Y,X).
– (symmetric, a problem in Prolog)
Symmetry
• Symmetric rule will always cause a loop in
Prolog.
– Why? (Explore the Prolog program…)
– What can we do to “fix” it?
• Prolog hackery: cuts, asserts, extra arguments, …
• Is there a more general/universal “fix”?
– What is the general problem to be fixed?
– Logic is OK, but Prolog’s evaluation is problemmatical.
Repeated Computation
• The problem is that Prolog repeats
computations again and again.
• So we can use “tables” to store the fact that
we’ve done a computation, and its results.
– Then if we’re about to do a computation and it
is already in the table, we just use the results
from there and don’t redo it.
Observations
• Does it solve sibling/2’s problem? (Explore)
• When will it eliminate loops in Prolog?
– Always?
– Sometimes?
• When? Can we say something general?
Transitivity
• If I am nancy’s sibling and jane is my
sibling, then jane is nancy’s sibling:
sibling(X,Y) :- sibling(X,Z), sibling(Z,Y).
• Add this rule to the Prolog program.
(explore)
• There is a problem here. Will tabling solve
it as well?
Tabling Intuition
• Prolog program executed by a growing and shrinking set
of virtual procedural machines:
– When calling a predicate, a machine duplicates itself
once for each matching clause.
– When an operation fails, that machine disappears.
• For tabling, when calling a predicate, look in table to see if
it’s already been called:
– If not, record the call in table, call it, and for each
machine that returns, record its answer with its call.
– If so, duplicate self for every answer, and suspend self
waiting for more answers; when one shows up,
duplicate self for it.
• Asynchonicity is necessary!
Summary
• Many simple rules cause Prolog to loop.
• Tabling eliminates redundant computation
by saving previous computations and their
results in a table.
• All programs that don’t use structures (lists,
or function symbols) will terminate under
tabled evaluation.
Basic Applications - Datalog
• Prolog without data structures is a natural relational
language: Databases
• Explore examples
• Extends relational databases by including recursion:
– supports transitive closure, span-of-control
• How does a DB Query language differ from a
Programming language?
– To be a “Database,” evaluation must be guaranteed to terminate.
Prolog evaluation doesn’t; Tabled Prolog does.
• Relational Databases include negation (or set difference.)
– With recursion, negation is more complicated.
– We’ll look at negation later
Context-free Grammars
• Easy to write grammars in Prolog:
– CFG Rule: A  B C
– Prolog Rule: a(S0,S) :- b(S0,S1),c(S1,S).
A
B
C
S0
S1
S
Input Str: …………………………………
CF Grammars
• Normally represent input Str as a list:
– Position is represented
– CF Rule: A  B t C
– Prolog rule:
a(S0,S) :- b(S0,S1), connect(S1,t,S2), c(S2,S).
With general “connect” fact (often called ‘C’/3):
connect([Term|S],Term,S).
Example CF Grammar
[Prolog has DCG preprocessor to add the “input variables”
to --> rules for convenience. (See example.)]
Simple Expression Grammar 1 (explore)
expr --> term, [+], expr.
expr --> term.
term --> factor, [*], term.
term --> factor.
factor --> [X], {integer(X)}.
factor --> ['('], expr, [')'].
CF Grammar Example 2
Simple Expression Grammar 2 (explore)
:- auto_table.
expr --> expr, [+], term.
expr --> term.
term --> term, [*], factor.
term --> factor.
factor --> [X], {integer(X)}.
factor --> ['('], expr, [')'].
What’s the difference from Example 1?
Why does it matter?
CF Grammar Discussion
• Prolog infinitely loops when given left-recursive
rules (parses by “recursive descent.”)
• Tabled Prolog handles all CFG’s (parses by “chart
parsing”, variant of “Earley recognition.”)
• Complexity?
– Polynomial (whereas rec desc is exponential)
– In theory cubic, if grammar is in Chomsky form
• But an issue with input representation as lists.
• For tabling, better to represent input with facts of form:
word(Loc,Word,Loc+1).
Grammar Questions
What we’ve seen is recognition: accepting or
rejecting input Str.
• Is this a Datalog problem?
• How do we parse? I.e., construct parse tree.
• Why can’t we do it in the same time as
recognition?
• Can we do it in same time as recognition +
linear time for each parse? How?
Grammar Parsing
• Consider grammar:
A  A A
A  a
:- auto_table.
• DCG for parsing:
a(r1(P1,P2)) --> a(P1), a(P2).
a(a) --> [a].
• Input: aaaaa…aaaaab
• Complexity, O(n³) but no parse!!
Parsing (better)
:- auto_table.
a --> a, a.
a --> [a].
a(r1(P1,P2),S0,S) :- a(S0,S1),a(S1,S),
a(P1,S0,S1), a(P2,S1,S).
a(a) :- ‘C’(S0,a,S1).
PTQ: A More Complex Grammar
• “The Proper Treatment of Quantification in
Ordinary English,” by Richard Montague
– “There are no significant differences between logical
languages and natural languages.”
– Proposed a formal grammar for (a fragment of) English,
and a formal (model theoretic) semantics!
– Examples:
• “John seeks a unicorn” vs. “John finds a unicorn”
• “John seeks a woman” de dicto/de re ambiguity
• “The temperature is ninety and rising” should not imply
“ninety is rising.”
• “Every man loves a woman” is ambiguous.
• … more …
Montague Grammar
• My Thesis, took 2-3 years to develop in Lisp
– With XSB, took 2-3 days…
• Syntax:
– Not Context-free, Left-recursive, infinitely many parses
(variants), …
– Complex parsing
• Semantics:
– By translation to Intensional Logic (a type theory)
– Required simplifications:
• β-reduction,
• “extensionalization” (explore…)
Automata Theory (cursory)
• Represent Finite State Machines by facts:
– Transition relation: m(MId,Q1,S,S2).
– Initial state: mis(MId,Qi).
– Final state: mfs(MId,Qf).
• Strs by facts:
– Str contents: Str(SId,Loc0,S,Loc1).
– Str length: Strlen(SId,Len).
FSA Accepts a String
accept(MId,StrName) :mis(MId,StateStart),
recog(MId,StrName,StateStart,StateFinal,0,StrFinal),
mfs(MId,StateFinal),
Strlen(StrName,StrFinal).
% regular transitions
recog(MId,StringName,MState0,MState,SLoc0,SLoc) :string(StringName,SLoc0,Symbol,SLoc1),
m(MId,MState0,Symbol,MState1),
recog(MId,StringName,MState1,MState,SLoc1,SLoc).
% Epsilon transitions
recog(MId,StringName,MState0,MState,SLoc0,SLoc) :m(MId,MState0,'',MState1),
recog(MId,StringName,MState1,MState,SLoc0,SLoc).
FSA Discussion
• Does recognition need tabling? Why or why not?
• Exercises: Write programs that:
– Generate an FSA equivalent to the intersection of two FSAs.
– Generate an epsilon-free FSA equivalent to a given FSA.
– Generate an deterministic FSA equivalent to a given FSA.
– Generate a minimal-state FSA equivalent to a given FSA.
• Can you write a program that determines whether the intersection of
languages of a CFG and an FSA is non-empty?
– Hint: Note the representation of a string is the same as that of an FSA
that recognizes exactly that string.
• What would be the difference in the programs written in Prolog vs. Tabled
Prolog?
Dynamic Programming
Knapsack Problem (trad.)
• Given a set of items, find whether a packing of a knapsack
with items with total weight w exists.
• Items numbered 1 to n: item(I,K) means item #I weighs K
:- table ks/2.
% ks(I,K) if a subset of items 1..I sums to K
ks(0,0).
% empty set sums to 0
ks(I,K) :- I>0, I1 is I-1, ks(I1,K).
% exclude Ith element
ks(I,K) :- I>0, item(I,Ki), K1 is K-Ki, % include Ith element
K1 >= 0, I1 is I-1, ks(I1,K1).
:- ks(n,w).
n
• O(2 ) queries to ks/2, but only O(n*w) different ones.
– explore
A General Evaluation Strategy
for Recursive Definitions
• Have seen examples of tabling as an
extension of Prolog evaluation.
• Now consider tabling in a more general
context:
– As a General Evaluation Strategy for
Recursive Definitions
• Functions and Evaluation
• Tabled Evaluation
• Multi-valued Functions and Relations
Mathematical Induction
• High school math class…
• Define functions on natural numbers
f(0) = 0
f(n) = f(n-1) + 2*n - 1
• We proved that f(n) = n²
• But how did we know f was well-defined?
• How did we evaluate it?
Evaluating Inductive Definitions
f(n) = if n=0 then 0 else n+f(n-1)
Top-down: 36 28 21 15 10 6
3
1
0
8 7 6 5 4 3 2
Bottom-up: 36 28 21 15 10 6 3
1
1
0 :n
0 : f(n)
• Evaluate f(8)
– Bottom-up evaluation
– Top-down (demand-driven) evaluation
: f(n)
Fibonacci
fib(n) = if n=0 then 1 else if n=1 then 1 else fib(n-1)+fib(n-2)
Top-down
8
5
3
2
1
1
: fib(n)
Bottom-up
5
8
4
5
3 2
3 2
1
1
0
1
:n
: fib(n)
• Bottom-up good for fib.
log2
log2: lg(n) = if n = 1 then 0 else 1 + lg(n div 2)
td 4
3
2 1 0 : lg(n)
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 : n
bu
4
3
3 3
3
3 3 3 3 2 2 2 2 1 1 0 : lg(n)
• Top-down is good for log2
Bottom-up vs. Top-down
Summary
• Bottom-up and Top-down evaluation are
“incommensurate”: neither one is uniformly
better than the other.
– Bottom-up is exponentially better than topdown for fib
– Top-down is exponentially better than bottomup for log2
• Can we get the best of both strategies?
Tabled Evaluation
• Top-down demand-driven, but:
– Save intermediate results in a table, so
– Future requests use the table.
• Combines top-down demand-driven with
bottom-up non-redundancy.
Tabled Evaluation (fib)
fib(n) = if n=0 then 1 else if n=1 then 1 else fib(n-1)+fib(n-2)
Top-down
w/ tabling
Bottom-up
8
5
3
2
1
1
: fib(n)
5
4
3
2
1
0
:n
8
5
3 2
1
1
: fib(n)
• Tabled evaluation similar to bottom-up on
fib.
Tabled Evaluation (log2)
log2: lg(n) = if n = 1 then 0 else 1 + lg(n div 2)
td w/
3
2
1 0 : lg(n)
tabl 4
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 : n
td
4
3
2
1 0 : lg(n)
• Tabled evaluation similar to top-down on
log2
A Theoretical Oddity?
• Tabled evaluation was proposed in 60’s by
D. Michie, but never pursued.
– Is the overhead too high?
– If a functional programmer is dumb enough to
write fib as doubly recursive, s/he gets what
s/he deserves! Write a better program.
• But …
On to Recursive Definitions
• Inductive definitions are:
– Defined on the natural numbers (or other wellfounded set)
– Required to be defined…
• Explicitly for minimal argument(s)
• In terms of smaller elements for non-minimal
arguments
• Recursive definitions aren’t!
New Problems with Recursive
Definitions
• Computationally problematical
– No ordering, so where is the “bottom” for
bottom-up evaluation?
– Demand evaluation loops, e.g., when f(17) =
……f(17)……
• Semantically problematical for functions
– May be no solutions: e.g., f(17) = f(17)+1
– May be many: e.g., f(17) = f(17)
One Approach:
Multi-valued Functions
• Permit functions to be multi-valued:
–
–
–
–
Result of a function is a set of values
Allow multiple “definitions” for a function
Functions are composed point-wise
Nondeterminism is a useful construct in a variety of
applications
• Naturally resolves semantic problems with selfloops:
– Define the least fixed point, on the lattice of sets
– f(17)=f(17) interpreted as f(17) = {}
Self-Loops and
Top-Down vs. Tabled Evaluation
• Self-loops, when definitions unfold to:
– f(17) = … f(17) …
• TD, not remembering anything, can’t avoid loops
in definitions with this form.
• Tabled can terminate those loops, since they don’t
contribute to defining a result, and look for other
ways to determine f(17).
• So tabled evaluation will terminate for definitions
for which TD will infinitely loop.
Recursive Definitions of
Relations
• Multi-valued functions?
fib(n) = if n=0 then 1 else if n=1 then 1 else fib(n-1)+fib(n-2)
• or Relations?
fib(0,1).
fib(1,1).
fib(N,F) :- N > 1, N1 is N-1, N2 is N-2,
fib(N1,F1), fib(N2,F2), F is F1+F2
• Differences:
– Syntax, Modes, Higher Order, …
– Prolog uses relations, and that is our interest here.
Programming Language
Implementations
• Programming Languages use recursive definitions
as programs and top-down evaluation as the
execution strategy.
• Evaluation of recursive definitions was (initially)
hard to implement
– Fortran didn’t implement it
– PL/1 said not to use it for efficiency reasons
• But it made programming MUCH easier
– E.g., C.A.R. Hoare’s experience with quicksort
Invention of Quicksort
(Reconstructed anecdote inspired by C.A.R. Hoare)
• Quicksort:
– Choose a “random” element from array
– Partition array with all elements greater than the chosen one to top
and all less to bottom
– Recurse on each partition
• Hoare invented and implemented it in Fortran,
explicitly handling all the stacks in arrays. Very
complicated and difficult.
• Was amazed at how “trivial” it became when it
was expressed as a recursive function in Algol60.
CLAIM:
• Tabled Evaluation can make relational
programming MUCH easier.
– As recursion made programming (and
algorithm development) much easier.
– And it ain’t that easy to implement either….
• (but that’s another talk)
Evidence: Applications
• Grammars and Automata Theory, as I hope
we have seen.
• Program Analysis
– Abstract Interpretation
– (Model Checking)
Homework Assignment 1:
Program Interpretation
• Use XSB to write an interpreter for Pascal (a
subset).
Hints:
– Represent state as a list of environments:
• An environment is a set of [variable,value] pairs
• State contains envs containing variables accessible at the
current program point: one env for each (statically)
enclosing block.
Example of
Program State Representation
prog P:
var A, B
proc Q:
var C, D
Program state at program point
[[E,F],[C,D],[A,B]]
proc R:
var E,F
beginR …call(Q)…
end
beginQ …call(R)…
end
beginP …call(Q)…
end.
[[C,D],[A,B]]
[[A,B]]
Abstract Syntax Tree
• You will be given a routine that, given a file
with Pascal program text, will return its
AST
• Each variable use will be represented in the
AST by its name and its “scope”
– Scope = 1 if local,
– Scope = 2 if declared in immediately enclosing block
– Scope = 3 if declared in next outer block …
More Hints:
• Write functions like:
– getVariableValue:
VarName × Scope × State  Value
– setVariableValue:
VarName × Scope × Value × State
 State
– interpExpr: AST × State  Value
– interpStmt: AST × State  State
Homework 1: (cont)
• In addition to submitting working code, please
answer the following discussion questions:
– How did you handle procedure invocation and return?
Describe in particular how the structure of the state was
changed?
– How did you use the nondeterministic aspects of the
XSB language? I.e., what would have been different
had you used Standard ML?
• Due Date: 2 weeks.
Francesco’s HW1 Submission
• On entry to a procedure:
– I created a new state by:
• taking a “tail” of the current state, keeping the envs for the block
where the called proc is declared,
• And adding a new env to the front for the proc being entered, with
(value) parameters initialized.
• On exit from a procedure:
– I replaced the “tail” of the state on entry by the tail of the state
returned from the procedure.
• I didn’t use the nondeterministic aspects at all.
– (I’ve got better things to do with my time than learn new irrelevant
languages. Is the Prof getting old and losing it?)
Homework 2:
Program Analysis
• Write an abstract interpreter for our Pascal
subset that will abstract integers to
even/odd. I.e., given any program, it
determines for each variable whether it will
contain only even integers or only odd or
might contain either.
– Extra credit: Use the same idea to determine for
each variable whether it might be used before it
is assigned a value.
Homework 2:
Discussion Questions
• How did you use your program for assignment 1?
– What did you keep and what did you change?
– Will your abstract interpreter terminate for every input
Pascal object program? Why or why not?
– How did you use the nondeterministic aspects of the
tabled Prolog language? I.e., what would have been
different had you used Standard ML?
• Due Date: tomorrow morning!
Francesco’s HW2 Submission
• I just abstracted integer constants to even/odd, and
changed each operation on integers to be an operation on
even/odd. E.g. even+odd=odd, even*odd=even, etc.
– The problem was comparisons, but if I couldn’t tell the result, I
just returned both true and false. E.g. odd=even returned false, but
even=even returned both true and false, as did even<odd, etc.
– I didn’t change ANYTHING ELSE! Evidence for Claim
• Extra credit: I got it! Vars start uninitted. Constants are
initted; Result is initted if both operands initted. EASY!
Francesco’s HW2 Submission
(cont)
• It terminates for every program I gave it. I think it
will always terminate, but I’m not exactly sure
why.
• No way could I have done this by this morning in
Standard ML. No way!
– The XSB language and tabled evaluation made it work.
(Maybe the Prof isn’t losing it…. yet.)
HW2 Discussion
• Without tabled evaluation, it would loop in
while statements, and in recursive
procedures.
• Does it always terminate under tabled
evaluation? Why?
Yes, there are only finitely many states
(assuming the abstract domain of each variable is finite):
Each environment has a fixed number of variables;
Number of envs in any state is bounded by program nesting.
What did you produce in
Homework 2?
• An abstract interpreter for a block structured
procedural language.
• Does full inter-procedural analysis
– Close to state-of-the-art
• Is “obviously” correct
• What does it not do?
– Use a user-defined lattice of abstract values
• It uses the subset lattice on values
• But with some more programming, can do that in XSB
Beyond Simple Tabling
• Negation
• Aggregation
• Constraints
Prolog and Negation
• Prolog has the \+ operator
– Semantics is “finite failure”
– Formalized as “Clark’s Completion”
• Tabled Prolog (finitely) terminates more often so
more negative goals are true
– E.g. all Datalog programs.
– Gives a simpler and more interesting theory of finite
failure
– What can its semantics be?
Negation and Tabling
• If no recursion through negation, no problem.
– Perfect model semantics
– Recall that DB (SQL) includes negation, but does NOT
have recursion
– But some (many?) programs are illegal.
• Problem with recursion through negation.
– What could
• p :- \+ p. mean?
• Prolog loops infinitely. Does that mean it has no meaning?
• Nonground negative calls are always problematic.
– Will assume/require that all negative calls are ground.
Negation
• The barber shaves everyone in town who doesn’t
shave himself:
shaves(barber,Y) :- resident(Y), \+ shaves(Y,Y).
resident(barber). resident(joe).
resident(dave). …
• I teach DB if Kifer doesn’t, and he teaches it if I
don’t:
teaches(warren,database) :- \+ teaches(kifer,database).
teaches(kifer,database) :- \+ teaches(warren,database).
• What might these mean?
Two Semantics?
• p :- \+ p.
– 3-valued semantics: true, false, and undetermined
– p is undetermined here
– Well-founded semantics
• Always exists, skeptical
• p :- \+ q. q :- \+ p.
–
–
–
–
2-valued semantics.
Here p: true, q:false; or p:false, q:true
Stable Model semantics
Multiple models, sometimes none.
• For first program, no SM; for second all are undet
in WF.
Properties of WF and SM
Semantics
• Stable Models
– NP-hard to compute (for propositional programs)
• Well-founded Semantics
– Polynomial to compute (quadratic, but often linear)
– “Relevant”, I.e., goal-directed computation possible.
– “approximates” stable models
• All SM’s agree on props that WF semantics determines
• XSB computes this semantics
– Uses SLG resolution
Digression:
XSB Tabling Builtins
• get_calls(?Goal,-Handle,?Vars)
– Unifies Goal with table calls, returns Handle to access
returns, and variables in Goal.
• get_returns(+Handle,?Vars,-AHandle)
– Binds Vars to successful returns for Handle.
– AHandle is optional; if given returns AHandle to access
delayed literals.
• get_delay_lists(+AHandle,-DelayLists)
– Binds DelayLists to a list of lists of delayed literals.
– A literal is delayed if it can’t yet be determined as true
or false.
• Now explore wfs.P
XSB and WF Negation
• XSB computes a residual program
– Ground original program
– Keep only “relevant” rules
– Eliminate any rule with:
• Positive body literal that is false in WFM
• Negative body literal that is true in WFM
– Eliminate body literals in remaining rules that are:
• Positive and false in WFM
• Negative and true in WFM
Residual Program
• Fact in residual program is true in WFM;
• Rule with nonempty body is undetermined in
WFM.
• Stable Model of residual program is a stable
model of the “relevant” portion of the original
program.
• XSB has xnmr package which uses Smodels (SM
computer) to compute various semantics of logic
programs with negation.
Aggregation
• Operations on elements in a table.
• E.g., minimum. Consider path:
dist(X,Y,D) :- edge(X,Y,D).
dist(X,Y,D) :- dist(X,Z,D1), edge(Z,Y,D2), D is D1+D2.
• Can we get shortest path?
– Idea: Before we return a distance, look in table to see if
there is already a smaller one for that path; if so, fail.
• Explore shortest_path.P
Constraints
• In Tabled Prolog, an answer is a set of bindings to
variables in the goal.
– Bindings are equality constraints.
– E.g., call p(a,X), answer p(a,b) can be understood as
p(a,X) where X=b.
• We can use more general constraints, e.g.,
– Answer: p(a,X) where X > 17.
• So computational state represents a set of current
constraints on the current set of variables.
– During computation, new constraints get added, and the
current set is simplified.
– If the current set becomes inconsistent, then failure.
CLP
• So this is Constraint Logic Programming
• What’s the difference between Prolog and Tabled
Prolog when general constraints are used?
– Constraints must be simplified (same as Prolog)
– Constraints must be associated with goals to be stored
in the table with answers
– Must handle constraints at:
• Call
• Return
Constraint Simplification
• XSB uses Constraint Handling Rules
– (CHR recently added to XSB by Tom Schrijvers)
– Used for Prolog constraint systems (CLP)
– Allows programmer to write rules that control
constraint simplification.
– CHR is a language to specify constraint rewriting and
simplification rules
• Are applied to the current set of constraints
whenever new ones are added.
Call
• What call to make?
– Project constraints on variables of the call:
• Take them all, or
• Weaken them, as eg, turn call of p(a,b,X) into
p(a,T,X),T=b.
– How to look up in table:
• One with equivalent constraints, or
• One with weaker constraints, as eg, given call of
p(a,b,X), could use call of p(a,T,X) if exists.
Return
• When new answer: p(X,Y) where
cons(X,Y), is produced:
– Add if new
– Or check if disjoining it with the answers
already there are equivalent to those already
there, and if so, don’t add.
• Generalization of: fail if it is implied by answer
already there.
Shortest Path revisited
• Consider >= as constraint.
ach_path(X,Y,D) :- edge(X,Y,D1), D >= D1.
ach_path(X,Y,D) :ach_path(X,Z,D1),
edge(Z,Y,D2),
D >= D1+D2.
• Answer D>=7 implies D>=5, so need keep only
D>=5 in table.
• So computing this with tabling computes the
shortest path.
XSB as View-Server
• Other applications may want access to tables
(views). They “subscribe”
– Views should be invalidated when any base fact
changes that (might) change the view.
– An application subscribing to a view should be notified
when it is invalidated.
• Allows XSB to serve as model in model-viewcontroller structured GUI
• XJ is a wrapper for Java Swing package that
allows it to use XSB this way.
• Makes data-centric applications very easy to build.
Conclusion
• You can do a lot of neat things in Tabled
Prolog
• XSB is a pretty good implementation of it.
• XSB is freely available from xsb.sf.net
• And learn more about tabling from a draft-y
book, available from:
http://www.cs.sunysb.edu/~warren/xsbbook/book.html
Download