Beyond the WAM: Topics in Contemporary Implementation

Terrance Swift

May 4, 2012

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 1: Overview and Miscellaneous Topics

Terrance Swift Topics in Logic Programming Implementation After the WAM

There are a lot of Prologs around: Sicstus, Quintus, YAP, Chao, SWI, GNU , B-Prolog, Mercury, HAL, ALS, XSB and many others Nearly every Prolog implements the WAM The WAM has been known for over 20 years ... so why are there a lot of Prologs?

Terrance Swift Topics in Logic Programming Implementation After the WAM

There is a lot more to Prolog than just the WAM Builtins for I/O, term manipulation, DCGs etc. Module systems Debuggers Dynamic code Libraries, interfaces, and packages: e.g. Interprolog [Cal04], lpdoc (Ciao [HtCG]), pl-doc (SWI) jasper, database interfaces, and many libraries, interfaces, etc. APIs for embeddability Memory management (garbage collectors) Arbitrary arithmetic – rational numbers Unicode and other extensions to readers Still, the main ISO standard has been around for 10 years [ISO95]

Terrance Swift Topics in Logic Programming Implementation After the WAM

Much of what keeps many Prologs around is research: Speed optimizations faster WAM execution (e.g. YAP [SC99, dSC06]) native-code compilation [Tay01, van92] (e.g. GNU Prolog [DP01b]) global analysis (e.g Ciao [MCH04], XSB [DRSS96]), indexing (e.g. YAP [], XSB [RRS+99]) Annotations and analysis for correctness Constraint libraries: CLP(), CLP(Q), CLP(FD), CLP(BN) [CC03], Various libraries based on Constraint Handling Rules. Parallelism, multi-threading, and “cluster” Prologs Changes to evaluation methods (e.g. tabling) Syntactic extensions: e.g. HiLog [CKW93, SW95] Semantic extensions: well-founded negation, Generalized Annotated Programs, Object-logics such as FLORA-2, preference logics, etc. Integration with other LP paradigms such as ASP (e.g. XASP [CSW, ARD08]),Terrance abduction, Swift Topics etc. in Logic Programming Implementation Focus of This Topic

We’ll discuss implementation issues arising from Making the WAM into a modern Prolog system Extending Prolog into new directions

Focus is on the XSB system (.sourceforge.net) It is a widely used Prolog with approximately 10,000 downloads from site a year since 2000, plus inclusions as a package in other systems – e.g. Debian It has most of the advanced features that other Prologs have It has some advanced features of its own It is partly a UNL product I know it.

Terrance Swift Topics in Logic Programming Implementation Tentative Overview

1 Overview: Exception Handling and a Taste of Speeding up the WAM 2 Tabling for Definite Programs: Variance and Subsumption; Scheduling Strategies 3 The SLG-WAM: Data Structures and Stack Changes; 4 The SLG-WAM: Completion, Registers and Instructions; Linear tabling 5 Tabling with Negation: Stratification Theories, SLG Resolution 6 The SLG-WAM: Implementation of Tabled Negation 7 Multi-threaded Prolog: ISO-multi-threading, the MT-SLG-WAM; Concurrent Completion and Shared Completed Tables, YAP Tabling. 8 Dynamic Rules and Facts: Incremental Tabling 9 Constraints and CHR; Tabled constraints; Answer Subsumption

Terrance Swift Topics in Logic Programming Implementation XSB Background

As a poor measure of system complexity XSB has: ˜ 84,000 lines of code in engine and support for builtins ˜ 14,000 Lines of Prolog code in ˜ 37,000 Lines of Prolog code for builtins and standard libraries ˜ 70,000 Lines of Prolog and C for packages (including constraint libraries) This is roughly the same as other leading open-source Prologs

Terrance Swift Topics in Logic Programming Implementation XSB Background

XSB is currently developed at Universidade Nova de Lisboa and State University of New York at Stony Brook. WAM has Code Space, Heap, Environment Stack, Trail and PDL Prolog systems typically contain other areas: Atom Tables, predicate/structure tables, findall buffers, and much else. XSB (and some other Prologs) splits Environment Stack into Environment Stack and Choice Point Stack The reason for the split is to make it easier to use the choice point stack for scheduling in tabled evaluations

Terrance Swift Topics in Logic Programming Implementation XSB Background

The code and algorithms discussed in these lectures were developed by (in alphabetical order) Luis de Castro, Baoqiu Cui, Steve Dawson, Ernie Johnson, Juliana Freire, Michael Kifer, Rui F. Marques, C.R. Ramakrishnan, I.V. Ramakrishnan, Prasad Rao, Konstantinos Sagonas, Diptikalyan Saha, Terrance Swift, David S. Warren and others. Terrance Swift Topics in Logic Programming Implementation Exceptions

How do you handle exceptions in C?

1 Declare a C variable of type jmp buf 2 use setjmp(jmp buf env) to assign a forward continuation (i.e. environment) referred to by env For example, if you wanted to longjump to the WAM instruction dispatch loop: if (setjmp(xsb abort fallback environment)) Restore the default signal handling; set P register to saved value else P = first instruction of boot module goto *instr addr table[*P]; at beginning of instruction dispatch loop. 3 use longjmp(xsb abort fallback environment,val) to pop C stack to proper environment — the instruction goes back in stack to look for an environment with address matching that maintained in the jmp buf env.

Terrance Swift Topics in Logic Programming Implementation Exceptions

ISO-style exceptions are an elegant part of Prolog and are often under-appreciated1 To throw an exception, call throw(Ball): Ball is simply a Prolog term To handle an exception, call a goal through catch(Goal,Ball,Handler) This calls Goal and if Goal throws an exception (via throw(Ball)) that unifies with Ball, call Handler if Goal throws an exception that does not unify with Ball nothing happens, the exception is handled by an ancestor catch Thus, there are three continuations in Prolog: forward (success), failure, and exception. Note that continuations may be removed via !/0. catch/3 important when a Prolog is part of a system: e.g. called from Interprolog, from within a Ruby, Delphi, or C process. 1Exceptions in XSB wereTerrance originally Swift implementedTopics in Logic by Programming B. Demoen Implementation Exceptions

How can exceptions be implemented? catch/3 is a little like a setjmp(), but relies on unification of Prolog terms, rather than matches of stack addresses. Go up Prolog’s environment stack until you find an environment Env that looks like a catch. Recall that WAM environments contain: A pointer to their parent environment A pointer to the byte-code for their continuation Various permanent variables (+ perhaps another pointer for Tabling) See if the thrown Ball unifies with something in Env if so reset stacks and call Handler if not, keep going up stack

Terrance Swift Topics in Logic Programming Implementation Exceptions

Here’s how we find the environment of a catch catch marker indicates that the current environment is that of catch/3 We aren’t yet addressing the unification of the ball with the second argument of catch/3

Terrance Swift Topics in Logic Programming Implementation Exceptions

find next catch() temp E = E find an environment that matches catch while (E and cp(E) != catch marker) temp E = parentEnv(E) if ( ! temp E) xsb exit(”Throw failed because no catcher for throw”)

search through choice points until you find the choice point whose cp E value is older than temp E set B to this value

search through choice points until you find the trail cell equal to cp TR(B) set TR to this value

return(FALSE);

Terrance Swift Topics in Logic Programming Implementation Exceptions

After interning the error ball, throw/1 finds the next catch/3 environment (if any) Stacks are set to this new environment so that when we fail (which acts analogously to longjmp()), we’ll take the failure continuation for catch/3 Recall from a few slides ago that xsb abort fallback environment puts you back to the beginning of the emulator.

throw(error term) Intern error term as exception ball(thread,error term) if (find next catch()) xsb exit(”find next catch() failed in xsb throw internal!”) /* Resume main emulator instruction loop */ longjmp(xsb abort fallback environment, fail inst)

Terrance Swift Topics in Logic Programming Implementation Exceptions

catch(Goal, Catcher, Handler) :- set variable catch marker to point to clean up block call(Goal), clean up block. catch( Goal,Catcher,Handler) :- xsb thread self(T), ’$$exception ball’(T,Ball), % one fact per thread here so no CP ( Ball = Catcher -> retractall(’exception ball’( )), call(Handler) ; find next catch() ).

A call to catch/3 first makes sure that catch marker points to clean up block (this actually needs to be done at initialization). If find next catch() traverses the environment for a call to catch/3 it will set the environment and choice point stacks, the heap and trail to that environment, and succeeds. If the thrown Ball unifies with Catcher, Handler will be called; othewise find next catch() will be called again. When there are no choice points created by Goal, clean up block removes the choice point set up by catch/3.

Terrance Swift Topics in Logic Programming Implementation Catching vs. Cutting

catch/3 finds a previous enviroment and resets stack to that enviroment. After the environment is reset, it calls a handler and succeeds (if the handler succeeds); !/0 finds a previous choice point C, and resets stacks to the enviroment in C by failing. Once the enviroment is reset, a failure continuation is taken.

Terrance Swift Topics in Logic Programming Implementation Cleaning Up after a Goal

How do you guarentee that a given handler is always called after a goal – whether the goal succeeds (with no more choice points), fails, or throws an exception E.g. to close a db cursor, mutex, etc. As described, catch/3 handles exceptions This is usually done via call cleanup(#Goal,#Handler) Failure of Goal:

?- call_cleanup(fail,writeln(failed(Goal))).

In this case, Goal has no solutions, and the handler is invoked when the engine backtracks out of Goal. Deterministic success of Goal. Assume that p(1) and p(2) have been asserted. Then

Terrance Swift Topics in Logic Programming Implementation Cleaning Up after a Goal

?- call_cleanup((p(X),writeln(got(p(X)))), writeln(handled(p(X)))). got(p(1))

X = 1; got(p(2)) handled(p(2))

X = 2;

no

Terrance Swift Topics in Logic Programming Implementation Cleaning Up after a Goal

The hard part is when choice points for Goal are removed via a cut. Again, assume p(1),p(2) are in the database. call_cleanup(p(X),writeln(handled_1)),!. handled_1

X = 1

yes If a cut cuts over more than goal to be cleaned, more than one handler will be executed: ?-call_cleanup(p(X),writeln(handled_4_1)), call_cleanup(p(Y),writeln(handled_4_2)), call_cleanup(p(Z),writeln(handled_4_3)), !. handled_4_3 handled_4_2 handled_4_1

X = 1 Y = 1 Z = 1

Terrance Swift Topics in Logic Programming Implementation Cleaning Up after a Goal

How do you implement this? The following code handles deterministic success + failure call_cleanup(Goal,Cleanup):- get_breg(BregBefore), catch(Goal,E,cleanup_catcher(Cleanup,E)), get_breg(BregAfter), (BregBefore == BregAfter -> % if no CPs left for Goal removes call_cleanup’s ’$$clean_up_block’(BregBefore), call(Cleanup) ; true). call_cleanup(_Goal,Cleanup):- call(Cleanup), fail. Note that B register hacking done to recognize deterministic success; also a choice point is explicitly removed (as with catch/3) When cutting over a choice point for call cleanup the choice point must be recognized and the handler called.

Terrance Swift Topics in Logic Programming Implementation Cleaning Up after a Goal

How does the cut recognize that a handler must be called? The following pseudo-code is called by putpbreg or putpbreg (XSB terminology)

cut_code(cut_breg) /* restore EB reg and HB reg except for check_complete */ cut_restore_trail_condition_registers(cut_breg); while (cp_prevbreg(breg) => cut_breg) /* add interrupt if breg points to 2nd clause of call_cleanup */ CHECK_CALL_CLEANUP( breg); inst_cut_over = *cp_pcreg(breg); /* throw exception if cutting over a table */ CHECK_TABLE_CUT(inst_cut_over) ; breg = cp_prevbreg(breg); unwind_trail(breg,xtemp1,xtemp2); breg = cut_breg; /* Check for call_cleanup or attributed var. interrupts */ if (pending_interrupts) /* Save env. as continuation then call call_cleanup or constraint handler */ alloc_env_and_call_check_ints(reserved_regs,arity);

Issues involving attributed variables and cutting over tables will be discussed later.

Terrance Swift Topics in Logic Programming Implementation Speeding up the WAM

How do you handle instruction dispatch in the WAM?

inst_dispatch:

switch(*P) { case getpvar: : goto instruction_dispatch;

case getpval: : goto instruction_dispatch; }

Tests have indicated that XSB spends 25-30% of its time in instruction dispatch when this model is used.

Terrance Swift Topics in Logic Programming Implementation Speeding up the WAM

To speed up instruction dispatch, you can create macro instructions E.g. define getlist tvar tvar R0,R1,R2 to execute the sequence:

getlist R0 unitvar R1 unitvar R2

Most Prologs have a few instructions like this. Analysis of instruction sequence frequency indicates that there aren’t that many “common” cases”

Terrance Swift Topics in Logic Programming Implementation WAM Review

What does p/3 do?

test_heap, 3, 2000 switchonterm, r1, 0x300d44, 0x300d50 try, 3, 0x300d44 trust, 3, 0x300d50 0x300d44 getnil, r1 gettval, r2, r3 proceed 0x300d50 getlist_tvar_tvar, r1, r4, r12 getlist, r3 unitval, r4 unitvar, r3 xsb_execute, 0x300c40, p/3

Terrance Swift Topics in Logic Programming Implementation Speeding up the WAM

Native code generation is an extreme form of this: compile e.g. append/3 into constituent instructions. Native code generation can give good speedup, but it also expands space needed for a program (10x in Aquarius or Parma?)) Native code generation means different things for different Prologs: various Prologs implement it: Aquarius and Parma (which are no longer maintained); GNU Prolog; YAP and Ciao also have experimented with native code.

Terrance Swift Topics in Logic Programming Implementation Speeding up the WAM

Jumptable Interpterter (or threaded interpreter)

getpvar: : goto *instr_addr_table[*P];

getpval: : goto *instr_addr_table[*P];

To do this, you need to either program in assembler or have a C compiler that supports label variables. In GCC (cf: Section 5.3 of the GCC manual) the table is set up as follows: instr addr table[byte value of getpvar] = && getpvar; Not available for non-GCC (e.g. Microsoft’s).

Terrance Swift Topics in Logic Programming Implementation Speeding up the WAM

Specialized WAM instructions. Take into account mode, type information Based on global analysis (e.g. Aquarius [van92]) Based on mode declaration (e.g. Mercury) Consider how to specialize getpval Recall getpval is used when a register value is unified with a permanent variable.

getpval Vi ,Rj register unsigned long * op1 = *(E-i) register unsigned long * op2 = *regs[j] P + sizeof(word) unify(op1,op2) goto *instr addr table[*P]

Early increment of P may help instruction speed in pipelined architectures

Terrance Swift Topics in Logic Programming Implementation Speeding up the WAM

If you know the type of e.g. Vi you can replace getpval with an instruction like

getpcon Vi ,Rj register unsigned long * op1 = *(E-i) register unsigned long * op2 = *regs[j] P = P + sizeof(word) unify constant(op1,op2) goto *instr addr table[*P]

This is essentially getcon but unifying a register with a number obtained from a permanent variable rather than code. Specialized unification has only one reference, and can avoid the switch() statement that is usual in full unification (e.g. unify()).

Terrance Swift Topics in Logic Programming Implementation Speeding up the WAM: Mode Information

unicon Vi register unsigned long * op1 = *(P+sizeof(Cell)) P = P+2*sizeof(word) if (flag == WRITE) H++ = op1 else op1 = *(S++) unify constant goto *instr addr table[*P]

If Xi is known to be free (and not aliased) this can be specialized to a set con

If Xi is known not to be free this can be specialized to a non-WAM instruction that we might call bind con

bind con Vi register unsigned long * op1 = *(P+sizeof(Cell)) P = P+2*sizeof(word) op1 = *(S++) unify constant goto *instr addr table[*P]

Terrance Swift Topics in Logic Programming Implementation Dereference Chains

Dereferencing can be expensive, and unification requires one (e.g. getcon), or two dereferences (e.g. getpval). Dereference chains can be shortened by a simple hack: deref(op) while (is_variable(op)) { if (op == *(op)) break; op = (CPtr) *(op); } This resets the chain as we go down it, the next time it will be shorter. Global and local analysis (based on declarations) can be used to avoid unnecessary dereferencing

Terrance Swift Topics in Logic Programming Implementation Calling and Executing

Optimization may work agains system properties. Consider XSB’s call

call PredRef P = P+2*sizeof(word) CP = P if no interrupts P = get entryPoint(PredRef) else check for attributed variable interrupts check for keyboard interrupts check for profiling interrupts check for signal or spy interrupts check for thread cancellation goto *instr addr table[*P]

This instruction is deoptimized Indirect reference to entry point via PredRef to allow dynamic loading of undefined predicates Check of interrupt vector System properties often weigh against optimization

Terrance Swift Topics in Logic Programming Implementation Benchmarking Prologs

On my Mac I tested the following open-source Prologs YAP version 5.1.3 Ciao version 1.13.0 XSB version 3.2 GNU version 1.3.1 SWI version 5.4.7 (not newest) In addition, on a Linux server I tested Quintus and Sicstus against XSB (both are recent versions).

Terrance Swift Topics in Logic Programming Implementation Benchmarking Prologs: Benchmarks

I tested 5 benchmarks of D.H.D Warren deriv which constructs the derivative of a polynomial, and benchmarks trailing and untrailing nrev which performs naive reverse and benchmarks tail recursive list traversal that requires creation of environment frames, but not choice points. serialise which assigns an ordinal number to integers in a list, and benchmarks backtracking and creation of large structures on the heap. qsort which quick-sorts a list of numbers and benchmarks backtracking and environment frame allocation query which performs queries against a database of countries, and benchmarks shallow backtracking and indexing. In addition, I tested 3 other benchmarks ackerman which computes the Ackerman function and tests determinacy detection in Prolog conditionals call which tests call/1 assert which tests repeated assertions and deletions of facts

Terrance Swift Topics in Logic Programming Implementation Benchmarking Prologs: Caveats

Relative times are given since the benchmarks were performed on two different machines. Each system was made and tested without any particular tuning. Compilation of Ciao was not fully optimized (OS X is not a preferred platform for Ciao) so Ciao might be faster on, say, Linux. The SWI version was not the newest. No native code generation was performed for GNU prolog, no analysis for Ciao. Thus these times reflect “default” behavior.

Terrance Swift Topics in Logic Programming Implementation Benchmarking Prologs

deriv nrev qsort serialize query ackerman call assert YAP 0.38 0.38 0.36 0.41 0.68 segfault 0.17 0.39 GNU-native 0.6 0.86 0,76 0.74 0.93 alloc error 2.55 no dyn code Ciao 0.63 1.02 0.77 0.85 1.01 alloc error 68.2 0.35 XSB 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 GNU 1.38 2.36 2.08 1.47 2.45 alloc error 2.9 no dyn code SWI 4.85 11.6 7.51 6.45 10.4 alloc error 3.1 0.54 Quintus 0.37 0.47 0.63 not tested 0.68 timeout 9.6 0.97 Sicstus 0.32 0.42 0.37 not tested 0.54 0.84 1.61 0.95

Quintus, Sicstus and YAP have the fastest emulators, Followed by Ciao, XSB, GNU, and SWI Attributed variables are supported in YAP, Ciao, XSB, SWI and Sicstus 2

The ordering changes for the builtin tests (call/1 and assert/1). A Prolog can have a slow emulator, but have fast builtins written in C.

SWI has one of the fastest compilers of these Prologs GNU Prolog native codes offer less speedup than Acquarius or Parma, but does not explode in terms of space. However, GNU native code does not allow debugging. The YAP and Sicstus emulators are the fastest (for these tests); SWI and Sicstus are probably the most robust. Usage of these Prologs is not correlated to their speed. 2GNU supports finite-domain constraints not based on attributed variables. Terrance Swift Topics in Logic Programming Implementation How Important is Speed?

Speed is obviously important, but In 1980’s C was the language of choice for many projects In early 1990’s C++ was the language of choice for many projects In early 2000’s Java and C# was the language of choice for many projects Now, Python and Ruby are the language of choice for many projects

How does speed compare to system aspects (memory management, interrupt handling)? How does speed compare to a memory footprint? Tabled Prolog (XSB, YAP) is usually much faster than rule-based systems such as Jess, Drools, etc [LFWK09] Prologs are often much slower than at least some functional languages (Lisp, ML, Haskell) particularly for deterministic programs like ackerman

Terrance Swift Topics in Logic Programming Implementation What is Speed?

Is naive reverse (or other Warren benchmarks) a good benchmark of speed? If so, than a fast WAM implementation is important (or native code generation). Is 8-Queens a good benchmark? If so than a fast CLP implementation is important. Is LR parsing a good benchmark? If so, then tabling is important. Is indexing important? What about taking advantage of multi-core processors? What is important is the speed of practical applications, which demand a mixture of all these.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 2: Tabling for Definite Programs

Terrance Swift Topics in Logic Programming Implementation Outline

Motivation for tabling: Why study it? Why add it to an engine? Overview of variance vs. subsumption Scheduling Strategies

Terrance Swift Topics in Logic Programming Implementation Motivation

Tabling addresses inadequacies of Prolog (SLDNF) Termination for e.g. programs ancestor(X,Y):- parent(X,Y). ancestor(X,Y):- ancestor(X,Z),parent(Z,Y). Poor complexity, even when it terminates. sg(X,X) sg(X,Y):- par(X,Z),sg(Z,Z1),par(Y,Z1). over a directed acyclic graph.

Terrance Swift Topics in Logic Programming Implementation Motivation

While SLD is complete for Horn clauses, it does not terminate for bounded term-depth programs. e.g. finite number of subgoals and answer substitutions, as with Datalog programs. The following program does not have finite term depth (nor a finite model). p(s(X)):- p(X). p(0). The following program does not have finite term depth (but does have a finite model). p(X):- p(s(X)).

Terrance Swift Topics in Logic Programming Implementation An Example of SLD Evaluation

0. p(a,X)

1. e(a,X) 5. e(a,Y),p(Y,X) X = a X = b Y = a Y = b 3. 4. 6. p(a,X) p(b,X)

...... e(b,X) e(b,Y1),p(Y1,X) X = c Y1 = c p(c,X)

e(c,X) e(c,Y2),p(Y2,X)

?- p(a,X)

p(X,Y) :- e(X,Y) p(X,Y) :- e(X,Z),p(Z,Y)

e(a,a). e(a,b). e(b,c).

Terrance Swift Topics in Logic Programming Implementation An Example of SLD Evaluation

The SLD tree contains all solutions (completeness) but is infinite (non-termination) If you simply check for loops, you can achieve termination, but you don’t address complexity

Terrance Swift Topics in Logic Programming Implementation An Example of SLG (Tabled) Evaluation

0. p(a,Z) :- table p/2.

p(X,Z) :- p(X,Y),p(Y,Z). 1. p(a,Z) :- p(a,Y),p(Y,Z) 2. p(a,Z) :- e(a,Z),q(Z) p(X,Z) :- e(X,Z),q(Z).

e(a,b). e(a,d). e(b,c).

6. p(a,Z) :- p(b,Z) 3. p(a,b) :- q(b) 5. p(a,d) :- q(d) q(a). q(b). q(c).

Subgoal Answers State 11. p(a,c) :- 4. p(a,b) :- p(a,Z) p(a,b) Incomplete p(a,c) 6a. p(b,Z) p(b,Z) p(b,c) Incomplete p(c,Z) Incomplete

7. p(b,Z) :- p(b,Y),p(Y,Z) 8. p(b,Z) :- e(b,Z),q(Z) 12a. p(c,Z)

12. p(b,Z) :- p(c,Z) 9. p(b,c) :- q(Z) 13. p(c,Z) :- p(c,Y),p(Y,Z) 14. p(c,Z):- e(c,Z),q(Z)

10. p(b,c) :-

Terrance Swift Topics in Logic Programming Implementation An Example of SLG (Tabled) Evaluation

This example uses double recursion (2 occurrences of a/2 in the body). Tabling is more efficient with left recursion. Examples in these slides use Prolog’s top to bottom clause selection strategy and left-to-right literal selection strategy. These orderings are among many that are possible.

Terrance Swift Topics in Logic Programming Implementation Definite Programs: SLD vs. Tabling

Tabling factors out redundant subcomputations to compute the minimal model of a definite program (expressible as the least fixed point of a monotonic operator). Several formulations for tabling: for example OLDT [TS86], SLD-AL [Vie89], SLG [CW96], Magic [BMSU86] Nodes have the form fail or

AnswerTemplate :- GoalList

(this form becomes slightly more complex for the well-founded semantics) If a tree T has root A :- A, then A is termed the root subgoal of T . In this formulation, answers are (non-failure) leaf nodes whose goal list is empty.

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Grammars

Consider the grammar

expr --> expr + term expr --> term term --> term * factor term --> factor factor --> ( expr ) factor --> integer(Int)

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Grammars

A translation into Prolog-style DCGs.

expr --> term, addterm. addterm --> []. addterm --> [+], expr. term --> factor, multfactor. multfactor --> []. multfactor --> [*], term. factor --> [I], {integer(I)}. factor --> [’(’], expr, [’)’].

The programmer has executed left-recursion elimination and left-factoring. Grammar now has right-associative operators rather than the left-associative operators of the original grammar. i.e. x − y − z now is x − (y − z) rather than (x − y) − z

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Grammars

The same grammar using tabling.

:- table expr/2, term/2.

expr --> expr, [+], term. expr --> term. term --> term, [*], factor. term --> factor. factor --> [’(’], expr, [’)’]. factor --> [Int], {integer(Int)}.

Syntactic variant of original grammar. Has no associativity problem

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Grammars

Applying tabling to a DCG grammar can effectively give Earley Parsing [Ear70] Supplementary Tabling (Supplementary Magic) can convert the grammar to Chomsky Normal Form3. i.e., convert a rule

a(A, D) ← b(A, B), c(B, C), d(C, D)

which is worst-case O(N4) in the number of grammar symbols, to a(A, D) ← b(A, B), a0(B, D) a0(B, D) ← c(B, C), d(C, D) Earley Parsing of grammars in Chomsky Normal Form takes at most O(N3) for ambiguous grammars; at most O(N2) for unambiguous grammars; and is linear for a large class of grammars.

3Implementing Earley’s Dotted Rules. Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Dynamic Programming

The knap-sack problem: Given n items, each of integer size ki (1 ≤ i ≤ n), and a knap-sack size K. determine whether there is a subset of the items that sums to K. Find such a subset.

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Dynamic Programming

A Prolog solution to the knapsack problem.

ks(0,0). ks(I,K) :- I>0, I1 is I-1, ks(I1,K). ks(I,K) :- I>0, item_size(I,Ki), K1 is K-Ki, K1 >= 0, I1 is I-1, ks(I1,K1).

item_size(1,2). item_size(2,3). item_size(3,5). item_size(4,6).

Worst-case complexity is 2I .

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Dynamic Programming

A tabling solution to the knapsack problem.

:- table ks/2.

ks(0,0). ks(I,K) :- I>0, I1 is I-1, ks(I1,K). ks(I,K) :- I>0, item_size(I,Ki), K1 is K-Ki, K1 >= 0, I1 is I-1, ks(I1,K1).

item_size(1,2). item_size(2,3). item_size(3,5). item_size(4,6).

Worst-case complexity is I 2.

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Dynamic Programming

But how do you find the subset(s)?

ksp(0,0,[]). ksp(I,K,P) :- I>0, I1 is I-1, ks(I1,K), ksp(I1,K,P). ksp(I,K,[I|P]) :- I>0, item_size(I,Ki), K1 is K-Ki, K1 >= 0, I1 is I-1, ks(I1,K1), ksp(I1,K1,P).

Because of tabling, ks/2 does not repeat computations. cf. [Man89] pg. 110 for an equivalent imperative solution.

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Verification

:- table trans/3. % Prefix: Act.P Act-> P trans(pref(Act, P), Act, P).

% Choice: P = P1 + P2 trans(choice(P, _Q), Act_a, P1) :- trans(P, Act_a, P1). trans(choice(_P, Q), Act_a, Q1) :- trans(Q, Act_a, Q1).

% Parallel: P = Q | R trans(par(P, Q), Act_a, par(P1, Q)) :- trans(P, Act_a, P1). trans(par(P, Q), Act_a, par(P, Q1)) :- trans(Q, Act_a, Q1). % Represent Coactions trans(par(P, Q), tau, par(P1, Q1)) :- trans(P, Act_a, P1), trans(Q, Act_b, Q1),comp(Act_a, Act_b). trans(par(P, Q), tau, par(P1, Q1)) :- trans(P, Act_a, P1), trans(Q, Act_b, Q1),comp(Act_b, Act_a).

% Restriction: P\L Act-> P1\L trans(rest(P,L), Act_a, rest(P1,L)) :- trans(P, Act_a, P1),legitimate_action(Act_a, L).

% Relabelling: P = Q [f] trans(relab(P, Hom_f), Act_b, relab(P1, Hom_f)) :- trans(P, Act_a, P1),map(Hom_f, Act_a, Act_b).

% Transitive Redefinition trans(P, Act_a, Q) :- def(P, R), trans(R, Act_a, Q).

Terrance Swift Topics in Logic Programming Implementation Tabling Applications: Deductive Databases

Redundant subcomputations

join(X,Y):- supplemental(X,X2),rel_3(X2,Y).

supplemental(X,Y):- rel_1(X,X1),rel_2(X1,Y).

rel1 rel2 rel3 (a,b) (b,e) (e,g) (a,c) (c,e) (e,h) (a,d) (d,f) (f,i) In SLD resolution, 8 join operations are performed on the above example, while if supplemental is tabled, there will be only 6 join operations. In extreme cases, redundant subcomputations can lead to exponential data complexity for Prolog. (See the knapsack problem below). Tabling has polynomial data complexity for datalog programs with negation. Under a given search strategy tabling is equivalent to magic evaluation under a semi-naive search strategy [FSW97].

Terrance Swift Topics in Logic Programming Implementation Implementation of Tabling

join(X,Y):- supplemental(X,X2),rel_3(X2,Y).

supplemental(X,X2):- rel_1(X,X1),rel_2(X1,X2).

Where join/2 and supplemental/2 are tabled, may be more efficient than join(X,Y):- rel_1(X,X1),rel_2(X1,X2),rel_3(X2,Y).

A simple optimization consists of folding EDB predicates into new tabled predicates. This is called Supplemental Magic Sets [BR91] or Supplemental Tabling. Both rediscover Earley’s observation that the complexity of grammar processing is proportional to the number of non-terminals on the RHS of a production [Ear70].

Terrance Swift Topics in Logic Programming Implementation Applications of XSB Tabling (and Flora [YKZ03]): A Partial List

Verification: [RRR+97, CDD+98, DKRR98, LRS98, DRS00, MRRV00, RRS+00, KT02, PRR02, BKPR02, PR04, SS05] Ontology Management and the Semantic Web: [PAE98, DYKR00, LPB02, ZFD+03, TDK03, CFJ03, SW03, Swi04, ZFC04, BG05, DHM07] and various products of XSB, Inc., Ontology Works, Inc., and OpportuniTV Inc. Program Analysis: [DRW96, Bou97, CDS98, JS98, SR05] Natural Language Analysis and Data Standardization: [LWFS95, RRS97, RL98, CS02, DJP+02] and various products of XSB, Inc Diagnosis: [CP04, AAB+04, BRO07], and various products of BBN Inc. Medical Informatics: [GST+00, Mun04, MGR04] and various products of MDLogix Inc. and Medicine Rules Inc. Robotics and Collaborative

Agents [ALPQ00,Terrance LCK01, Swift KF04,Topics LGTH05, in Logic Programming LTLH05, Implementation SP06] Machine Learning [LRP99, PGP01, dSSR04] Software Engineering: [PV07, STI+06] and the ArchLog Project [Oqu04] Semantic Web Applications:‘[Gro09] Implementation of Tabling: Copy Avoidance

Structural recursion is acyclic for Prolog-style terms append([],L,L). append([H|T],L,[H|T1]):- append(T,L,T1). which can be seen to have a right recursive form: append([],L,L). append(Term,L,[H|T1]):- cons(Term,H,T),append(T,L,T1). Consider the query append([a,b,X],[c],Y). The following queries are made append([a,b,X],[c],Y). append([b,X],[c],Y). append([X],[c],Y). append([],[c],Y). Still quadratic in the size of the first argument if you must copy from execution area to table. Other possible solutions: Intern Ground Structures in Table Can, in principle, use structure-sharing techniques for non-ground terms. [dlC93, SR93, CR09]. Terrance Swift Topics in Logic Programming Implementation Definite Programs: Tabling Operations

From [Swi99a], based on [CW96].

1 New Subgoal: Let Fn be a forest that contains a non-root node N = Ans :- G, Goal List

where G is the selected literal S or not S. Assume Fn contain no tree with root subgoal S. Then add the tree S :- |S to Fn.

2 Program Clause Resolution: Let Fn contain a root node N = S :- |S and C be a program clause Head :- Body such that Head unifies with S with mgu θ. Assume that in Fn, N does not have a child Nchild = (S :- |Body)θ. Then add Nchild as a child of N.

3 Positive Return: Let Fn contain a non-root node N whose selected literal S is positive. Let Ans be an answer node for S in Fn and Nchild be the SLG resolvent of N and Ans on S. Assume that in Fn, N does not have a child Nchild . Then add Nchild as a child of N 4. 4 Completion: Given a completely evaluated set S of subgoals, mark the trees for all subgoals in S as completed. 4For definite programs, simple resolution is all that is needed. Terrance Swift Topics in Logic Programming Implementation Definite Programs: Completion

What does Completely Evaluated mean? A subgoal is completely evaluated iff it has all of its possible answers. A subgoal S is completely evaluated when all possible operations have been done on its nodes, and the nodes of trees upon which S depends. A ground subgoal is completely evaluated when an answer is derived for it. Incremental Completion is necessary for efficient evaluation of programs. We also haven’t yet defined | or SLG answer resolution – these will be defined when we introduce non-stratified negation For now, ignore | and think of SLG answer resolution as the resolution of a fact against the leftmost argument of a goal.

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Completion

p(a,Z)

p(b,Z)

p(c,Z)

Definition (Subgoal Dependency Graph)

Let F be a forest in a SLG evaluation. We say that a tabled subgoal S1 directly depends on a tabled subgoal S2 in F iff neither the tree for S1 nor that for S2 is marked as complete and S2 is the selected literal of some node in the tree for S1. The Subgoal Dependency Graph of F, SDG(F), is a directed graph V,E in which V is the set of root goals for non-completed trees in F and (Si , Sj ) ∈ E iff Si directly depends on Sj .

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Completion

There is a function from SLG forests to SDGs. Since SDGs are directed graphs, Strongly Connected Components (SCCs) can be defined for them. Incremental Completion can be performed an SCC at a time, or a set of SCCs at a time.

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Variance vs. Subsumption

p(f(Y),X,1) and p(f(Z),U,1) are variants as one can be made to look like the other by a renaming of the variables.

The term t3: p(f(Y),X,1) subsumes the term t4: p(f(Z),Z,1). However, they are not variants. Hence t3 properly subsumes t4.

From a more general perspective, Term T1 subsumes Term T2 if T1 ≥ T2 on the lattice of terms. In this lattice most general unifier is the meet, and the minimum anti-unifier is the join. Other lattices could be defined. For instance, the ordering of terms used by ≥@. Depending on the application, a partial order could be used instead of a lattice – for instance the partial order defined over the isa-relation of an ontology. Exercise: define variance and subsumption in terms of most general unifiers.

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Variance vs. Subsumption

Variance vs. Subsumption in the New Subgoal operation Either variance or subsumption can be used when checking whether a subgoal is the root of a tree in the New Subgoal operation. This is termed call variance (or call subsumption). Call variance is useful for goal-directed queries and meta-interpreters. Call subsumption is especially useful when you want to find the inferential fixed point of a program -i.e. a bottom-up fixed-point. For instance, all pairs with property p(X,Y) in a graph. Application: RDF reasoner (Carlos Dam´asio) Application: Program analysis, where you want to find all properties of a program element (e.g. of a clause variable at the time of a call). Application: evaluating an OWL-style ontology where reasoning by cases is not needed.

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Variance vs. Subsumption

Variance vs. Subsumption in the Positive Return operation Either variance or subsumption can be used when checking whether an answer has been resolved against a subgoal in Positive Return. This is termed answer variance (or answer subsumption). Answer subsumption is useful iff an application has a good semantics for a lattice of answers (i.e Generalized Annotated Programs [KS92]); for Probabilistic and Possibilistic Logics [RS10, RS11]; or for preferring some answers over others (e.g. Preference Logic [CS02, JGM98], or Defeasible logics [WGK+09]) (negation can also be used for these).

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Local Evaluation

We have 4 operations: New Answer, Program Clause Resolution, Positive Return, and Completion – how should we schedule them? We’ve already argued that Completion should be performed as early as possible (incrementally), to save space. Program Clause Resolution should be scheduled as in Prolog, as far as possible. New Subgoal should be performed as soon as a goal is encountered, to accord with Prolog’s search strategy This leaves the question of how to schedule Positive Return w.r.t Program Clause Resolution

Definition (Locality property) Let F be an SLG forest. Resolution of an answer A against a consuming node N occurs in an independent SCC of F if the root subgoal for N is in an independent SCC in SDG(F). An SLG evaluation has the locality property if any answer resolution operation applied to a state Fn occurs in an independent SCC of Fn.

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Local Evaluation

1. p(1,Y) <- p(1,Y)

2. p(1,Y) <- p(1,Z), p(Z,Y) 3. p(1,Y) <- a(1,Y)

6. p(1,Y) <- p(2,Y) 19. p(1,Y) <- p(3,Y)4. p(1,2) <- 5. p(1,3) <-

18. p(1,3) <- 20. Fail

7. p(2,Y) <- p(2,Y) 12. p(3,Y) <- p(3,Y)

8. p(2,Y) <- p(2,Z),p(Z,Y) 9. p(2,Y) <- a(2,Y) 13. p(3,Y) <- 14. p(3,Y) <- a(3,Y) p(3,Z), p(Z,Y)

11. p(2,Y) <- p(3,Y) 10. p(2,3) <- 16. Fail 15. Fail

17. Fail

:- table p/2. p(X,Y) :- p(X,Z), p(Z,Y). p(X,Y) :- a(X,Y). a(1,2). a(1,3). a(2,3).

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Batched Scheduling

A local evaluation of a goal G may not be suitable if only one answer to G is required, or if something can be done with an answer to G before all answers to G have been derived Batched evaluations serve this function (cf. [FSW98] for a fuller description of Batched and Local Evaluations)

1. p(1,Y) <- p(1,Y)

2. p(1,Y) <- p(1,Z), p(Z,Y) 3. p(1,Y) <- a(1,Y)

6. p(1,Y) <- p(2,Y) 19. p(1,Y) <- p(3,Y) 4. p(1,2) <- 5. p(1,3) <-

11. p(1,3) <- 20. Fail

7. p(2,Y) <- p(2,Y) 13. p(3,Y) <- p(3,Y)

8. p(2,Y) <- p(2,Z),p(Z,Y) 9. p(2,Y) <- a(2,Y) 14. p(3,Y) <- p(3,Z),p(Z,Y) 15. p(3,Y) <- a(3,Y)

12. p(2,Y) <- p(3,Y) 10. p(2,3) <- 17. Fail 16. Fail

18. Fail

Terrance Swift Topics in Logic Programming Implementation Local Evaluation: Example

sgi(X,Y)(D) :- arc(X,Y). sgi(X,Y)(D) :- arc(X,Z), subsumes(min)(sgi(Z,Z1),D1), arc(Y,Z1), D is D1+1. Time for ?-p(bound,free) is linear in edges for Local Evaluation, Linear in size of paths for Batched Evaluation

0

1 2

3 4

5 6 . . . . n-3 n-2

n-1 n

Terrance Swift Topics in Logic Programming Implementation Local Evaluation: Example

4500 XSB v. 1.5 4000 Local 3500 3000 2500 2000

Time (in secs) 1500 1000 500 0 0 200 400 600 800 1000 1200 n

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Scheduling Strategies

Time for left recursion Batched Scheduling is somewhat faster than Local Evaluation for left recursion as Local Evaluation imposes overhead to prevent answers from being returned outside of an independent SCC. Time to first answer Because Batched Scheduling returns answers out of an SCC eagerly, it is faster to derive the first answer to a tabled predicate. Stack space Local evaluation often requires less space than Batched evaluation as it fully explores a maximal independent SCC, completes the SCC’s subgoals, reclaims space, and then moves on to a new SCC. Integration with cuts Local Evaluation integrates better with cuts, as tabled subgoals may be fully evaluated before the cut takes effect.

Terrance Swift Topics in Logic Programming Implementation Definite Programs: Scheduling Strategies

Efficiency for call subsumption Because Local Evaluation completes tables earlier than Batched Evaluation it can be faster for call subsumption, as subsumed calls can make use of completed subsuming tables. Negation and tabled aggregation Local Evaluation is superior for tabled aggregation as only optimal answers are returned out of a maximal SCC. Local Evaluation also can be more efficient for non-stratified negation as it may allow delayed answers that are later simplified away to avoid being propagated. Scope for Parallelism Because local evaluation does ot return answers out of an (independent) SCC until it is completed, it has limited scope for parallelism compared to Batched Evaluation.

Terrance Swift Topics in Logic Programming Implementation Optimizing Recursions

Consider three forms of the same recursion: left linear reach(X,Y):- edge(X,Y). reach(X,Z):- reach(X,Y),edge(Y,Z). non-left (right) linear reach_r(X,Y):- edge(X,Y). reach_r(X,Z):- edge(X,Y),reach_r(Y,Z). double reach_dbl(X,Y):- edge(X,Y). reach_dbl(X,Z):- reach_dbl(X,Y),reach_dbl(Y,Z).

Terrance Swift Topics in Logic Programming Implementation Optimizing Recursions

Consider the query form reach(free,free). This will give rise to various calls of the form reach(bound,free) (assuming that the edge/2 facts are all ground).

For call variance using left recursion, a new table is created for each new call. For a fully connected graph of N nodes, there will be 1 table with N2 answers. For call variance using right recursion, a new table is created for each new call. For a fully connected graph of N nodes, there will be 1 table with N2 answers, and N tables each with N answers. For call variance using double recursion, a new table is created for each new call. For a fully connected graph of N nodes, there will be 1 table with N2 answers, and N tables each with N answers.For a fully connected graph of N nodes, there will again be N tables each with N answers. However, answers will need to be returned to both literals in the body, rather than just to one literal. For call subsumption, the bound,free calls reuse the free,free tables.

Terrance Swift Topics in Logic Programming Implementation Optimizing Recursions

Left recursion / Variant Avg edges/vert 1 4 16 64 256 512 Time (secs) .02 7.2 22.9 96.5 382.3 793.4 #Ans rets 27,367 15,423,312 64,032,000 256,128,000 1,024,512,000 2,049,024,000 Tab space (mb) .85 81.2 84.3 84.3 84.3 84.3

Left recursion / Subsumption Avg edges/vert 1 4 16 64 256 512 Time (secs) .02 8.2 25 104 412.4 850.8 Tab space (mb) .975 96.7 100.4 100.4 100.4 100.4

Right recursion / Variant Avg edges/vert 1 4 16 64 256 512 Time (secs) .02 8.1 31.6 125.5 509.9 1056 #Ans rets 43,586 30,530,036 128,064,000 512,256,000 204,9024,000 4,098.048.000 Tab space (mb) 1.4 161.4 168.8 168.8 168.8 168.8

Right recursion / Subsumption Avg edges/vert 1 4 16 64 256 512 Time (secs) .03 6.7 22.2 85.4 361.6 787.9 Tab space (mb) 1.07 100.7 100.7 100.7 100.7 100.7

Terrance Swift Topics in Logic Programming Implementation Optimizing Recursions

Double recursion / Variant Avg edges/vert 1 2 Time (secs) 0.1 1455.3 # Ans rets 371,360 1,824,740,241 Tab space (mb) 1.4 102,2

Double recursion / Subsumption Avg edges/vert 1 2 Time (secs) 0.1 968 Tab space (mb) 1.4 65.3

Terrance Swift Topics in Logic Programming Implementation Optimizing Recursions

Left linear recursion with call variance is the most efficient in terms of table space usage. Under call variance, table space for double recursion is exactly the same as for right recursion (not obvious from tables) For left recursion call subsumption provides no benefits, as there are no instances of subsuming calls. Comparing call subsumption to call variance for left recursion therefore indicates the overhead of call subsumption where it is not used. This overhead is about 10 Call subsumption is significantly more efficient than call variance for right recursion. Its table space is nearly the same as call subsumption for left recursion, but its times are often the fastest of all. For the sparse graphs (1 edge/vertex) the type of recursion doesn’t matter much. However for the dense graphs (where most vertices are connected) double recursion is much worse in terms of time than linear recursion no matter what form.

Terrance Swift Topics in Logic Programming Implementation Memory (total) 3818817464 bytes: 3492831064 in use, 325986400 free permanent space 6571240 bytes: 6531200 in use, 40040 free trie-asserted 1227416 40040 atom 698184 string 1001184 asserted 936872 compiled 2604224 findall 42000 hash 5080 read canon 1024 other 15216 glob/loc space 1610612736 bytes: 1581385936 in use, 29226800 free global 1402208280 bytes local 179177656 bytes trail/cp space 1610612736 bytes: 1330920056 in use, 279692680 free trail 396036104 bytes choice point 934883952 bytes SLG unific. space 131072 bytes: 0 in use, 131072 free SLG completion 16777216 bytes: 10703200 in use, 6074016 free (334475 incomplete table(s)) Incr table space 320 in use SLG table space 574112464 bytes: 573993872 in use, 118592 free

Tabling Operations 4338864 subsumptive call check/insert ops: 48 producers, 18 variants, 106 properly subsumed (50 table entries), 4338692 used completed table. 148 relevant answer ident ops. 452 consumptions via answer list. 13438357 variant call check/insert ops: 1715398 producers, 11722959 variants. 193506 answer check/insert ops: 58304 unique inserts, 135202 redundant. 12 tabled predicates explicitly abolished

0 heap ( 0 string) garbage collections by copying: collected 0 cells in 0.000000 secs

Time: 374.280 sec. cputime, 634.722 sec. elapsetime

Terrance Swift Topics in Logic Programming Implementation Viewing XSB’s Resource Consumption

Process-level information about allocated memory excluding execution stacks but including: atoms Space used to maintain global information about predicates and structures. string Space used to maintain information about atomic constants in XSB. asserted Space allocated for dynamic code. asserted Space allocated for static code. foreign Space allocated for foreign predicates. table Space allocated for XSB’s tables. findall Space allocated for buffers to support findall/3 and similar predicates. mt-private Private space used by threads. profiling Space used to maintain profiling information, if XSB is called with profiling on. gc temp Temporary space for used for heap garbage collector. interprolog space allocated for the Interprolog XSB/Java interface. thread space allocated for the thread table the space occupied by subgoal and answer tables (in the form of tries) [RRS+99, CSW99, ?]. In the multi-threaded configuration process level table space includes shared tables but not private tables.

Terrance Swift Topics in Logic Programming Implementation Viewing XSB’s Resource Consumption

Thread-specific information about allocation of memory for the calling thread including the Global stack (heap) and local (environment) stack (see e.g. [AK90a]) for the calling thread. Memory for these two WAM stacks is allocated as a single unit so that each stack grows together; information is provided on the current allocation for the stacks as well as on the stack sizes themselves. Trail and choice point stack (see e.g. [AK90a]) for the calling thread. Memory for these two WAM stacks is allocated as a single unit so that each stack grows together; information is provided on the current allocation for the stacks as well as on the stack sizes themselves. SLG unification stack for the calling thread This stack is used as a space to copy terms from the execution stacks into table space, or back out. SLG completion stack for the calling thread. The completion stack is used to perform incremental completion for sets of mutually dependent tabled subgoals. One completion stack frame is allocated per tabled subgoal [SS98] but the size of these frames is version-dependent. The space occupied by private subgoal and answer tables for the calling thread.

Terrance Swift Topics in Logic Programming Implementation Viewing XSB’s Resource Consumption

Call Subsumption Subgoal Operations. For predicates that use subsumptive tabling, the total number of subsumptive subgoal calls is given, as is the number of new calls (producers) and the number of repeated calls to non-completed tables (variants). Furthermore, the number of properly subsumed calls to incomplete tables is given, along with the number of subsumed calls to completed tables. Finally, the total number of subsumptive table entries overall is given, including all producer and consumer calls. Call Subsumption Answer Operations. In call subsumptive tabling, answer lists are copied from producer subgoals to subsumed consumer subgoals (this operation is not required in variant tabling). The number of answer ident operations represents the number of times this copy is done. In addition, the number of consumptions performed by all consuming subsumptive table entries is also given. Call Variance Subgoal Operations. For call variance the number of subgoal check/insert operations is given along with the unique number of subgoals encountered (generator) and the number of redundant consumer encountered (consumer). Total Answer Operations. For both variant and subsumptive tables, the number of answer check insert operations is given along number of redundant answers derived.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 3: The SLG-WAM – Stacks and Data structures

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Stacks and Data Structures

Let’s start considering the data structures needed and how the WAM stacks and instructions are modified to table definite programs.

We’ll start with Edef , and later extend things by adding negation and constraint handling.

Presentation of Edef generally follows [SS98, RRS+99, FSW98] but there are a few (mostly) minor differences reflecting changes to XSB since these papers were written.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

How do the variant tabling operations we’ve defined so far interact with the table? Subgoal check/insert – Check whether a subgoal is in the table and add it if a variant isn’t there – part of New Subgoal Answer check/insert – Check whether an answer is in the table and add it if a variant isn’t there. Answer backtracking – For both completed, and non-completed tables. Part of Positive Return Can we come up with a data structure that is efficient in time and space for these operations, as well as Operations for call and answer subsumption Memory management operations abolishing all tables (when db changes, thread exit) abolishing all tables for a given predicate abolishing the table for a given subgoal abolishing a given answer (e.g. for answer subsumption) incremental table updates

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Let’s try tries!

s 1 1 a b

s 22s 9 2

f/2 ν1

s 3 2.1 s 10 3 rt(a,f(a,b),a). rt(a,f(a,X),Y). a d s s rt(b,V,d). 4 2.2 11

b ν1

s 5 3s 7 3

a ν2

s6 s 8 (a) (b)

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

s 1 1 a b

s 2 2s 9 2

f/2 g/2 ν1

s 3 2.1s 12 2.1 s 10 3

a b d s 4 2.2 s 13 2.2 s 11 ν b 1 c

s 5 3s7 3 s 14 3

a ν2 c

s6 s 8 s 15

The same trie after the addition of the term rt(a,g(b,c),c).

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Table Space SLG-WAM code code for a b c p/2 Subgoal Trie code for e/2 Var_1 Var_1 Var_1

code for q/1 Subgoal Subgoal Subgoal Frame Frame Frame

b c c Answer Tries

Answer Return List

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

In Edef , tries are used for subgoals and answers Subgoal frames contain information about each tabled subgoal encountered Answer return lists support backtracking, as explained below

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Where are we with our variant tabling operations?

Now we have a 1-pass check insert for variant subgoals + answers (though we haven’t talked yet about variables) As for backtracking through answers, For a completed table A trie can be reasonably efficient means of backtracking as shown by similar structures in [DRSS96]. We can keep a WAM instruction as part of trie node, so that we can backtrack through completed tables. Thus our table contains dynamically compiled code. Note, however that terms are not added in any particular order: so backtracking top-down through the trie is not efficient for non-completed tables (we’d have to iteratively backtrack through the table). To access answers of a completed table, the table space does not need to be altered (as is natural).

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Backtracking through answers For non-completed tables, an answer list chain is added for backtracking, along with parent pointers to traverse the chain backwards. answer list nodes are reclaimed upon completion of the table. There is a double traversal when returning answer from incomplete table – push symbols onto (new) stack as you traverse from the root to leaf, then pop off stack to build term. The reason for this extra traversal will become more apparent after we discuss substitution factoring.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Basic Trie Nodes are used in Subgoal Tries, and Answer Tries for Call-Variant Tables Time-Stamped Nodes are used in Answer Tries for Call-Subsuming Tables

Instructions and Meta-info InstrEtc Sibling Pointer Child Pointer Parent Pointer Symbol Used only in Time-Stamped Tries Time-Stamp

The InstrEtc cell consists of 4 1-byte fields. Instruction The actual trie instruction to be executed if called when the table is completed. Status Used to mark a deleted node whose space has not been reclaimed. Trie Type The type of trie the node is in: Subgoal Trie, Basic Answer Trie, Time-Stamped Answer Trie, Delay Trie, Assert Trie, and Interned Trie. Used mainly for garbage collection and other memory management functions. Node Type: Root, Hash Header, Leaf, Hashed Leaf, Interior, Hashed Interior. Used to navigate the trie when returning an answer from a non-completed table, and for garbage collection.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

When a node has too many descendants, check/insert becomes expensive Solution is to insert a hash-node between parent and children

InstrEtc Number of hashed elements Number of buckets Bucket Array Pointer Previous Hash Node Next Hash Node

Hash Nodes do not need sibling pointers, and backwards traversal uses parent pointer of children, which points to hashes parent. Previous Hash Node and Next Hash Node are used for mass deallocation (i.e. abolish all tables).

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Don’t need to store the whole answer, just substitution. This is called substitution factoring Schematic picture shown below, with just symbol, sibling, and child pointers.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Subgoals: p/2

p(X,X) V1 f/1 p(f(X),a) Subgoal trie for p/2 p(f(X),g(Y)) V1 V1

p(f(X),g(X)) a g/1

V2 V1

Answer substitutions for p(f(X),g(Y)): Answer trie for a b X = a, Y = a p(f(X),g(Y)) X = a, Y = b X = b, Y = a a b a b X = b, Y = b Answer list

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

How do we copy variables into and out of tries? Variables in tries have a special TrieVar tag. When copying from stacks into a trie (e.g. p(X,Y,X)) When a position dereferences to a variable, bind the variable to TrieVarn where n is the nth dereferenced variable encountered. Use a special trail. Copy TrieVarn into the trie. In example above, TrieVar1, TrieVar2, TrieVar1 would be copied. At end, unbind the variables in the special trail. When copying from a trie to a (dereferenced) stack address, A, use a variable indexing array V . Consider the example p(TrieVar1,TrieVar2,TrieVar1)

When encountering a new TrieVarn, and set V [n] = A. When encountering an already seen TrieVarn, set A = V [n].

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Variant tabling can just copy terms (subgoals, answer substitutions) into and out of a table. But how does call subsumption work in XSB? Call subsumption requires a special declaration :- use subsumptive tabling f/a or :- table f/a as subsumptive. If a subgoal Sθ is called, and it is determined that there is a subsuming subgoal S, then Sθ will use answers from S. — so only S will generate answers. If S is complete, no table entry for Sθ will be needed — as with call variance, we can simply backtrack through the trie. If S is incomplete, a subsumed subgoal frame will be made for Sθ and linked with the producing subgoal frame for S

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Call subsumption requires different table access methods (but note that with answer variance, answer check/insert can be the same as above) Subsuming-check/variant-insert for subgoals This check/insert operation backtracks through the trie, using “one-way” unification, potentially binding terms in Sc to TrieVars in Sg . Note that unification is “one-way” because Sg must subsume Sc . Bound variables are unbound at end of search. A greedy algorithm is used that prefers exact matches are preferred to variable bindings. We are guaranteed to derive a subsuming call if one exists, but it may not be minimal on the lattice of terms.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Answer Backtracking: because of call subsumption, when returning an answer A from Sg to Sc , A may not unify with Sc . Time-stamped tries [JRRR99]. are used for answers in call subsumption. The engine maintains a global time-stamp that is incremented each time an answer is added to any call-subsumptive table. When a new answer A is added, all nodes on the path of A have their time-stamps incremented. At various scheduling points (that occur at check complete) a routine backtracks through Sg to find a new set of answers that unify with Sc but have not been returned to it.

A new list of answer return nodes is created for Sc , which it backtracks through. This backtracking is the same as with call-variance as nodes in Sc ’s answer return list have been pre-selected to unify.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space: Performance

The methods presented consist of a set of optimizations: tries, substitution factoring, dynamic code (vs. interpreting the tries). [RRS+99] analyses various of these effects on various benchmarks. Dynamic code is the weakest of these optimizations. Performance gains of, e.g. tries, may be application specific, It may be best to think of them as an index that never does too badly and often does quite well. Tries open up a way to a new kind of programming. To take one example, consider answers like the following: hasAttr(oid(o2,test),rid(r4,test),oid(o12,test)) which indicates that object o2 in namespace test has a relation r4 (namespace test) to object o12 in namespace test. Tries can also be used for asserts (discussed later) and propagate the need for better indexing throughout a system.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Format of a Subgoal Frame

StatusInfo Information on Status of Table AnsTrieRoot Pointer to the Root of the Answer Trie AnsRetListH Pointer to the Head of the Answer Return List AnsRetListT Pointer to the Tail of the Answer Return List CCP Chain Pointer to the Head of the Consumer Choice Point Chain ComplSF Pointer to the Associated Completion Stack Frame GenCPPtr Pointer to Generator Choice Point NextSF Pointer to Next Subgoal Frame PreviousSF Pointer to Previous Subgoal Frame

StatusInfo indicates Type the type of table we’re computing: call variance, call subsumption generator, or call subsumption consumer is complete indicating whether the subgoal has been completed CCP Chain, ComplSF and GenCPPtr are used for scheduling NextSF and PreviousSF are used for memory management. Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Table Space

Summary We’ve discussed how tries are used for call variance and call subsumption, where, in both cases, answer variance was used. Subgoal tries for are always basic tries, although they may need to be interpreted in a different manner for call subsumption than for call variance Answer tries for call variance are basic tries, and are time-stamped tries for call subsumption We’ll be put more demands on tries for negation, for constraints and for memory management.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Stacks

0. p(a,Z) :- table p/2.

p(X,Z) :- p(X,Y),p(Y,Z). 1. p(a,Z) :- p(a,Y),p(Y,Z) 2. p(a,Z) :- e(a,Z),q(Z) p(X,Z) :- e(X,Z),q(Z).

e(a,b). e(a,d). e(b,c).

6. p(a,Z) :- p(b,Z) 3. p(a,b) :- q(b) 5. p(a,d) :- q(d) q(a). q(b). q(c).

Subgoal Answers State 11. p(a,c) :- 4. p(a,b) :- p(a,Z) p(a,b) Incomplete p(a,c) 6a. p(b,Z) p(b,Z) p(b,c) Incomplete p(c,Z) Incomplete

7. p(b,Z) :- p(b,Y),p(Y,Z) 8. p(b,Z) :- e(b,Z),q(Z) 12a. p(c,Z)

12. p(b,Z) :- p(c,Z) 9. p(b,c) :- q(Z) 13. p(c,Z) :- p(c,Y),p(Y,Z) 14. p(c,Z):- e(c,Z),q(Z)

10. p(b,c) :-

Recall from Lecture 2 that SLG evaluation uses a forest of trees How do we map this into the WAM stacks?

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Stacks

0. p(a,Z)

1. p(a,Z) :- p(a,Y),p(Y,Z) 2. p(a,Z) :- e(a,Z),q(Z)

6. p(a,Z) :- p(b,Z) 15. p(a,Z):- p(c,Z) 3. p(a,b) :- q(b) 5. p(a,d) :- q(d)

11. p(a,c) :- 4. p(a,b) :-

7. p(b,Z) :- p(b,Y),p(Y,Z) 8. p(b,Z) :- e(b,Z),q(Z)

12. p(b,Z) :- p(c,Z) 9. p(b,c) :- q(c)

10. p(b,c) :- 13. p(c,Z) :- p(c,Y),p(Y,Z) 14. p(c,Z) :- e(c,Y),q(Y)

Informally, a SLG Forest (with node ordering) can be mapped to an SLG Search Tree by merging an SLG tree T with the first call to the root subgoal of T . Here node 6a is merged with 6 and node 12a with 12 In general, various paths of an SLG Search Tree may need to be maintained (e.g. node 1 is called, but does not have an answer available until node 4 has been created, similarly with nodes 7 and 10).

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Stacks

freeze3 Consumer CP (14) p(c,Z)

Generator CP (13) p(c,Z) freeze2 freeze2 Consumer CP Consumer CP (8) p(b,Z) (8) p(b,Z)

Generator CP Generator CP Prolog CP (7) (7) (2) e(a,Z) p(b,Z) p(b,Z) freeze1 freeze1 freeze1 freeze1 Consumer CP Consumer CP Consumer CP Consumer CP (1) (1) (1) (1) p(a,Z) p(a,Z) p(a,Z) p(a,Z)

Generator CP Generator CP Generator CP Generator CP (0) p(a,Z) (0) p(a,Z) (0) p(a,Z) (0) p(a,Z) (a) At node 4 (b) At nodes (c) At nodes (d) After com- (e) After com- 7–10 13–14 pleting p(c,Z) pleting p(b,Z)

From an implementational point of view, the merging is called First Call Optimization with a single choice point and environment for the first call. SLG-WAM stacks act like Prolog when a computation has no tables, but may become trees when it does 5 5This is true of the SLG-WAM in YAP, but not in XSB Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Stacks

Computation paths in the trees now need to be suspended and resumed Freeze Registers maintain information about the top of each stack. Accordingly there is a EF register, a BF register, a TRF register and an HF register. Generator choice points are used in the SLG search tree to perform Program Clause Resolution for tabled subgoals, to schedule answer return and to perform incremental completion. Consumer choice points are used in the SLG search tree to perform Positive Return

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Stacks

Suspending and resuming requires backtracking plus restoration of bindings

Format of a trail frame in Edef

Parent Pointer to Parent trail frame Value Value to which the variable was bound Addr Address of the trailed variable

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Stacks

Algorithm switchEnvironments(new B) start TR := TR; end TR := choice point TR(new B); TR := choice point TR(new B); while (start TR != end TR) while (start TR > end TR) untrail(trail addr(start TR)); start TR := trail parent(start TR); while (end TR > start TR) end TR := trail parent(end TR); end TR := TR; while (start TR < end TR) * trail addr(end TR) := trail value(end TR); end TR := trail parent(end TR);

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Choice Points

Format of a Prolog choice point in Edef

FailCont The Failure Continuation EBreg Environment Backtrack Point Hreg Top of Global Stack (Heap) TRreg Top of Trail CPreg Success Continuation for Subgoal Ereg Parent Environment BregChain* Failure Continuation for Backtracking

An Argument Register n . . . . A1 Argument Register 1

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Choice Points

Format of a generator choice point in Edef is on next slide. Added cells are Freeze Registers, a pointer to the substitution factor, and a pointer to the subgoal frame in the table (used for scheduling)

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Choice Points

FailCont The Failure Continuation EBreg Environment Backtrack Point Hreg Top of Global Stack (Heap) TRreg Top of Trail CPreg Success Continuation for Subgoal Ereg Parent Environment BregChain* Failure Continuation for Backtracking SubsFact Ptr to Substitution Factor on Heap Subgoal Ptr to Subgoal Frame SugFr* Pointer to the Subgoal Frame BFreg* Choice Point Freeze Register HFreg* Heap Freeze Register TRFreg* Trail Freeze Register EFreg* Local Stack Freeze Register

An Argument Register n . . . . A1 Argument Register 1

Terrance Swift Topics in Logic Programming Implementation SLG-WAM: Choice Points

Format of a consumer choice point in Edef FailCont Pointer to answer return Instruction EBreg Environment Backtrack Point Hreg Top of Global Stack (Heap) TRreg Top of Trail CPreg Success Continuation Ereg Parent Environment BregChain* Failure Continuation for Backtracking LastAnswer* Pointer to Last Consumed Answer PrevCCP* Pointer for Consumer Choice Point Chain SubsFact Ptr to Substitution Factor on Heap

Like a generator choice point, a consumer choice point contains a pointer to the substitution factor, and a pointer to the subgoal frame. Contains a pointer to the last consumed answer, but requires no freeze registers.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 4: The SLG-WAM – Completion, Registers and Instructions

Terrance Swift Topics in Logic Programming Implementation SLG-WAM

Last time, we talked about how table access is done for subgoal check/insert in the new subgoal operation answer check/insert when a leaf node is created with an empty goal list answer backtracking for complete and incomplete tables, in the Positive Return operation We also talked about how WAM stacks are altered to represent the SLG search tree; freeze registers added to maintain separate computation paths; and the need to suspend computations and later resume them Finally, we introduced generator choice points, to perform program clause resolution for tabled subgoals consumer choice points, to perform positive return operations for incomplete subgoals In this lecture we’ll cover the basic SLG-WAM instructions Scheduling and Completion SLG-WAM Trie Instructions Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Instructions

Consider WAM compilation of this Prolog predicate:

ancestor(X,Y):- parent(X,Z),ancestor(Z,Y). ancestor(X,Y):- parent(X,Y).

test_heap, 2, 2000 try, 2, L1 trust, 2, L2 L1 allocate_gc, 2, 4 getpvar, 2, r2 putpvar, 3, r2 call, 4, 0x4007d0, ’parent’/2 putuval, 3, r1 putdval, 2, r2 deallocate xsb_execute, 0x400790, ’ancestor’/2 L2 xsb_execute, 0x4007d0, ’parent’/2

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Instructions

:- table ancestor/2. ancestor(X,Y):- parent(X,Z),ancestor(Z,Y). ancestor(X,Y):- parent(X,Y). ------test_heap, 2, 2000 * tabletry, 2, L1, 4008f0 * tabletrust, 2, L2 L1 allocate_gc, 2, 4 * getVn, 4 getpvar, 2, r2 putpvar, 3, r2 call, 5, 0x4007d0, ’parent’/2 putpval, 3, r1 putpval, 2, r2 call, 5, 0x400790, ’ancestor’/2 * check_interrupt, 5, 0x400790 * new_answer_dealloc, 2, 4 L2 allocate_gc, 2, 2 * getVn, 2 call, 3, 0x4007d0, ’parent’/2 * check_interrupt, 3 * new_answer_dealloc, 2, 2

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Instructions

We’ll discuss most of the new instructions in detail. For now

The choice point instructions (try, trust have been replaced by their table versions (tabletry, tabletrust). Both clauses end with a new answer dealloc instruction The second clause now requires an environment. We’ll see that this is required by new answer dealloc (and not just because of the dealloc The getVn instruction will be used to place a pointer to the generator choice point as a permanent variable in the environment In general, a choice point is also needed for tabled predicates. Tabled predicates use a tabletry, tableretry, tabletrust chain: but the tabletrust backtracks into a check complete instruction Tabled predicates with a single clause use a tabletrysingle instruction Interrupts are always checked before potentially adding a new answer (here through the check interrupt instruction)

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Instructions

Instruction tabletrysingle(Arity, Subgoal Trie Root) /* Subgoal is in argument registers */ If (subgoal check insert(Subgoal,Subgoal Trie Root) == new) (α) /* Subgoal is new and added */ Create and set up a subgoal frame SF for the Subgoal; Set up a generator choice point GCP to perform program clause resolution; Set the failure continuation FailCont cell of GCP to point to a check complete instruction; Push a new completion stack frame ComplSF onto the Completion Stack; /* discussed below */ Associate ComplSF with SF; Branch to the next instruction to perform program clause resolution; else /* Subgoal was not new — already existed in the Subgoal Trie */ If (SF ComplSF(Subgoal) == complete) (β) /* The subgoal frame has been marked as complete */ Answer Root := SF AnsTrieRoot(Subgoal); Branch to Answer Root to perform answer clause resolution by executing the code in the answer trie; else (γ) /* Subgoal is not new, and not complete */ Create a consumer choice point CCP for Subgoal, and add CCP to the head of Subgoal’s consumer choice point chain; Set the failure continuation FailCont cell of CCP to point to an answer return instruction; Call update dependencies(Subgoal); /* for scheduling ASCCs – discussed below */ Freeze stacks and fail into CCP to execute answer return instructions;

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Instructions

Instruction new answer dealloc(Arity,vm+1) /* vm+1 is the GCP pointer from the environment*/ answer table := SF AnsTrieRoot(GCP SubgFr(vm+1)); ηA := locate substitution factor(Arity,vm+1); /* ηA accessed via GCP */ if (answer check insert(ηA,answer table) == new) /* the answer substitution was inserted */ Deallocate local environment; Set the program pointer P to the continuation pointer CP; /* continue forward execution */ else fail; /* the answer substitution pointed by ηA was already present */

Edef the GCP keeps pointers to the substitution factor and to the subgoal frame Since new answer dealloc occurs at the end of a clause, we may not have access to the GCP through engine registers. We access it through the environment, to which we do have access

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Instructions

Instruction answer return CCP := B /* B register points to a consumer choice point */ Call switch environments(CCP) /* restore environment of the suspended consumer */ Restore values of WAM registers as saved in cells of the CCP if (the last answer consumed by this CCP is not the last of the answer return list) /* let ans be the first unconsumed answer of the answer return list */ CCP LastAnswer(CCP) := ans /* mark ans as consumed by CCP */ Load ans from the answer trie into the substitution factor of CCP Set the program pointer P to the continuation pointer CP /* continue forward execution */ else /* backtrack to another choice point */ B := CCP BregChain(CCP) /* backtrack */ fail /* Suspend the node to await further answers */

Answer return (Positive Return) is performed by backtracking into a consumer choice point

Terrance Swift Topics in Logic Programming Implementation SLG-WAM – Scheduling

Recall that a subgoal S can be completed when all program and answer clause has been performed for S, and all subgoals that S depends on. An SCC S is (maximal) independent if no subgoal in S depends on a subgoal outside of S. An Approximate SCC, ASCC A is a set of SCCs such that no subgoal in A depends on any subgoal outside of A The Completion Stack contains maintains information on ASCCs for use in incremental completion For Local Evaluation, the ASCCs maintained are actual SCCs for non-ground goals. A completion stack frame: SubgFr Pointer to Subgoal Frame Subg# Unique Subgoal Number DirLink Deepest Direct Dependency

Terrance Swift Topics in Logic Programming Implementation SLG-WAM – Scheduling

A very general viewpoint ASCC information is maintained in the completion stack as our representation of the SLG forest changes. When we backtrack to a generator choicepoint G that is the oldest in the ASCC (termed the leader of the ASCC) we perform a fixpoint check to see whether all answer resolution has been performed on tabled subgoals in the ASCC If there are no more answers to return, we complete the tables in the ASCC; reset the freeze registers, effectively reclaiming all stack space for the ASCC; then backtrack to the previous choice point If there are more answers to return we schedule them so that after having returned all answers currently available, we will backtrack to G. When G is backtracked into again, the ASCC may have changed and so it may not be the oldest in the ASCC.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM – Scheduling

:- table p/2, r/1, q/1.

p(X,Y) :- q(X), r(Y). p(c,a).

q(a). q(b).

r(c). r(X) :- p(X,Y). ?- p(X,Y). p(X,Y) + + r(Y) 3 1 1 + q(X) 2 2 1 1 q(X) r(Y) p(X,Y) 1 1 Terrance Swift SubgoalTopics in LogicSubg# ProgrammingDirLink ImplementationMinLink(S) SLG-WAM – Scheduling

The completion stack maintains the ASCC of a subgoal via a MinLink – conceptually, the minimum of all DirLink values for all subgoals equal to it or younger than it on the completion stack In tabletry(single) (new subgoal) a newly created completion stack frame is assigned a new global Subg#, and a DirLink equal to Subg#

When a tabled subgoal Scalled becomes the selected literal in the node of a tree with root Sroot , set DirLink(Sroot ) equal to

min[DirLink(Sroot ), MinLink(Scalled )]

DirLink values are adjusted during the New Subgoal operation A node is a leader if Subg# = MinLink This ASCC conssts of 2 maximal independent SCCS, {p(X , Y ), r(Y )} and {q(X )} q(X ) is sometimes called a trapped SCC

Terrance Swift Topics in Logic Programming Implementation SLG-WAM – Scheduling

Batched scheduling was not explained in detail last time, but we now have enough background to understand its details. Let N be a node Answer Template:-S, Goal List, in an SLG tree where S is tabled.

1 The SLG-WAM schedules Program Clause Resolution as does the WAM: clauses are resolved according to their textual order and literals are selected by a fixed left-to-right rule.

2 If S is complete, the node N need not be suspended and answers can be returned to it as if they were program clauses.

3 If S is incomplete, any answers for S are returned to N under a model that approximates program clause scheduling: the first answer is immediately returned upon the creation of N, and a consumer choice point frame is set up to return any further answers to N. Only when N exhausts all answers (currently) in the table for S will it suspend.

4 Answers may also be scheduled for return to N during the procedure fixpoint check() performed by the leader SL of the scheduling ASCC of S. This fixpoint check() is executed during the check complete instruction for SL.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Instructions

Instruction check complete 0 SubgComplStFr := SF ComplSF(GCP SubgFr(B)); /* Access Completion Stack via Subgoal Frame via GCP*/ 1 If (Subgoal is the leader of a scheduling ASCC, A) 1.1 Call fixpoint check(SubgCSF ); 1.2.1 Mark as complete all subgoals in A; 1.2.2 Reclaim the stack space of subgoals in A and adjust the freeze registers; 2 B := GCP BregChain(B); 3 fail;

Only the leader will schedule and potentially complete the subgoals Non-leaders will simply fail

Procedure fixpoint check(SubgCSF ) /* SubgCSF is a pointer to the completion stack frame */ while (SubgCSF is less than or equal to the top of the completion stack) SubgFr := CSF SubgFr(SubgCSF ); Call schedule resumes(SubgFr); /* a failure continuation is taken if any consumer choice */ /* point associated with SubgFr has unconsumed answers (cf. Figure ??) */ Increment SubgCSF by the size of a completion stack frame;

Terrance Swift Topics in Logic Programming Implementation SLG-WAM – Scheduling

Procedure schedule resumes(SubgFr) /* SubgFr is a pointer to the subgoal frame for subgoal S */ CCP Head := SF CCPChain(SubgFr); /* consumer choice point chain for S */ First CCP := NULL; Starting from CCP Head traverse the consumer choice point chain and set First CCP to point to the first consumer choice point with unconsumed answers, if any; if (First CCP != NULL) Create a consumer choice point backtracking chain, and set the BregChain cell of its last element to point to the choice point currently pointed by B B := First CCP; fail; /* to execute answer return instructions by picking up the failure continuation */

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Table Instructions

In the last lecture, it was stated that tries contained SLG-WAM instructions so that they can be thought of as dynamically compiled code. Let’s see what this code looks like. The prefix-factored code maps to a trie: each predicate symbol is a node, and each rule is a transition.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Table Instructions

On the left as a list of facts On the right as a “prefix-factored” set of clauses

rt(a,X2,X3) :- rt a(X2,X3). rt(b,X2,X3) :- rt b(X2,X3). rt a(f(X1.1,X1.2),X2) :- rt af(X1.1,X1.2,X2). rt a(g(X1.1,X1.2),X2) :- rt ag(X1.1,X1.2,X2). rt b(V,X2) :- rt bV(X2). rt(a,f(a,b),a). rt af(a,X2,X3) :- rt afa(X2,X3). rt(a,f(a,V),b). rt ag(b,X2,X3) :- rt agb(Y,X3). rt(a,g(b,c),c). rt bV(d). rt(b,V,d). rt afa(b,X2) :- rt afab(X2). rt afa(V,X2) :- rt afaV(X2). rt agb(c,X2) :- rt agbc(X2). rt afab(a). rt afaV(b). rt agbc(c).

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Table Instructions

How would these Prolog clauses be compiled in the WAM? rt(a,X2,X3) :- rt a(X2,X3). rt(b,X2,X3) :- rt b(X2,X3).

rt a(f(X1.1,X1.2),X2) :- rt af(X1.1,X1.2,X2).

rt1: try me else rt2 rt2: trust me else fail rt a1: try me else rt a2 get constant a, A1 get constant b, A1 get structure f/2, A1 shift left 1 shift left 1 shift right 1 execute rt a/2 execute rt b/2 unify variable V1 unify variable V2 execute rt af/3

shift right is simply an abbreviation for some number of puttvar instructions

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Table Instructions

We can break the above instructions down into 5 parts:

1 the choice alternative; 2 the get type alternative (if trie instructions are only used for call variance, the general unification can be specialized, as it is known that binding will be to variables. 3 the constant, structure symbol, or variable to match (Symbol); (The argument register involved in the get type instructions is always register 1 (A1). 4 the address of the next code segment down the trie (ContLabel); and, 5 the address of the alternative to try on failure (FailLabel). So, the general form of the trie instructions is:

trie choice type Symbol, ContLabel, FailLabel

Terrance Swift Topics in Logic Programming Implementation SLG-WAM - Table Instructions

So far we have:

Unique First Intermediate Last Constant trie do constant trie try constant trie retry constant trie trust constant Structure trie do structure trie try structure trie retry structure trie trust structure List trie do list trie try list trie retry list trie trust list Variable trie do variable trie try variable trie retry variable trie trust variable Variable trie do value trie try value trie retry value trie trust value

Functionality of a proceed is also needed once the leaf is reached. This is done by creating explicit escape nodes with a proceed instruction, or by mega-instructions such as trie xxx constant proceed Hash nodes also have an instruction: hash handle that backtracks through the hash table (if called with a variable) or backtracks through a hash bucket 6

6Currently, in XSB this is done by hash handle together with another instruction hash opcode. Terrance Swift Topics in Logic Programming Implementation SLG-WAM – Call Subsumption

Producer frame S

Subsumed Frame S Subsumed Frame S η θ

Answer List for S η

Answer List for S θ

Answer List for S

Terrance Swift Topics in Logic Programming Implementation SLG-WAM – Call Subsumption

In Call Subsumption, each subgoal frame for a producer subgoal S may be linked to a chain of subsumed subgoal frames (e.g. Sθ, Sη), where each subsumed subgoal frame has its own answer list.

Terrance Swift Topics in Logic Programming Implementation SLG-WAM – Call Subsumption

Answer returns for consumer choice points for Sθ and Sη are scheduled at completion in a manner similar to call variance, but with the following differences When all consumer choice points for a subsumed subgoal (say, Sθ )have backtraced through all answers in their answer list, the answer trie for S is checked to determine if there are new answers that haven’t been returned to Sθ. Thus, obtaining answers for subsumed goals may require backtracking multiple times through the answer trie. This backtracking can be optimized by time-stamped tries. A thread global time stamp is augmented whenever a new answer is added to a time-stamped trie. A node for a time-stamped tries contains a time-stamp field along with the other fields of a basic trie node When an answer A is added at time T , each node checked or added in the traversal of the answer trie has its time-stamp set to T . The time stamp of a node is thus set to the maximal time stamp of any of its descendents. Each subsumed subgoal frame contains the time stamp at which its answer list was last updated (even if no nodes were added to the answer list). Thus, when backtracking to determine if there are more answers for Sθ, only nodes with time stamp greater than the time stamp of Sθ need to be explored.

Terrance Swift Topics in Logic Programming Implementation Tabling – Overview

What is the state of tabling implementations?

XSB: Variant or Subsumptive tabling for (Well-Founded Semantics (WFS) with. constraints; Incremental tabling for definite programs; based on SLG-WAM. Multithreaded implementations of all of except incremental tabling for thread-private tables Multithreaded implementations of variant-based tabling for thread-shared tables. YAP: Parallel tabling for definite programs [RSC04b] as based on the SLG-WAM. Dynamic Scheduling Strategy [RSC05] Optional Global Tables [CR09] Work underway for stratified negation and thread-private tables. B-Prolog: Implementation based on linear tabling [ZSYY01, ZSS04]

Terrance Swift Topics in Logic Programming Implementation Tabling – Overview

Ciao: implementation based on a portable library [GCH09] that uses tries and local scheduling but that is not based on SLG-WAM. Mercury – initial implementation of tabling for definite programs with call variance [SS06]. Implementation is based on CAT [DS98], which differs from the SLG-WAM in using copying for suspension and resuming, rather than a cactus stack SWI – Rumors that library-based implementation similar to Ciao’s will be supported.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 5: Tabling with Negation: Stratification Theories, SLG resolution, Scheduling Strategies.

Terrance Swift Topics in Logic Programming Implementation Tabling with Negation: Overview

We’ll discuss well-founded negation and applications for which it is useful. We’ll cover stratification theories and show how tabling can be used to compute programs with a form of stratified negation. This will correspond to an engine Estrat to be discussed in the next topic. We’ll then introduce computation of Well-Founded Semantics (WFS) [vRS91] through dynamically stratified programs [Prz89a]. Finally, we’ll review the relation between WFS and stable models to introduce the concept of residual programs. An engine to compute such programs, Ewfs , will be also discussed in the next topic.

Terrance Swift Topics in Logic Programming Implementation Well-founded semantics

What does WFS do for us? It gives a semantics for all normal logic programs In particular it allows logic programs to adequately handle inconsistencies and paraconsistencies, for example: The village barber shaves everyone in the village who does not shave himself [Dun91].

shaves(barber,Person):- villager(Person), not shaves(Person,Person). shaves(doctor,doctor).

villager(barber). villager(mayor). villager(doctor). The barber shaves the mayor, does not shave the doctor, and it is unknown whether he shaves himself. Helps logic programming systems to be used to explore knowledge representation, through extensions to WFS and residual programs

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Verification

Verification of concurrent systems, workflows, agent interactions is often done through model-checking Recall that model-checking usually uses two levels of formalization (see e.g. [Sti]) A process logic such as CCS [Mil89]; π-calculus [MPW92a, MPW92b]. These calculi can usually be modeled via definite logic programs. A temporal logic for reasoning about properties of paths in such as the modal-µ calculus [Koz83], CTL [EH], or LTL [?]. These logics require not only least fixed points (which can be computed through definite programs) but also greatest fixed points (which may require non-stratification).

Terrance Swift Topics in Logic Programming Implementation WFS Applications: Verification

:- table |=/2. :- table |/=/2. State s |= prop(P):- State s |/= prop(P):- has prop(State s,P). \+ has prop(State s,P). State s |= diam(Act a,F):- State s |/= diam(Act a,F):- trans(State s,Act a,State t), tfindall(State t, State t |= F. trans(State s,Act a,State t), State ts), ’list |/=’(State ts, F). State s |= and(X 1, X 2)):- State s |/= and(X 1, X 2)):- State s |= X 1, State s |= X 2. State s |/= X 1 ; State s |= X 2. State s |= or(X 1, X 2)):- State s |/= or(X 1, X 2)):- State s |= X 1 ; State s |= X 2. State s |/= X 1, State s |/= X 2. State s |= form(X):- State s |/= form(X):- formula def(X, Y), formula def(X, Y), ( Y = lfp(Z), ( Y = lfp(Z), State s |= Z tnot(State s |= State s, Z) ;; Y = gfp(Z), Y = gfp(Z), tnot(State s |/= Z) ). State s |/=Z ).

Non-Alternating modal-µ calculus formulas are stratified Alternating modal-µ calculus formulas are non-stratified [RRR+97] (alternating formulas are sometimes used to prove fairness)

Terrance Swift Topics in Logic Programming Implementation WFS Applications– Flora-2

Object-oriented logic programming may require non-monotonic or “defeasable” inheritance (note that the inheritance described differs from that in ontologies, which is monotonic). Consider this Flora-2 knowledge base. elephant[color*=>color] /* the color attribute of an elephant is functional */ royal elephant::elephant /* a royal elephant is an elephant */ clyde:royal elephant /* clyde is a royal elephant */ elephant[color*->grey] /* an elephant is grey (functional) */ we conclude that clyde is grey If we add the fact royal elephant[color*->white] we conclude that clyde is white Knowledge bases like this are compiled into XSB and evaluated using tabled negation.

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Flora-2

Inheritance structures are not always stratified. Consider the “Nixon diamond” problem republican[policy *-> nonpacifist] quaker[policy *-> pacifist] nixon:quaker nixon:republican

Nixon’s policy is undefined, and this knowledge base translates into a non-stratified program.

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Medical Informatics

Diagnostic Criteria for Dementia of the Alzheimers Type [APA94] The development of multiple cognitive defects manifested by both memory impairment (impaired ability to learn new information or to recall previously learned information) one (or more) of the following cognitive disturbances aphasia (language disturbance) apraxia (impaired ability to carry out motor activities despite intact motor function) agnosia (failure to recognize or identify objects despite intact sensory functions) disturbance in executive functioning (i.e., planning, organizing, sequencing, abstracting) The cognitive deficits in criteria A1 and A2 each cause significant impairment in social or occupational functioning and represent a significant decline from a previous level of functioning. The course is characterized by gradual onset and continuing cognitive decline.

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Medical Informatics

The cognitive deficits in Criteria A1 and A2 are not due to any of the following other central nervous system conditions that cause progressive deficits in memory and cognition (e.g. cerebrovascular disease, Parkinson’s disease, Huntington’s disease, subdural hematoma, normal-pressure hydrocephalus, brain tumor) systemic conditions that are known to cause dementia (e.g. hypothyroidism, vitamin B12 or folic acid deficiency, niacin deficiency, hypercalcemia, neurosyphilis, HIV infection) substance-induced conditions The deficits do not occur exclusively during the course of a delirium The disturbance is not better accounted for by another Axis I disorder (e.g., Major Depressive Disorder, Schizophrenia)

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Medical Informatics

DSM-IV sometimes gives loops through negation [GST+00] ’Alzheimers Dementia’ :- not_better ’Major Depressive Disorder’ ’Major Depressive Disorder’:- not_better ’Alzheimers Dementia’ Diagnostic and other applications can be improved using both default and explicit negation.

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Medical Informatics

WFS reflects through a meta-interpreter

:- table demo/1.

demo(true). demo((X,Y)):- !,demo(X),demo(Y). demo(not(X)):- !,tnot(demo(Y)). demo(X):- clause(X,Y),demo(Y).

But we already can compute WFS ... so what?

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Medical Informatics

WFSX can also be implemented as a meta-interpreter. Now you can model both default and explicit negation

demo(A):- demo t(A). demo(A):- demo tu(A).

:- table demo t/1, demo tu/1. demo t(true). demo tu(true). demo t(’,’(A,B)):-!, demo t(A),demo t(B). demo tu(’,’(A,B)):-!, demo tu(A),demo tu(B). demo t(not A):-!, tnot(demo tu(A)). demo tu(not A):-!, tnot(demo t(A)). demo t(A):- clause(A,B), demo t(B). demo tu(A):-clause(A,B), demo tu(B), exchange(A,A opp),demo tu(not A opp).

exchange(-A,A):-!. exchange(A,-A). But that’s not an application ... so what?

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Informatics

An Extended Logic Program (C. Damasio) perforation(X) <- sudden_pain(X),abd_tenderness(X), peritoneal_irritation(X), not_believed high_amylase(X). pancreatitis(X) <- sudden_pain(X),abd_tenderness(X), peritoneal_irritation(X), not_believed jobert(X).

-nourish(X) <- perforation(X). -nourish(X) <- pancreatitis(X).

h2_antagonist(X) <- pancreatitis(X). h2_antagonist(X) <- perforation(X).

surgery_indication(X) <- perforation(X). -surgery_indication(X) <- pancreatitis(X).

anesthesia(X) <- surgery_indication(X).

Terrance Swift Topics in Logic Programming Implementation WFS Applications – Medical Informatics

Default negation is used when something is shown false because there was no evidence Explicit negation is used when something is explicitly known (or proved) to be false Loops through negation may be resolved by preferences DSM-IV criteria have been modeled using Prolog rules and used in a commercial system by Medicine Rules, Inc.

Terrance Swift Topics in Logic Programming Implementation WFS Applications

In some applications WFS gives a way to detect inconsistencies (Flora, Medical Informatics). Some of these inconsistencies may be resolved by preference rules (e.g. a politician’s policy is based most strongly on his/her party affiliation) In other applications, WFS reduces a program to a kernel over which more computationally complex processing should be done (stable model computation, alternating modal-µ calculus).

Terrance Swift Topics in Logic Programming Implementation Negation: Stratification Theories

dynamically stratifed

lr-dynamically stratified weakly stratified

lr-weakly stratified

(lr)-modularly stratified

locally stratifed

predicate stratified

Terrance Swift Topics in Logic Programming Implementation Negation: Stratification Theories

Lower stratification classes are computed by Determining a dependency graph (DG) Determining whether components in the dependency graph contain cycles through negation Examples: Predicate Stratification [ABW88]: single DG for entire program, based on predicate dependencies. Local Stratification [Prz88]: single DG for entire (grounded) program, based on atom dependencies.

Terrance Swift Topics in Logic Programming Implementation Negation: Stratification Theories

Forming a dependency graph and checking for loops through negation is performed iteratively in the higher stratification classes such as modular stratification [Ros94] and weak stratification [PP88]. Given a partial model I, you reduce a ground program by I by

Removing any clause H :- L1, ..., not Ai , Ln. where Ai is true in I

Remove the literal notAi from a clause H :- L1, ..., not Ai , ..., Ln. where Ai is false in I producing the clause H :- L1, ..., Ln. A ground program P may not be stratified when taken as a whole, but you can find the first stratum I0, reduce by I0, find the second stratum of P , I , reduce P by I and so on. I0 1 I0 1

Terrance Swift Topics in Logic Programming Implementation Negation: Stratification Theories

In the rest of this lecture... We’ll present fixed-order dynamically stratified programs [SSW00b] (or LRD-stratified programs) at an intuitive level, and show how they can be computed with an extension of the tabling operations we’ve seen so far. We’ll then get formal with Dynamic Stratification [Prz89a, BF91] in detail. Note that with the exception of Predicate Stratification, these properties may depend on infinite dependency graphs or on iterated fixed points – and so are undecidable in general.

Terrance Swift Topics in Logic Programming Implementation Negation: Stratification Theories

1 An LRD-stratified program that is not locally or modularly stratified, but is weakly stratified. p(b). p(X) :- t(X,Y,Z), not q(c), q(b), not p(Y). t(a,b,a). q(c):- not p(b).

2 An LRD-stratified program that is not weakly stratified p(a):- not p(a). p(a). Intuitively, an LRD-stratified program is one that isn’t faced with a loop through negation because: it either fails before it encounters that loop (as 1) or can resolve the loop via a positive proof of the negated literal (as 2)

Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of an LRD-Stratified Program

:- table p/1. p(a) :- p(b), not p(d). p(b) :- p(c). p(b). p(b) :- not p(d). p(b) :- not p(a). p(c) :- p(b), p(e). p(d) :- not p(c), p(d) p(e) :- p(c). p(e) :- not p(b), not p(e).

0. p(a) 1a. p(b) 2a. p(c)

1. p(a) :- p(b), not p(d) 3. p(c) :- p(b), p(e) 2. p(b) :- p(c) 6. p(b) :-

7. p(a) :- not p(d) 4. p(a) :- not p(d) 8. p(c) :- p(e)

4a. p(d) 8a. p(e)

5. p(d) :- not p(c), p(d) 9. p(e) :- p(c) 10. p(e) :- not p(b), not p(e)

11. fail The above figure represents a partial computation

Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of an LRD-Stratified Program

p(a) -

p(d) -

p(c) + +

p(e)

Now our SDGs have signed edges. After completing p(c) and p(e) they will be failed; the computation of p(d) can continue and will fail; the computation of p(a) will then continue and succeed.

Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of LRD-Stratified Programs

The definition of completely evaluated (slide 63) states that A ground subgoal is completely evaluated when an answer is derived for it. This facet of the definition (sometimes called early completion) is needed to exclude cyclic negative dependencies through p(b). We do need a new tabling operation to produce node 11. Negative Return Let Fn contain a leaf node

N = Ans :- not S, Goal List.

whose selected literal not S is ground. 1 Negative Success: If S is failed in F, then create a child for N of the form: Ans :- Goal List. 2 Negative Failure: If S successful in F, then create a child for N of the form fail 7

7The terms successful and failed will be defined later. Terrance Swift Topics in Logic Programming Implementation Negation: Dynamic Stratification

The power of Dynamic stratification can be seen from the following theorem

Theorem [Prz89a] A program is Dynamically Stratified iff it has a two-valued well-founded model.

Intuition: WFS treats paths with infinite positive recursion as failed, and paths with infinite recursion through negation as undefined. We’ll use the loop-checking features of tabling (among other things) to evaluate WFS.

Terrance Swift Topics in Logic Programming Implementation Negation: Dynamic Stratification

p(b). p(c) :- not p(a). p(X) :- t(X,Y,Z), not p(Y), not p(Z). t(a,b,a). t(a,a,b). The ground instantiation of the above program is:

p(b). p(c):- not p(a). p(a) :- t(a,a,a), not p(a), not p(a). p(a) :- t(a,a,b), not p(a), not p(b). : p(a) :- t(a,b,a), not p(b), not p(a). : p(c) :- t(c,c,c), not p(c), not p(c). t(a,b,a). t(a,a,b). This program has a 2-valued model: w.r.t p/1 it is {p(b), p(c)} = true; {p(a)} = false

but it cannot be evaluated with a fixed literal selection strategy

Terrance Swift Topics in Logic Programming Implementation Negation: Dynamic Stratification

Dynamic stratification iteratively finds an interpretation I for a ground program, and reduces the rest of the program with respect to I . Start with I0 = ∅

Ah :- A1, ..., Am, not Am+1, ..., not An

To determine positive facts find the least fixpoint of the operator

TI (T ) = {A : there is a clause B ← L1, ..., Ln in P and a ground substitution θ such that A = Bθ and for every 1 ≤ i ≤ n either Li θ is true in I , or Li θ ∈ T }; To determine negative facts, find the greatest fixpoint of the operator

FI (F ) = {A : for every clause B ← L1, ..., Ln in P and a ground substitution θ such that A = Bθ and there is some i (1 ≤ i ≤ n), such that Li θ is false in I or Li θ ∈ F }.

Terrance Swift Topics in Logic Programming Implementation Negation: Dynamic Stratification

The first partial model, I0 is ∅ so the operators effectively work on the program p(b). p(c):- undef.

p(a) :- t(a,a,a), undef,undef. p(a) :- t(a,a,b), undef,undef. : p(a) :- t(a,b,a), undef,undef. : p(c) :- t(c,c,c), undef,undef. t(a,b,a). t(a,a,b).

Whose fixpoint gives I1 in which true I1 = {p(b), t(a, a, b), t(a, b, a)} are true and false I1 = {t(a, a, a), t(a, a, c), ...} are false. Terrance Swift Topics in Logic Programming Implementation Negation: Dynamic Stratification

Thus the second reduction is p(c):- undef. p(b). t(a,b,a). t(a,a,b). true true false false Now I2 = I1 , while I2 = I1 ∪ {p(a)}, and the third reduction is p(c). p(b). t(a,b,a). t(a,a,b). true Which adds p(c) to I3 . Further iterations will not change I3, which is, in fact, a model for the program. Any undefined literals at the end of this iterative process may be said to be in the ultimate stratum. Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of WFS

The method just shown was pure bottom-up. To make it goal-oriented requires a notion of relevance. Assuming (as always) a left-to-right computation rule: In Prolog, relevant literals for a selected clause belong to a failing prefix. p(a) :- t(a,b,a), not p(b), not p(a). To get this dynamic stratification an evaluation cannot view only a prefix. p(a) :- t(a,a,b), not p(a), not p(b). Are relevant literals all those in a body for a selected clause?

Terrance Swift Topics in Logic Programming Implementation 1. p(c):− | p(c)

2. p(c):− | not p(a)

3. p(a):− | p(a)

6. p(a):− | t(a,b,a),not p(b), not p(a). 4. p(a):− | t(a,a,b),not p(a), not p(b).

7. p(b):− | not p(b), not p(a) 5. p(a):− | not p(a),not p(b)

10, fail

8. p(b) :− | p(b) (completed)

9. p(b) :− |

:- table p/1. p(b). p(c) :- not p(a). p(X) :- t(X,Y,Z), not p(Y), not p(Z). t(a,b,a). t(a,a,b).

Terrance Swift Topics in Logic Programming Implementation 1. p(c):− | p(c)

2. p(c):− | not p(a)

11. p(c):− not p(a) |

3. p(a):− | p(a)

6. p(a):− | t(a,b,a),not p(b), not p(a). 4. p(a):− | t(a,a,b),not p(a), not p(b).

5. p(a):− | not p(a),not p(b) 7. p(b):− | not p(b), not p(a)

10. fail 12. p(a):− not p(a) | not p(b)

13. fail

completed 8. p(b):− |p(b)

9. p(b) :− |

:- table p/1. p(b). p(c) :- not p(a). p(X) :- t(X,Y,Z), not p(Y), not p(Z). t(a,b,a). t(a,a,b).

Terrance Swift Topics in Logic Programming Implementation 1. p(c) :− | p(c)

2. p(c):− | not p(a)

11. p(c):− | not p(a)

14. p(c) :− |

3. p(a) :− | p(a)

6. p(a):− | t(a,b,a),not p(b), not p(a). 4. p(a):− | t(a,a,b),not p(a), not p(b).

7. p(b):− | not p(b), not p(a) 5. p(a):− |not p(a),not p(b)

10. fail 12. p(a):−not p(a) | not p(b)

13. fail completed 8. p(b) :− | p(b)

9. p(b) :− |

:- table p/1. p(b). p(c) :- not p(a). p(X) :- t(X,Y,Z), not p(Y), not p(Z). t(a,b,a). t(a,a,b).

Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of WFS

Let’s review how each node was produced. 1 Initial Forest 2 Program Clause Resolution 3 New Subgoal 4 Program Clause Resolution 5 Program Clause Resolution (t/3 is not tabled) 6 Program Clause Resolution 7 Program Clause Resolution 8 New Subgoal 9 Program Clause Resolution 10 Completion of p(b) + Negative Return 11 Delaying 12 Delaying 13 Negative Return 14 Simplification Note that the evaluation was not delay-minimal, and completion was not fully incremental. If the delaying operation in 12 had been performed and p(a) completed, no Delaying operation would have been needed in the p(c) tree. Also note that we can mix evaluation of tabled with non-tabled predicates.

Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of WFS

So that’s what the | means. An answer is unconditional if there are no literals to the left of the |; otherwise it is conditional Let F be a forest. We say that an atom S is failed in F if S is completely evaluated in F, and S has no answers. We say that an atom S is successful in F if the tree for S has an unconditional answer S.

SLG Answer Resolution Let N be a node H :- D|L1, ..., Ln, where n > 0. Let Ans = A0 :- D0| be an answer whose variables have been standardized 0 apart from N. N is SLG resolvable with Ans if Li and A are unifiable with an mgu θ. The SLG resolvent of N and Ans on Li has the form

(A :- D|L1, ..., Li−1, Li+1, ..., Ln)θ if D0 is empty, and

(A :- D, D|L1, ..., Li−1, Li+1, ..., Ln)θ

Li otherwise, where D = Li if Li is negative, and D = Li A0 otherwise. Positive delayed literals are added only by SLG Answer Resolution, not directly by Delaying

Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of WFS

We introduced two new operations which may be applicable to a node in a forest Fn: 8 Delaying: Let Fn contain a leaf node

N = Ans :- DelaySet|not S, Goal List

with selected literal not S such that S is ground, in Fn, but S is neither successful nor failed in Fn. Then create a child for N of the form

Ans :- DelaySet, not S|Goal List

8This definition of Delaying assumes a left-to-right literal selection strategy. Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of WFS

So that’s what the | means. An answer is unconditional if there are no literals to the left of the |; otherwise it is conditional Let F be a forest. We say that an atom S is failed in F if S is completely evaluated in F, and S has no answers. We say that an atom S is successful in F if the tree for S has an unconditional answer S.

SLG Answer Resolution Let N be a node H :- D|L1, ..., Ln, where n > 0. Let Ans = A0 :- D0| be an answer whose variables have been standardized 0 apart from N. N is SLG resolvable with Ans if Li and A are unifiable with an mgu θ. The SLG resolvent of N and Ans on Li has the form

(A :- D|L1, ..., Li−1, Li+1, ..., Ln)θ if D0 is empty, and

(A :- D, D|L1, ..., Li−1, Li+1, ..., Ln)θ

Li otherwise, where D = Li if Li is negative, and D = Li A0 otherwise. Positive delayed literals are added only by SLG Answer Resolution, not directly by Delaying

Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of WFS

We introduced two new operations which may be applicable to a node in a forest Fn: 9 Delaying: Let Fn contain a leaf node

N = Ans :- DelaySet|not S, Goal List

with selected literal not S such that S is ground, in Fn, but S is neither successful nor failed in Fn. Then create a child for N of the form

Ans :- DelaySet, not S|Goal List

9This definition of Delaying assumes a left-to-right literal selection strategy. Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of WFS

Simplification: Let Fn contain a leaf node

N = Ans :- DelaySet|

with D ∈ Delayset. If D = not Subg and

Subg is failed in Fn then create a child Ans :- DelaySet0|

for N, where Delay Set0 = Delay Set − Subg. Subg succeeds in Fn then create a child fail for N. Subg Otherwise, if D = LA0 and 0 A succeeds in Fn, then create a child Ans :- DelaySet0|

for N, where Delay Set0 = Delay Set − Subg. 0 A is failed in Fn, then create a child fail for N.

Terrance Swift Topics in Logic Programming Implementation Negation: Tabled Evaluation of WFS

SLG Answer Resolution adds a positive literal to the delay list rather than the negative delayed literals in order to avoid exponential blowup in the answers returned. Subgoal Delayed literals sometimes are depicted as LAnswer . A delayed literal L may be unified by further resolution of literals, but the Subgoal before the answer resolution is not, nor is the Answer used for answer resolution. This is definition of Simplification explains the behavior of XSB and has a variant flavor. For non-ground positive literals A delayed literal fails a clause if its Subgoal fails. A delayed literal is removed if its Answer becomes unconditional. Other forms of subsumptive simplification are possible, such as failing the clause if Lθ is failed, or removing the literal if there is a Lθ that is conditional [Swi99a] In a program P, if clauses all have the form

Head : −L1, ..., Lm, notLm+1, ..., notLn All bindings will have been made before any delaying occurs.

Terrance Swift Topics in Logic Programming Implementation Negation: Answer Completion

Unfortunately, Delaying and Simplification are not always enough. Consider this program under local evaluation. :- table p/0, s/0, r/0. p:- p. p:- tnot(s). s:- tnot(r). s:- p. r:- tnot(s),r. A query ?- p will detect a loop, then call s. s will call r and r will call s; finally s will call p At this point, p, s and r are in the same SCC. Delaying is applied to the literals tnot(s) and tnot(r). The various computations are re-invoked: conditional answers p :- tnot(s)| and s:- tnot(r)| are derived. New conditional answers s:- p| and p:- p| are derived. r is failed. s:- tnot(r)| is simplified to a unconditional answer; the conditional answer p:- tnot(s) is removed through simplification The conditional answer p:- p| remains, giving p a truth value of undefined rather than of false. This computation is informationally sound, but not complete.

Terrance Swift Topics in Logic Programming Implementation Negation: Answer Completion

Let’s take a closer look at what was wrong with p. In SLG terminology, it was unsupported Definition (Supported Answer) Let F be a SLG forest, S a subgoal in F, and Answer be an atom that occurs in the head of some answer of S. Then Template is supported by S in F if and only if:

1 S is not completely evaluated; or

2 there exists an answer node

Answer :- Delay Set|

Call of S such that for every positive delay literal DAns , Ans is supported by Call.

Our final SLG operation removes unsupported answers: Answer Completion: Given a set of unsupported answers UA, create a failure node as a child for each answer Ans ∈ UA. Terrance Swift Topics in Logic Programming Implementation Negation: Answer Completion

Note that if we had postponed returning the conditional answer for p to p:- p we wouldn’t have needed Answer Completion For a datalog program P of size N Computing WFS has worst-case complexity of O(N2), as does computing a query to P via SLG. It can be shown that any SLG evaluation of a query Q to P that does not include Answer Completion is O(N) It can further be shown that there exists some SLG evaluation that does not require answer completion and that is O(N) (but you need a O(N2) oracle to figure out the next operation) The need for Answer Completion is rare in programs that I’ve seen, but is being implemented in XSB’s engine [SPP09]

Terrance Swift Topics in Logic Programming Implementation Negation: Answer Completion

For a normal program P, the well-founded model of P is contained in the intersection of all stable models of P [Prz89b] Thus, the conditional answers of a query to P form a residual program that can be used to compute the stable models of P using the notion of Revised Stable Models [PP05]

Terrance Swift Topics in Logic Programming Implementation Summary: Computing the WFS

We introduced LRD-Stratified programs which can be computed using the operations for definite programs along with Negative Return and full Completion We then showed how full WFS requires Delaying, Simplification, and Answer Completion, although Answer Completion is rarely needed in practice. LRD-Stratified programs are important in themselves, and also because if we can compute LRD-Stratified programs without Delaying we can ensure relevance. An evaluation is delay minimal if it never performs a delay operation for a subgoal S some other operation is possible on the tree for S or for some other subgoal that S depends on.

Terrance Swift Topics in Logic Programming Implementation ¡

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 6: The SLG-WAM 3: Implementation of Tabled Negation

Terrance Swift Topics in Logic Programming Implementation The SLG-WAM: Negation Overview

We begin by describing Estrat which can evaluate LRD-stratified programs, and which implements the following two SLG extensions: The Negative Return operation. The following clause of completely evaluated (slide 63): A ground subgoal is completely evaluated when an answer is derived for it

We then describe Edelay which adds the Delaying operation which extends Estrat and implements a sound approximation of WFS (on the information lattice)

We then describe Ewfs which implements full WFS and produces a residual program The Delaying and Simplification operations Full SLG completion A tabled residual program Presentation follows [SSW00a, CSW99]

Terrance Swift Topics in Logic Programming Implementation Estrat: Negative Return

The basic idea behind Negative Return is to suspend incomplete negative calls to a tabled subgoal S. When S becomes successful, the suspended environment should be failed; When S becomes failed, the suspended computation should be resumed and its forward continuation taken.

Since it can suspend and resume, Edef already has the most important feature for Negative Return.

Terrance Swift Topics in Logic Programming Implementation Negative Return

tnot/1 is the tabled negation operation in XSB negation suspend lays down a negation suspension choice point, and suspends the current evaluation (including failing) If the negation suspension choice point resumes and S has no answers, its forward continuation will be the true in the pseudo-code

tnot(S) :- ( ground(S) → ( subgoal not in forest(S), call(S), fail ; (is complete(S) → has no answers(S) ; negation suspend(S), true /* if execution reaches here, S */ ) /* is completed with no answers */ ) ; throw error(table error,”Flounder: subgoal S is not ground”) ).

Terrance Swift Topics in Logic Programming Implementation Estrat: Negative Return

Format of a Negation Suspension Frame FailCont Pointer to negation resume Instruction EBreg Environment Backtrack Point Hreg Top of Global Stack (Heap) TRreg Top of (Forward) Trail Stack CPreg Return Point of Suspended Literal Ereg Parent Environment *RSreg Root Subgoal Choice Point *SubgFr Frame of Suspended Subgoal **Dreg Pointer to Parent Delay List **Delay Status Set to true if Delaying is needed PrevNS Pointer for Negation Suspension Frame Chain

Format is analogous to a consumer choice point frame (slide 114) but no pointer to the substitution factor is needed (remember its subgoal is ground) The RSreg and SubgFr cells are needed to construct the dependency graph in certain cases, as discussed below. The Dreg and Delay Status cells are not needed until Edelay

Terrance Swift Topics in Logic Programming Implementation Estrat: Completion

Ensuring that A ground subgoal is completely evaluated when an answer is derived for it is conceptually easy In new answer dealloc check to see if the substitution factor for the subgoal S is empty. If it is you can complete S. You can also prune any other tabled choice points for S ... unless S is the leader of an ASCC, in which case it is needed for scheduling. also have to clean up completion stack

Terrance Swift Topics in Logic Programming Implementation Estrat: Completion

One problem remains: if we have an approximate SCC, how can we tell whether the program is lrd-stratified or not? We can use information in negation suspension frames to determine whether there is a negative link in the SDG between two subgoals in the ASCC Note that there may be negative links from one subgoal to another within the dependency subgraph of the ASCC but not within any maximal independent SCC To evaluate LRD-stratified programs, we need to extend completion with a “dependency checker” that returns a maximal independent SCC from the dependency subgraph of the ASCC

Dependency checking can be useful not only in Estrat but in Ewfs for ensuring delay minimality [SSW00b].

Terrance Swift Topics in Logic Programming Implementation Estrat: Completion

check complete 0 SubgComplSF := SF ComplSF(GCP SubgFr(B)); /* B register points to the generator CP of Subgoal */ 1 if (Subgoal is a leader of a scheduling ASCC, A) /* using the completion stack as in slide 126 */ 1.1 Call fixpoint check(SubgComplSF ); 1.2 if (there are no negation suspensions on subgoals in A) 1.2.1 Mark as complete all subgoals in A; 1.2.2 Reclaim the stack space of subgoals in A and adjust the freeze registers; else /* handle negation */ 1.3 I := maximal independent scc(Subgoal); /* see note */ 1.4 For each subgoal S ∈ I 1.4.1 Mark the subgoal frame of S as complete; 1.4.2 if (there are negation suspensions on S) 1.4.3 if (there exists a subgoal S0 ∈ I that is suspended on S) 1.4.4 Abort: the program is not lrd-stratified; 1.4.5 else Schedule negation resume instructions for S by chaining together the negation suspension frames for all completed subgoals; 1.5 Let E be those subgoals of A that were early completed and let C := E ∪ I ; 1.5.1 Compact the completion stack by removing the frames of subgoals in C; 1.5.2 If possible, reclaim the stack space of subgoals in C and adjust the freeze registers; 2 fail

Terrance Swift Topics in Logic Programming Implementation Estrat: Completion

Now check complete has an inner fixed point that returns answers and an outer fixed point that completes sub-SCCs and invokes negation suspension operations Determining exact SCCs, via maximal independent scc() is not necessary when Delaying and Simplification have been implemented, but it does give delay minimality In XSB, batched evaluation, which has bigger SCCs implements the exact SCC check, while local evaluation does not. Local evaluation simply check whether there is a negative link between to non-completed subgoals in the ASCC. (Line 1.3 is omitted, and occurrences of I are replaced by A).

A new register, the Root Subgoal register is added to Estrat to perform these checks

Terrance Swift Topics in Logic Programming Implementation Edelay : Delaying

Recall that there are two ways a literal can be delayed By Delaying a negative literal We’d like to do this as little as possible – so we can do it at check complete if our maximal independent SCC has a loop through negation By SLG Answer Resolution with a conditional answer (slide 175) This clearly needs to happen in new answer dealloc

Terrance Swift Topics in Logic Programming Implementation check complete in Edelay (batched evaluation version)

check complete 0 SubgComplSF := SF ComplSF(GCP SubgFr(B)); /* B register points to the generator CP of Subgoal */ 1 if (Subgoal is a leader of a scheduling ASCC, A) /* using the completion stack as in slide 126 */ 1.1 Call fixpoint check(SubgComplSF ); 1.2 if (there are no negation suspensions on subgoals in A) 1.2.1 Mark as complete all subgoals in A; 1.2.2 Reclaim the stack space of subgoals in A and adjust the freeze registers; else /* handle negation */ 1.3 I := maximal independent scc(Subgoal); 1.4 For each subgoal S ∈ I 1.4.1 Mark the subgoal frame of S as complete; 1.4.2 if (there are negation suspensions on S) * if I has a loop through negation * Schedule negation resume instructions for S by chaining together * each negation suspension frame for S * and setting their Delay Status cell to delay * else if I does not have a loop through negation and S is failed * Schedule negation resume instructions for S by chaining together * each negation suspension frame for S 1.5 Let E be the set of subgoals of A that were early completed and let C := E ∪ I ; 1.5.1 Compact the completion stack by removing the frames of subgoals in C; 1.5.2 If possible, reclaim the stack space of subgoals in C and adjust the freeze registers; 2 fail

Terrance Swift Topics in Logic Programming Implementation Edelay : negation resume

Instruction negation resume CCP := B; /* B register points to a negation suspension frame */ Call switch environments(CCP) /* restore environment of the suspended consumer */ Restore values of WAM registers as saved in cells of the CCP; subgoal ptr := NSF SubgFr(CCP): /* obtain pointer to suspended subgoal, S */ if (has answers(subgoal ptr) or Delay Status cell is set) { if (has unconditional answer(subgoal ptr)) fail; else /* either S has a conditional answer or Delay Status is set */ delay negatively(subgoal ptr, subgoal ptr); /* add ¬SS to delay list */ } /* else continue; */ B := Dealloc FailCont(CCP); deallocate environment; proceed;

The Delaying operation is performed here by delay negatively() which builds a structure for ¬SS on the heap and adds it to the delay list The delay list is accessed by the D register.

Terrance Swift Topics in Logic Programming Implementation Other Instruction Changes for Edelay

To perform SLG Answer Resolution, the answer return instruction has a similar addition of delay positively(). If the answer A returned to a subgoal S is conditional. delay positively() performs unification of the substitution S factor with A and also constructs AA on the heap and adds it to the delay list. Discussion of new answer dealloc which interns delay lists into the table space is deferred until Ewfs

Terrance Swift Topics in Logic Programming Implementation Summary: Eneg and Edelay

In Estrat : A new instruction is added, negation resume called by a new predicate, tnot/1. negation resume requires a new choice point. The check complete instruction is changed to call negation resume if needed, perhaps after performing an exact SCC check. A new register RS is added to maintain the root subgoal of a node. This is used for the exact SCC check.

In Edelay : check complete is further modified to signal the need for Delaying if necessary, and negation resume is modified to actually perform Delaying. answer return is extended to perform SLG Answer Resolution new answer dealloc is extended to copy delay lists into the table space A new register, D is added to maintain the delay list in the heap.

Terrance Swift Topics in Logic Programming Implementation Simplification for Ewfs

Principles of simplification Conditions for simplification of delay elements should be detected, and the simplification operation should be applied, as early as possible. Derivation of an unconditional answer Sθ for a subgoal S should immediately remove from the table for S all conditional answers whose head is a variant of Sθ

Terrance Swift Topics in Logic Programming Implementation Simplification for Ewfs

In the SLG-WAM, it is useful to specialize the simplification operation depending on whether a delayed literal is successful or failed, and whether the delayed literal is negative or not. simplify pos successful(Sθ) which removes the positive delay element referred to by Sθ from the delay list of an answer conditional on it. simplify neg successful(S) which removes the negative delay element referred to by ¬S from the delay list of an answer conditional on it. simplify neg failed(S) which removes an answer conditional on the negative delay element referred to by ¬S. simplify pos failed(Sθ) which removes an answer conditional on the positive delay element referred to by Sθ.

Terrance Swift Topics in Logic Programming Implementation Simplification for Ewfs

Events that trigger simplification

Derivation of an unconditional answer A for S via new answer dealloc. This removes any conditional associated conditional answers whose head is a variant of A, and may initiate simplify pos successful(A) or simplify neg failed(S) instructions. Completion of a subgoal with no answers. When a subgoal fails, all negative elements delayed on that subgoal become successful, and can be removed from the delay lists that contain them, by initiating simplify neg successful instructions. Failure or success of a delayed literal due to simplification. When initiated by either of the preceding two events, simplifications may have cascading effects. For instance, if a simplification instruction removes the last conditional answer A, then simplify pos failed instructions should be initiated for A. If the removal of A causes S to be failed, and S is ground, then simplify neg successful instructions should be initiated for S.

Terrance Swift Topics in Logic Programming Implementation Table Space in Ewfs

Table space in Ewfs needs to be significantly expanded. Conditional Answers have a DelayInfo Structure that contains a list of DelayList structures, each of which have a list of DelayLiterals a For simplification, back-pointers must be kept From Subgoal Frames to lists of NegativeDelayLiterals that refer to them From Answers to lists of PositiveDelayLiterals that refer to them To maintain the residual program, any variables of the delayed literals must be stored. They are maintained in Delay Tries See next two slides for a schematic view of this.

Terrance Swift Topics in Logic Programming Implementation Table Space in Ewfs

Subgoal Trie for p/3 Subgoal Trie for q/2 Subgoal Trie for r/3

p/3 q/2 r/3

v1 v1 v1

v2 v2 v2

v3 v3

... Subgoal Frame of ... Subgoal Frame of ... Subgoal Frame of p(X,Y,Z) q(X,A) r(Y,Z,A)

Answer Answer Answer Trie for Trie for Trie for f/3 p(X,Y,Z) f/3 q(X,A) g/2 r(Y,Z,A)

a a b

v1 v1 v1

v2 v2 v2

g/2 v3 v3

b

v2 DelayInfo DelayInfo

v1 PDE List

DelayInfo DL List DE DE

Delay Trie Delay Trie for for v1 q(f(a,_,_),_) v2 r(g(b,_),_,_)

v2 v1

v3 v3

Terrance Swift Topics in Logic Programming Implementation Table Space in Ewfs

Subgoal Frame of P’ Subgoal Frame of S’ ......

Answer Answer Answer Answer Return Trie Return Trie NDE List List NDE List List

Leaf Node for P" Leaf Node for S"

DelayInfo DelayInfo PDE List PDE List DL DE DL DL Prev DL List Next DL List

DE ... Q" ... S"

DE ...... Subgoal Frame of R" T" R’ ... S" ... DE

Answer DL DE DE Trie Prev Next Next PNDE Answer Delay_Trie Return NDE List Answer_Subst_ID Subgoal_ID List

Terrance Swift Topics in Logic Programming Implementation Simplification Instructions in Ewfs

The following instructions illustrate how simplification navigates the table structures for conditional answers Instruction simplify pos successful(Answer) /* PDL: Back-pointer to a Positive DelayLiteral Frame */ PDL := DelayInfo BackPDL(Answer)) while PDL is not null /* Get the delay list from this frame */ DelayList := BackPDL DelayList(PDL) /* Remove the positive DelayLiteral from the delay list */ DelayList := DelayList − {PDL} /* The DelayList is empty; its answer is unconditional */ if (DelayList = [ ]) simplify pos successful(DelayList Answer(DelayList)) /* Access the subgoal via the DelayInfo frame for the answer */ Subgoal := DelayInfo Subgoal(DelayList DelayInfo(DelayList)) if Subgoal now succeeds simplify neg failed(Subgoal) PDL := DelayInfo Next(PDL) Reclaim space for the DelayInfo, DelayList, DelayElement, DelayTrie, and BackPDE structures for Answer

Terrance Swift Topics in Logic Programming Implementation Simplification Instructions in Ewfs

This instruction differs from the previous one in that It starts with the subgoal frame rather than the DelayInfo frame of an answer It removes DelayLists, rather than removing a DelayElements from DelayLists /* Subgoal succeeds, so ¬Subgoal is false */ Instruction simplify neg failed(Subgoal) /* NDL: Back-pointer to a Negative DelayLiteral Frame */ NDL := SuboalFrame BackNDL (Subgoal) while NDL is not null /* Get the delay list from this frame */ DelayList := BackNDL Delaylist(NDL) DelayInfo := DelayList DelayInfo(DelayList) Remove DelayList from the delay list chain of DelayInfo Reclaim space for DelayList, and its associated DelayElements and Delay Tries /* The Answer associated w. DelayList is unsupported */ if DelayList DelayInfo(DelayList) is null Answer := DelayInfo Answer(DelayList) Delete Answer and reclaim space for its associated DelayInfo and Back PDL frames simplify pos failed(Answer) if (the subgoal Subgoalnew that had Answer as an answer substitution now fails) simplify neg successful(Subgoalnew ) NDL := BackNDL Next(NDL) Reclaim space for all answers for Subgoal, DelayLists, DelayElements, etc.

Terrance Swift Topics in Logic Programming Implementation EWFS : new answer dealloc

/* Let A = AT :- DL be the newly derived answer of subgoal S having answer substitution ηS */ Instruction new answer(Arity,GCP) /* GCP points to the generator choice point for S */ 1 Get the delay list DL by using the current value of the D register 2 If (no D ∈ DL is failed) 2.1 Subgoal := GCP SubgFr(GCP); /* pointer to the subgoal frame for S */ 2.2 TRS := SF AnsTrieRoot(SID ); /* the answer trie for S */ 2.3 ηS := locate answer substitution(Arity,GCP); /* ηS now points to the answer substitution*/ 2.4 AnswerLeaf := answer check insert(ηS ,TRS ,NewFlag); /* inserts A (if needed); also removes any successful delayed literals during traversal.*/ 2.5 if (NewFlag = TRUE) /* ηS is new */ 2.5.1 Restore the value of the D and RS registers as saved in GCP; /* Implicit return of answer on forward continuation */ 2.5.2 If (DL 6= [ ]) /* A is conditional */ 2.5.2.1 Add a positive delay element hSubgoal, Answeri to the head of the restored delay list 2.5.3 else 2.5.3.1 SF NS Chain(Subgoal) := NULL;/* remove negation suspensions of S */ 2.5.3.2 if (GCP SubstFact(GCP) = ∅) /* S is ground and succeeds */ 2.5.3.2.1 Mark Subgoal as complete; /* perform early completion */ 2.5.3.2.2 simplify neg failed(Subgoal); 2.5.4 Deallocate local environment; 2.5.5 Set the program pointer P to the continuation pointer CP; 2.6 else /* ηS was already present in the answer table for S */ 2.6.1 if (DL = [ ] and there were conditional answers) 2.6.1.1 simplify pos successful(Answer); 2.6.2 fail; 3 else fail; /* A was simplified and failed */

Terrance Swift Topics in Logic Programming Implementation The new answer dealloc instruction in Ewfs

In step 2, a given delayed literal may have failed between the time that the literal was delayed, and now. Simplification is restricted to answers in the tables, thus the need for the failure check in step 2 and the success check in step 2.2. In step 3, the D and RS registers are used to shift from the delay list of the answer to the delay list of the calling subgoal. The early completion in 2.5.3.2 and 2.5.3.3 is also needed for Estrat . The fail in 2.6.2 ensures that an unconditional answer AT is not returned if a conditional answer has already been derived. The fact that the answer is unconditional is propagated by simplification so that the continuation of CP need not be taken.

Terrance Swift Topics in Logic Programming Implementation Residual Programs in Ewfs

For a completed query, SLG table space contains a residual program in which the program is reduced with respect to WFS. S A delay literal LA may contain variables, hence the need for correct maintenance of variables in L using delay tries The query get residual(Head,-Body) backtracks through clauses of the residual program that unify with Head, and so can be used to extract the residual program. The XASP package [CSW] can be used to send a residual program to Smodels for ASP processing directly, or after being extracted via get residual/2 and manipulated.

Terrance Swift Topics in Logic Programming Implementation Subsumption and Variance in the SLG-WAM

In XSB WFS is supported for both call variance and call subsumption (extension to call subsumption in [Swi09]) WFS is only supported for answer variance; answer subsumption will be discussed later. However, answer subsumption has not been extended to incorporate Delaying and Simplification, but instead implements LRD-stratified programs.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 7: Multi-threaded Prologs: ISO-multi-threading, the MT-SLG-WAM

Terrance Swift Topics in Logic Programming Implementation Multi-threading

Why Multi-thread? Threads may perform specialized functions: to write to a log (DBMSs), perform garbage collection (Java), profile code (Prologs, including XSB) Scalability: to do separable, repeated tasks more quickly Various types of servers do this: database servers, web servers, knowledge-base servers Threads coordinate through message queues, a shared database, etc. Break up a large component into subcomponents and solve in parallel. In LP, perform Or-[AK90b, CHH89, War87], And-[HR89], or Table-[FHSW95, RSC04b] parallelism Usually requires tighter coordination among threads than servers Computer architectures support multi-threading through multi-core CPUs

Terrance Swift Topics in Logic Programming Implementation Multi-threading

Desiderata for a multi-threaded engine No Overhead No overhead for a single-threaded application Scalability Scalable to lots of threads without a per-thread slowdown Semantic Support Support Prolog semantics (and XSB’s semantics for WFS, etc) Application Support Support server-style and parallel applications As of 04/08, I know of no Prolog that does all of these really well.

Terrance Swift Topics in Logic Programming Implementation Multi-threading

10 A first model of multi-threaded Prolog – MT0 Shared static code Private dynamic code Private tables Based on semantics of pthreads (emulatable in Windows) One “main” thread and zero or more created threads The model will be extended for shared tables later in this lecture and for shared dynamic code in the next lecture.

10 MT0 was developed mostly by Rui Marques along with Terrance Swift and David Warren Terrance Swift Topics in Logic Programming Implementation Multi-threading: MT0

For scalability, we want as much as possible private to a thread Private (SLG-)WAM Stacks (and their registers) Private findall buffers Private dynamic code Private tables and table stacks (Such as the copying stacks on Slide 98) Some things remain shared Static code Atom/Predicate table (implied from shared static code) Stream table, as OS’s maintain file descriptors and their properties on a per-process basis Other process-level resources, such as sockets

Terrance Swift Topics in Logic Programming Implementation Multi-threading: MT0

A first step to MT0 requires each thread can maintain a separate computation state. This means going through all global variables and data structures to make them private to a thread or protected by a mutex.

Thread-private data structures are kept in a structure called a thread context. Register values, such as E are now macros for thread context->E. All functions in the engine (for builtins like functor/3, etc) now have a thread context argument passed to them Mutexes must be placed around global structures for streams, atom table, symbol table, socket code, etc. Private tables (and dynamic code) are accessed through a dispatch block, essentially an array off of a PSC record that, given the XSB thread index, returns a pointer to the subgoal trie of a given predicate. Since malloc() and free() both require mutexes, special-purpose memory managers need to be written on top of these functions to that threads do not require a lock each time they need to allocate memory.

Terrance Swift Topics in Logic Programming Implementation Space Reclamation

The architecture of MT0 has impact for space reclamation, so we make a short digression on space reclamation. XSB has 4 garbage collectors

1 A heap (global stack) garbage collector 2 An atom table garbage collector 3 A garbage collector for retracted clauses 4 A garbage collector for abolished tables Most Prologs, in fact, have the first three of these

Terrance Swift Topics in Logic Programming Implementation Space Reclamation on the Heap

Heap garbage collection may be invoked rarely, or never depending on the program Heap garbage collection is not usually expensive, but can sometimes be avoided by use of repeat/fail loops Some types of constraint processing require a lot of heap garbage collection The following code fragment is from a program that implements path consistency for temporal constraints [Mei96] The first argument does not monotonically decrease. This resembles a fixed point algorithm, and builds a lot of structures on the heap. check_consistency([],_Nodes). check_consistency([(I,J)|Rest],Nodes):- setof(K,(member(K,Nodes), \+(I = K),\+(J = K)),IJNodes), check_consistency_k(IJNodes,(I,J),Rest,RestOut), check_consistency(RestOut,Nodes).

Terrance Swift Topics in Logic Programming Implementation Space Reclamation on the Heap

XSB has two heap garbage collectors. The first [DS01, CS01] uses a mark and slide algorithm Mark all cells in the heap by traversing all pointers to them. In the WAM this means traversing the local stack (and choice point stack), the trail, the register array and the heap itself. In the SLG-WAM this means making sure that all active environments are traversed and means ensuring that heap garbage collection is never done when in the midst of copying to or from a table In the sliding phase, need to presever order of heap elements to allow further backtracking Since each thread has its own heap, heap garbage collection has been made thread-safe and each thread can gc its own heap independently of any others. These garbage collectors were originally written for an implementation of XSB that used copying to switch environments rather than freeze registers – see [DS99] and [CSW02] for a comparison of the two approaches. Garbage collection now requires choice points to have a preceeding cell, a pointer to the prior choice point on the stack. This is different than the failure continuation Terrance Swift Topics in Logic Programming Implementation Space Reclamation on the Heap

The second heap garbage collector traverses the stacks as before, but when it marks, it copies the heap information to a new area 11. Advantage: no sweep phase is necessary so it is faster than the mark-sweep collector Disadvantage: heap order is not maintained. Thus, once you garbage collect with the copying collector you do not reclaim space on backtracking. Which garbage collector to use depends on your style. For constraint applications, the copying collector may be best, for general purpose programming the mark-slide collector may be best No detailed comparisons between the two garbage collectors have been performed with XSB.

11This garbage collector was primarily written by Bart Demoen and Kostis Sagonas. Terrance Swift Topics in Logic Programming Implementation MT0: Atom Table Space Reclamation

XSB also has an atom-table garbage collector 12. Recall that every time an atom is read, loaded through a file, or created via name/2 or other means, it is interned into an atom table The atom-table garbage collector looks through everything the heap looks through, plus static and dynamic code. Atoms are global in the multi-threaded engine. Currently XSB only allows atom table garbage collection when there is a single active thread. SWI Prolog has a more sophisticated approach to multi-threaded atom-table garbage collection To initiate atom table garbage collection, a gc-thread sends each Prolog thread an interrupt that causes the Prolog thread to wait on a condition variable. When all threads have suspended, the garbage collection thread may run. When the gc-thread finishes it wakes all Prolog threads. No work has been done on private atom tables in Prolog (that I know of). Terrance Swift Topics in Logic Programming Implementation 12written by David Warren MT0: Table Space Reclamation

XSB also has many ways of deleting information in tables In the sequential engine, abolish table call(Subgoal), abolish table pred(Predicate), abolish table module(Module), abolish all tables All throw an error when called when there is an incomplete table A check is made of the choice point stack to see if there are any choice points for The completed table for Subgoal in the case of abolish table call/1 A completed table for Pred in the case of abolish table pred/1 Any completed table in the case of abolish all tables If this happens, pointers to the table(s) are reset so that new calls will re-create the tables, but their space is not reclaimed until garbage collection time. Thus, there is a garbage collection list containing subgoal-level and predicate-level information.

Terrance Swift Topics in Logic Programming Implementation MT0: Table Space Reclamation

In the MT-SLG-WAM, space for private tables is reclaimed just as in the sequential engine Thread-shared tables (which are discussed below) can only be reclaimed when there is a single active thread – of course this could also be changed to allow the condition-variable trick. Space for dynamic code is reclaimed in much the same way as space for tables. It will be discussed in the next lecture, where I’ll present a (hopefully) better method for reclaiming table space. In the MT-SLG-WAM, there are two new predicates abolish private tables, abolish shared tables

In summary, the MT0 (which allows only private tables and dynamic code) has no problem reclaiming space, except for the atom table

Terrance Swift Topics in Logic Programming Implementation ISO Multi-threading Predicates: thread create/3

How do you program in Multi-threaded Prolog? Here are some predicates from an emerging ISO standard

thread create(#Goal,-ThreadId,+Options)

When called by a thread Tcall , creates a new thread Tnew to execute Goal, and Tcall will immediately succeed with ThreadId bound. Note that a fresh set of variables are created in Tnew , so no bindings will be propagated back to Tcall Tnew will exit when Goal succeeds. By default, Tnew will be joinable, but an option allows it to be created as detached on exit option allows an exit handler to be called regardless of whether Goal succeeds, fails, or throws an error. Other options allow initial settings for Prolog stack sizes.

Terrance Swift Topics in Logic Programming Implementation ISO Multi-threading Predicates: thread join/2

thread join(+ThreadIds,-ExitDesignators) waits for a set of threads to exit ExitDesignators is a list of terms, no error ball if a given thread exited without an unhandled error, and an explicit error ball if the thread raised an unhandled error or was aborted via a thread cancel. thread cancel(+ThreadId) allows one thread to send an interrupt to another thread. The interrupt is a special exception that can be handled by the application, or by the default handler. The default handler simply causes the thread to exit. The main XSB thread cannot be cancelled by another thread.

Terrance Swift Topics in Logic Programming Implementation ISO Multi-threading Predicates: User Mutexes

For goals that need to access shared objects, like streams or external C code, we may need to protect these goals via a mutex. This is most easily done via with mutex(+Mutex,?Goal). This predicate locks mutex, executes Goal deterministically, and when it succeeds the mutex is unlocked. Choice points created by Goal are cut away upon success Mutex is unlocked if Goal fails or raises an exception

Terrance Swift Topics in Logic Programming Implementation ISO Multi-threading Predicates: Message Queues

Message queues are a common method in multi-threaded programming to synchronize information between threads. In traditional queues A thread writes to the queue by placing a message at the end of the queue. If there is no space left on the queue, the writer suspends until space is available. A thread reads the first message on the queue. If there are no messages, the reader suspends until a message is added. In Prolog message queues, an arbitrary Prolog term can be put onto the queue, via thread send message(+Queue,#Message) A reader goes through the queue, seeking the first message that unifies with a given goal via thread get message(+Queue,#Message) Now, the reader will suspend if there are messages on Queue, but none of the messages unify with Message. If the reader suspends, it will have to start at the beginning of the queue when it is awakened.

Terrance Swift Topics in Logic Programming Implementation ISO Multi-threading Predicates: thread signal/2

thread signal(ThreadOrAlias, Goal) interrupts thread ThreadOrAlias so that it executes Goal at the first opportunity. “First opportunity” means at interrupt check (at least in XSB). This happens on every WAM call, proceed, execute, and before every cut. If the interrupt is handled while ThreadOrAlias is executing a goal with continuation C, all solutions for Goal will be obtained, and the failure continuation of Goal will be C. If Goal throws an exception E, the continuation will be the handler for E. This is powerful – there exists a predicate call with signals off/1 to disable signal handling for a period of time.

Terrance Swift Topics in Logic Programming Implementation A Multi-Threaded Goal Server 13

:- thread shared server id/1.

server :- socket(SockFD), socket set option( SockFD, linger, SOCK NOLINGER ), xsb port(XSBport), socket bind(SockFD, XSBport), socket listen(SockFD,Q LENGTH), thread create( server loop(SockFD), Id, [] ), assert( server id(Iden) ), thread join( Iden ).

server loop(SockFD) :- socket accept(SockFD, SockClient), thread create( attend client(SockClient) ), server loop(SockFD).

attend client(SockClient) :- socket recv term(SockClient, Goal), ( Goal == stop -> retract(server id( Server )), thread cancel( Server ), socket close( SockClient ), thread exit ; true ). ( is valid(Goal) -> catch((Goal,socket send term(SockClient, Goal),fail), Error,socket send term(SockClient,Error)) ; socket send term(SockClient, invalid goal(Goal)) ) socket send term(SockClient, end), socket close(SockClient). 13 Written by Rui MarquesTerrance Swift Topics in Logic Programming Implementation Multi-threaded Prime Number Generation

prime(P, I ) :- I < sqrt(P),!. prime(P, I ) :- Rem is P mod I , Rem = 0, !, fail. prime(P, I ) :- I1 is I − 1, prime(P, I1). prime(P) :- I is P − 1, prime(P, I ).

list of primes(I , F , Tail, Tail) :- I > F , !. list of primes(I , F ,[I |List], Tail) :- prime(I ), !, I1 is I + 1, list of primes(I1, F , List, Tail). list of primes(I , F , List, Tail) :- I1 is I + 1, list of primes(I1, F , List, Tail).

partition space(N, H, H1) :- H is N//2, H1 is H + 1.

worker( Q, Iden, I , F , List, Tail) :- list of primes( I , F , List, Tail), thread send message( Q, primes(Iden,List,Tail) ).

master( N, L ) :- partition space( N, H, H1), message queue create(Q), thread create( worker(Q, p1, 1, H, L, L1) ), thread create( worker(Q, p2, H1, N, L1, []) ), thread get message( Q, primes(p1,L,L1) ), thread get message( Q, primes(p2,L1,[]) ).

Algorithm for finding primes and partitioning is not efficient, but the program illustrates the general principle of cooperating threads (written by Rui Marques).

Terrance Swift Topics in Logic Programming Implementation Multi-threaded Answer Set Programming

XSB provides an interface to Smodels, a stable model generator XSB can send to Smodels a residual program from a query to a non well-founded program Alternately, a program for Smodels can be explicitly constructed in XSB Each XSB thread can have its own copy of Smodels On the next page, a thread creates two other threads, each of which generate a stable model. As of May 2008, some features of MT-XASP have been implemented; others are under development.

Terrance Swift Topics in Logic Programming Implementation Multi-threaded Answer Set Programming

test:- message_queue_create(Queue1),message_queue_create(Queue2), thread_create(test1(Queue1)),thread_create(test2(Queue2)), read_models(Queue1),read_models(Queue2).

test1(Queue) :- smcInit,smcAddRule(a1,[]),smcAddRule(b1,[]), smcAddRule(d1,[a1,not(c1)]),smcAddRule(c1,[b1,not(d1)]), smcCommitProgram, ( smComputeModel,smcExamineModel(Model), thread_send_message(Queue,solution(program1,Model)), fail ; thread_send_message(Queue,no_more_solutions), smEnd ).

test2(Queue) :- smcInit,smcAddRule(a2,[]),smcAddRule(b2,[]), smcAddRule(d2,[a2,not(c2)]),smcAddRule(c2,[b2,not(d2)]), smcCommitProgram, ( smComputeModel,smcExamineModel(Model), thread_send_message(Queue,solution(program2,Model)), fail ; thread_send_message(Queue,no_more_solutions), smEnd ).

read_models(Queue):- repeat, thread_get_message(Queue,Message), (Message = no_more_solutions -> true ; writeln(Message), fail ). Terrance Swift Topics in Logic Programming Implementation Timings of MT0 Functionality

Overhead of multi-threaded engine vs. the single threaded engine (XSB 3.2) Prolog Benchmarks Times for Macintosh (OS 10.4.9) on a dual-core Intel chip: geometric mean 4% faster; arithmetic mean 5% faster Times for Macontosh (OS 10.3.5) on a powerpc chip are similar. Times for Debian Linux; geometric mean 5.5% faster, arithmetic mean 4.2% faster Times for Fedora Linux (Core 6) on a dual-core Intel chip: geometric and arithmetic mean 3% slower. Times for Fedora Linux (Core 6) on a single-core Intel chip are similar

Terrance Swift Topics in Logic Programming Implementation Timings of MT0 Functionality

Overhead of multi-threaded engine vs. the single threaded engine (XSB 3.2) Tabling Benchmarks: left recursion, right recursion, and win/1 Times for Macintosh (OS 10.4.9) on a dual-core Intel chip: geometric mean 12% slower; arithmetic mean 13% slower. Times for a single-core Macintosh powerpc (OS 10.3.5) are similar. Times for Debian Linux: geometric and arithmetic mean about 7% slower Times for Fedora Linux (Core 6) on a dual-core Intel chip: geometric and arithmetic mean 13% slower Times for Fedora Linux (Core 6) on a single-core Intel chip are similar

Terrance Swift Topics in Logic Programming Implementation Timings of MT0 Functionality

Overhead of multi-threaded engine vs. the single threaded engine (CVS version) Tabling Benchmarks: Program Analysis Times for Macintosh (dual-core 10.4.9): geometric and arithmetic mean of 12% faster Times for a single-core Macintosh powerpc (OS 10.3.5) are similar. Times for Debian Linux Times geometric and arithmetic mean about 1% faster Times for Fedora Linux (Core 6) on a dual-core Intel chip: geometric and arithmetic mean 1% faster Times for Fedora Linux (Core 6) on a single-core Intel chip are similar

Terrance Swift Topics in Logic Programming Implementation MT0 Scalability

N. threads 1 2 Overhead 4 Overhead Elementary Net 5.94 6.23 4.8% 6.25 5.2% Dynamic Elementary Net 6.03 6.03 0% 6.03 0% Workflow Net 19.21 19.68 2.4% 19.95 3.8% Omega Net 7.18 8.33 16.0% 10.3 46.0% Omega Net Specialized 6.37 6.37 0% 6.37 0.0% Constraint Net 2.75 2.84 3.2% 2.85 3.6% Preference Net 3.74 3.77 0.8% 3.82 2.1% Call Subsumption .86 1.04 20.0% 1 43%

Elementary Net uses tabled definite programs for Petri Net reachablilty; Dynamic Elementary Net is the same, but uses dynamic clauses. Workflow Net uses definite programs to test workflows. Constraints Net tests the constraint-based colored Petri nets, and Preferences Net tests extension for well-founded preferences. Omega Net tests ω-abstraction using answer subsumption. filterPOA/5 relies on call/N, which accesses XSB’s shared predicate table, causing poor performance. A specialized version, Omega Net Specialized avoids this problem Call Subsumption tests an unbound call to right recursion over a graph. Its poor speedup is apparently due to high demands for memory management Goal 3: Private tables should be highly scalable up to the number of cores available is mostly satisfied (for 4 cores), although more work needs to be done on call subsumption. These performance numbers were obtained on a 4-core linux machine whose use was kindly provided by Luis Caires Asserting and retracting non-trie-based dynamic code does not scale well, as memory for this code is not efficiently allocated and freed. Asserting and retracting private trie-based dynamic code scales linearly (trie-based dynamic code is discussed in next lecture)

Terrance Swift Topics in Logic Programming Implementation MT-TLP: Summary of Private Table Functionality

Feature Private Tables Tabled constraints Supported Answer subsumption Supported Tabled Dynamic Code Supported Tabled negation Supported Space reclamation Supported Call subsumption Supported Incremental recomputation “Almost” supported XASP (Residual Program → Smodels) “Almost” supported

Terrance Swift Topics in Logic Programming Implementation MT0 Summary How does XSB do with respect to our desiderata? Overhead Except for right recursion and win/1 times are not bad – sometimes even faster than the sequential engine. Scalability Times again are good for 8 processors, except for right recursion, win/1, and private dynamic clauses Semantics Support – So far, we’ve (basically) preserved semantics in that the behavior MT0 on any Prolog thread is the same as in the sequential engine. An exception is abolish/1 Application Support The ISO-style mutexes, message queues, signals, etc provide a good start The frame-based logic, [Mou] has a multi-threaded version that has been ported to SWI, YAP, and XSB. Other applications will undoubtedly require more. SWI, for instance allows a user to attach a debugger to any running thread.

Terrance Swift Topics in Logic Programming Implementation Concurrent SLG

Concurrent SLG [Mar07, MS08] adds a few new definitions to SLG Each tree T in a forest (F) is marked with a unique thread id (informally Thread owns T or the subgoal of T ). The set of trees marked with T represents the view of the forest by the thread T A node N is thread compatible with a subgoal S if S is complete or S and N are owned by the same thread A tabled literal cannot be resolved (or delayed or simplified) unless its node is thread compatible with its selected subgoal A set of subgoals cannot be completed unless they are owned by the same thread This can lead to deadlock – mutually dependent subgoals owned by different threads where no operations are possible on trees for those subgoals To resolve this, a new usurpation operation is defined: If Thread1 owns a subgoal that is in a deadlock, it can usurp (remark) all the subgoals in that deadlock cycle. T then controls evaluation of the SCC. Usurpation breaks a SCC by sequentializing its evaluation, or at least its control.

Terrance Swift Topics in Logic Programming Implementation Concurrent Local SLG: Example

Thread 1 Thread 2 Thread 3

Subgoal2

Subgoal1

Abstract SDG for a computation Subgoal2 owned by thread 2 calls Subgoal1 owned by thread 1 For thread 2 to perform a Local Evaluation, it must apply operations in the tree for Subgoal1 However, since Subgoal1 is owned by thread 1, it is not thread compatible with thread 2 No operations apply to subgoals owned by thread 2 in this forest; (thread 2 suspends) Terrance Swift Topics in Logic Programming Implementation Concurrent Local SLG

Thread 1 Thread 2 Thread 3

Subgoal2

Subgoal1

Now Subgoal1 calls Subgoal2 No operations are applicable to the SCC owned by thread 1 and thread 2: it is in deadlock

Terrance Swift Topics in Logic Programming Implementation Concurrent Local SLG

Thread 1 Thread 2 Thread 3

Subgoal1

Subgoal2

Thread 1 usurps the subgoals of thread 2 and remarks the trees (and subgoals) Now thread compatibility restrictions don’t apply

Terrance Swift Topics in Logic Programming Implementation Concurrent Local SLG: Dependencies

SDG(F) is as before.

SDG(F, Thread) is SDG(FThread ) where (FThread ) is the subforest of F that T owns. The Thread Dependency Graph of F (TDG(F)) is defined as follows The vertices of TDG(F) are the thread ids marking trees in F (Thread1, Thread2) is an edge in TDG(F) if (S1, S2) is an edge in SDG(F), Thread1 owns S1, and Thread2 owns S2

Terrance Swift Topics in Logic Programming Implementation Properties of Concurrent Local SLG

Concurrent SLG has same correctness and termination properties as SLG Addition of usurpation does not change complexity of SLG Concurrent Local SLG is based on locality in the SDG(F, Thread) for each thread Has the same correctness and termination properties as Local SLG N threads, each performing a Local Evaluation on SDG(F, Thread), together perform a Local Evaluation on SDG(F)(N finite)

Terrance Swift Topics in Logic Programming Implementation Concurrent Local SLG: Operational Properties

Any thread Thread contains a single maximal independent SCC in SDG(F, Thread) Each node in TDG(F) has at most one outgoing edge i.e, any deadlock is a simple cycle in TDG(F) These properties considerably simplify the algorithm. A thread suspends when it selects a literal that is not thread compatible with itself. Thus If a thread T detects a deadlock, all threads in the deadlock cycle will be suspended except for T Each suspended thread T can be awakened when the subgoal on which it was suspended completes. (T can then resumes execution by backtracking through answers for the completed table)

Terrance Swift Topics in Logic Programming Implementation Concurrent Local SLG: Implementation

Implementation changes mostly concern the tabletry instruction that is called when a tabled subgoal is encountered. completion instruction also wakes up threads suspended on a completed subgoal

Instruction tabletry (sequential version) /* Subg is in argument registers; Tcurrent is current thread */ Perform the subgoal check insert(Subg) operation in the table If Subg is new Create a generator choice point to resolve program clauses Else if Subg is incomplete Create a consumer choice point to resolve answer clauses Else if subg is complete Branch to root of trie to execute instructions for completed table

Terrance Swift Topics in Logic Programming Implementation Concurrent Local SLG: Implementation

Instruction tabletry (Concurrent Local Version)

/* Subg is in argument registers; Tcurrent is current thread */ Perform the subgoal check insert(Subg) operation in the table /* if Subg was usurped, treat it as a new subgoal */ If Subg is not new and is marked by another thread Lock global TDG mutex If deadlock(Tcurrent ,Subg.ThreadMark) /* all other threads in the independent SCC are suspended at deadlock */ usurp(Tcurrent ,Subg,Subg.ThreadMark) Else unlock TDG mutex; suspend the calling thread until Subg completes /* Proceed as in the sequential case */ /* if Subg was usurped, treat it as a new subgoal */ If Subg is new Create a generator choice point to resolve program clauses Unlock global TDG mutex Else if Subg is incomplete Create a consumer choice point to resolve answer clauses Else if subg is complete Branch to root of trie to execute instructions for completed table

Terrance Swift Topics in Logic Programming Implementation Concurrent Local SLG: Implementation

As currently implemented in XSB, a usurping thread rederives usurped computations from scratch (although it does not need to re-insert previously derived answers into the table). So far, experiments show that usurpation occurs surprisingly rarely Details of the implementation are subtle; however they amount to about 300 lines of code added to tabletry with minimal refactoring of existing code. This means that the approach is quite general for various tabling functions (as shown below) It also means that there is little overhead for this approach beyond overheads for shared table space (i.e. one or two new conditions in tabletry) It also means that the approach is portable: all tabling systems execute special code when encountering a tabled subgoal

Terrance Swift Topics in Logic Programming Implementation Summary

Local Evaluation is critical for Answer Subsumption (quantitative and paraconsistent logics, maximal abduction) and useful for WFS. Also reduces stack space for many computations. Our approach shares completed tables only. This leads to an implementation Whose correctness and critical properties are provable That can be modularly added to a tabling engine Is currently working in XSB (please use anonymous CVS until v. 3.3 comes out) Supports WFS (including residual programs), Answer Subsumption, and Tabled Constraints Concurrent Batched Evaluation allows a tabled consumer and producer to communicate in a manner analogous to message queues. XSB contains an experimental version of this In the longer term, we are working on have dynamic scheduling of Concurrent Local and Batched Evaluation Terrance Swift Topics in Logic Programming Implementation Shared Table Functionality for Local Evaluation

Feature Shared Tables (Local) Tabled Dynamic Code Supported Tabled constraints Supported Answer subsumption Supported Tabled negation Supported XASP (Residual Program → Smodels “Almost” supported Space reclamation Partially Supported Call subsumption Not supported Incremental recomputation Not supported

The generality of Concurrent Local SLG means that it can support most tabling functionality Full space reclamation for abolished tables is not yet fully supported because of lack of resources to implement a table garbage collector in a multi-threaded environment. Further work needs to be done to extend Concurrent Local SLG to call subsumption and to assess its efficiency. Incremental recomputation is difficult for shared tables, since each thread that is using a table must maintain its view of the table throughout a query

Terrance Swift Topics in Logic Programming Implementation Shared Tables: Efficiency of Concurrent Local SLG

N. threads 1 2 Speedup 4 Speedup Shared Elementary 25.12 13.00 1.93 6.55 3.83 Shared Dynamic Elemtary 24.8 13.02 1.90 6.59 3.76 Shared Workflow 41.25 20.78 1.98 10.58 3.89 Shared Omega 19.58 10.38 1.88 5.57 3.51 Shared Constraint 11.13 5.56 2.00 2.83 3.93 Shared Preferences 3.73 1.86 1.99 0.95 3.92

Benchmarks show that usurpation occurs surprisingly infrequently in pratice. Overhead of shared tables over private tables is about 10-40 depending on benchmark and platform Overheads are mostly due to handling mutual exclusion for tables and to memory allocation. Further work is needed in these areas.

Terrance Swift Topics in Logic Programming Implementation Shared Tables: Batched Evaluation

In a concurrent computation, let S be an SCC with subgoals owned by different threads

Suppose a thread T1 computing subgoals in S backtracks to the oldest subgoal that it “owns” in S.

If another thread computing S is active, T1 will suspend and will be wakened when a thread performs batched scheduling for S;

Tf T1 is the last unsuspended thread computing subgoals in S, T1 itself will perform a fixed point check and batched scheduling and awaken the other threads computing S — either to return further answers or to complete their tables. As implemented in XSB, Concurrent Batched Evaluation thus allows parallel computation of subgoals, but has a sequential fixpoint check that synchronizes multiple threads when they compute the same SCC.

Terrance Swift Topics in Logic Programming Implementation Shared Table Functionality for Batched Evaluation

Feature Shared Tables (Batched-β) Tabled Dynamic Code Supported Tabled constraints Supported Answer subsumption Supported XASP (Residual Program → Smodels “Almost” supported Tabled negation Partially Supported Space reclamation Partially Supported Call subsumption Not Supported Incremental recomputation Not Supported

Unlike Concurrent Batched Evaluation, Concurrent Local Evaluation does not yet support full WFS. Currently adjusting heuristics to coordinate behavior between threads

Terrance Swift Topics in Logic Programming Implementation YAP Table Parallelism

Within an Or-parallel engine, YAP has implemented the SLG-WAM (for definite programs). They call their model Tabling within Or-parallelism [RSC04b] They have excellent scalability for up to 32 processors [RSC04a] They can even extract parallelism from left recursion [RSC02] which raises the possibility of parallel model checkers, program analyzers, etc.x This engine is not multi-threaded per-se, as the different parallel workers are processes. However, its one of the most advanced parallel Prolog engines around.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 8: Dynamic Code – semantics and implementation

Terrance Swift Topics in Logic Programming Implementation Dynamic Code

Logical theories are static – if you change an axiom you get a new theory with a new well-founded model, or a new stable model (or no stable model) Dynamic code is important. Not only Prolog but many high-level languages such as Ruby support it. But how can we have semantically meaningful dynamic code in a logic programming system? Lots of formulations (e.g. [APPP02, BK94]) but they boil down to modeling a meta-theory of change about a target theory, so that a given atom A may or may not be true at state N. Our approach is to support a fragment of Transaction Logic of [BK94]). The world changes, so until there is a consensus on formalisms, we need dynamic code. Also, note that WFS based semantics (e.g. WFSX [ADP95]) are arguably more tolerant of inconsistency than Stable Model-based (e.g. Answer Set [GL90]) semantics

Terrance Swift Topics in Logic Programming Implementation Prolog and Databases

Before considering dynamic code per se, lets compare Prolog to databases.

Is Prolog more declarative than a DBMS? Here declarative means Having a formal and clear semantics Allowing problems of similar complexity to be solved with similar clarity and with similar computational complexity Consider writing a join in SQL vs. writing a join in Prolog Which system will automatically optimize your query?

Terrance Swift Topics in Logic Programming Implementation Prolog and Databases

In many ways, the two cannot be compared – Prolog has dynamic rules (including facts), while a database has dynamic data. From the perspective of dynamic code, Prolog code can be self-modifying, databases do not allow this. Prolog is Turing-complete, which databases do not attempt to be. Prolog also supports structures to and recursion more thoroughly than databses – even those extended with SPARQL or other frameworks.

Terrance Swift Topics in Logic Programming Implementation Prolog and Databases

Standard Prolog doesn’t do some things that databases do 1 Access disks directly 2 Handle recoverability if there are crashes in the middle of a long computation 3 Optimize Non-Recursive Datalog queries 4 Allow data to be accessed in various ways through diverse indexing mechanisms 5 Allow multiple users to access and modify stored data 6 Ensure read consistency for queries

Arguably, number 6 is an important function for multi-threaded Prologs, numbers 3, 4 and 5 are important features for any Prolog XSB and YAP Prolog partially address 4, while multi-threaded prologs partially address 5 The logic Flora [YKWZ12] also partially addresses 2 and 6 See the papers on Aditi [VRK+91] for an interesting blend of LP and DB functionalities that addressed some of the other points.

Terrance Swift Topics in Logic Programming Implementation Dynamic Code

Most Prologs allow both static and dynamic code. Static code is fully compiled into WAM instructions; dynamic code may take shortcuts 14 Code is static by default; a dynamic predicate is declared using a declaration like :- dynamic predicate/3. There are no restrictions on dynamic code, and as we will see, Prolog systems go to lengths to support this generality. Static code is generally carefully compiled, and may have optimizations that make its execution faster; short-cuts are generally made when compiling dynamic code. On the other hand, dynamic code is often used to store a large amount of facts; as a result Prologs like XSB and YAP support special indexing mechanisms for dynamic code. In addition to “regular” dynamic code, XSB has trie-indexed dynamic facts and trie interned facts. So here, we’ll refer to “regular” dynamic code as dynamic rules, remembering that facts are also well supported. 14Dynamic rules were implemented by David Warren, Jiyang Xu, Terrance Swift, and Rui Marques Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Dynamic Compilation

Dynamic rules must be compiled quickly, probably in C, at assert time. This is not impossible for binary clauses

1 Generate get-type instructions for head 2 Generate put-type instructions for the body literal 3 Generate an execute instruction for the body literal (ignoring indexing for now) No allocate/deallocate needed, no complicated register allocation Example: the clause p(c) :- tnot(p(a)). is compiled as

test_heap 1, 2000 getcon r1, c putstr r1, p/1 bldcon a xsb_execute ’tnot’/1

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Dynamic Compilation

What about rules that have multiple literals in their body? Example: p(X) :- t(X,Y,Z), not q(c), q(b), not p(Y). Use a simple trick: translate ’,’ as a call to and/2

p(X) :- and(t(X,Y,Z), and(tnot(q(c)), and(tnot(q(b)),tnot(p(Y)))).

and(X,Y):- code_call(X),code_call(Y).

code call/1 is just a specialized form of call/1 The same trick works for ’;’ and ’->’

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Dynamic Compilation

Ok, but what about rules that have multiple literals in their body and a cut? Example: a(X):- b(X),c(X),!,d(X).

1 Transform to a(Y):- ’_$savecp’(Y),a_new(X,Y). a_new(X,Y):- b(X),c(X),’_$cutto’(Y),d(X). 2 ’ $savecp’/1 is compiled to a puttBreg instruction and ’ $cutto’/1 is compiled to a gettBreg instruction. Then transform to use and/2, then use binary clause compiler.

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Dynamic Compilation

Ok, but what about rules that have multiple literals in their body, a cut and are tabled? Make another transformation. Example:

:- table a/2. a(X,Y):- (p(X,Y) ; q(X,Y)),!. a(X,Y):- (p(X,Z) ; q(X,Z)),!,a(Z,Y). is translated to

:- table a/2.

a(X,Y):- a_new(X,Y).

a_new(X,Y):- (p(X,Y) ; q(X,Y)),!. a_new(X,Y):- (p(X,Z) ; q(X,Z)),!,a(Z,Y).

Then use other transformations and compile

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Dynamic Compilation

By the way, we haven’t talked about tables and cut. You can’t cut over a choice point for an incomplete table (You’ll get a table error if you do). This is checked dynamically. You can cut anywhere else (including choice points that backtrack through a completed table). In local evaluation, most cuts will not throw an error. Example: p(X,Y):- q(X),!,r(X) If q(X) is tabled and is not part of the open SCC, it can be completed. When it is completed, it will set up trie choice points for the completed table, and the cut will cut over these. Even if the cut doesn’t throw an error, to ensure the complexity properties, all answers will be generated for q(X) (and for subsidiary tables) before succeeding. So you don’t really get the results you want. Some work has been done on so-called relevant tabling [GG01, Swi99a], and some implementations of linear tabling [GG01, ZSYY01] have implemented this

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Dynamic Compilation

In summary There is a simple transformation for tabling, a simple transformation for cuts, predicates to execute ’,’/2, ’;’/2, ’->’/2 and a C compiler for binary clauses. Things have been simplified, just a litle. Dynamic facts and binary rules are compiled into code that is almost identical to that of compiled static facts and binary rules. Other Prologs differ with in how they compile asserted code – there’s no standard methodology that I know of.

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Indexing

Dynamic code can be indexed on alternate arguments. Indexing is always done via hashing

?- index(p/4,[1,2]) indicates that the first argument will be used to index if the first argument of the call is ground, and on the second if the first argument is not ground. If neither argument is ground, we’ll backtrack through all the clauses.

... on up to 3 compound arguments ?- index(p/4,[1+2]) indicates that a combination of the first two arguments are to be indexed if they are both ground ... or within an argument ?- index(p/4,*(1)) indicates that indexing is to be done on (currently) up to 4 positions within the first argument of a term. In other words, a call p([a,b,c,d...,...) would be *-indexed on ’.’,a,b,c but p(f(a,X,c),...) would be indexed only on f,a. ... or any combination of these

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Indexing

?- index(p/4,[*(3)+1,1+2,1,2]) is read as

If arguments 3 and 1 of a goal to p/4 are instantiated index on (up to) the first 4 positions of argument 3 plus the first position of argument 1 Else if arguments 1 and 2 are instantiated index on the first position of argument 2 plus the first position of argument 1 Else if arguments 2 is instantiated index on the first position of argument 2 Else if arguments 1 is instantiated index on the first position of argument 1

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Indexing

How is this supported? In XSB, the entry point to code is from a PSC record For dynamic code, the PSC record points to a Predicate Reference Record. This contains the entry point of the code along with other information, including the first and last clauses (for asserta/1 and assertz/1). The Predicate Reference Record may point into an Indexing Block. This indexing block may contain One or more switchonbound instructions to handle alternate argument indexing (e.g. [1,2]) A new instruction, (switchon3bound) to handle multiple-argument indexes or *-indexing There are 3 ”index” bytes in switchon3bound, each indicating one argument of a compoind index. star-indexing is indicated with the argument position + 128. Example: *(3)+2+1 would be indicated by bytes 131,2,1 A hash table for each alternate index (simple, *, or compound)

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Indexing

These Indexing Blocks point to a Clause Reference Block. The clause reference contains a repeating group of 1 or more backtracking instructions along with the actual SLG-WAM code for the clause

The hashtable, and switch-instructions point to the beginning of an indexing chain. The indexing chains create lists of clause references based on try-retry-trust instructions There is always an “all” chain to use when the call has variable indexing arguments There is a chain for each alternate index (of course, the chain may only contain one clause)

Thus, the instructions figure out which index to use based on which arguments are bound. Another instruction computes the hash, and the hash table points to the beginning of an indexing chain.

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Indexing

In XSB, indexing must be declared when there are no asserted clauses for a predicate – otherwise it has no effect. YAP has all indexing types of XSB, except for *-indexing. However with YAP indexing can be declared dynamic. Thus if calls are made: p(b,f,b) and p(f,b,b) and p/3 is declared to have dynamic indexing, p/3 will be indexed on 1+3 and 2+3.

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Retracting

From a computational viewpoint, there are different ways of retracting clauses Clause-level retraction Retracting a single clause using retract/1 Retracting a sequence of clauses for a predicate using retractall(Term) where Term is not an open predicate (e.g. p(a,Y,Z)) Predicate-level retraction Retracting the set of all clauses for a predicate using retractall(Term) where Term is an open predicate (e.g. p(X,Y,Z)) Abolishing the predicate.

Terrance Swift Topics in Logic Programming Implementation Dynamic Rules: Retracting

For clause-level retraction, a clause is invalidated by setting the first instruction of its code field to fail. For predicate-level retraction, clauses for a predicate are invalidated by resetting the first and last fields of the predicate reference. In clause-level retractall(Term) the choice point stack is traversed and all dynamic clauses are marked In backtracking through the clauses to retract, if there is danger of backtracking into a retracted clause, a clause reference frame is added to the garbage collection list; otherwise space is reclaimed. After backtracking through all the clauses that match Term the dynamic clauses are unmarked. In predicate-level retractall(Term), The choice point stack is traversed, If any clauses to the predicate of Term are on the stack, a predicate reference frame is added to the garbage collection list; otherwise space is reclaimed. In retract/1, clause garbage collection is called when the amount of retracted clauses and predicates gets above a certain threshold This approach is slightly different from other Prologs since XSB does not (yet) support read consistency for dynamic rules.

Terrance Swift Topics in Logic Programming Implementation Ensuring Read Consistency in Sequential Systems

What are the “correct” answers to the query and program fragment below?

:- dynamic p/3. p(1). p(2).

?- p(X),Y is X + 1,assert(p(Y)).

Under immediate semantics, you get X = 1, X = 2, X = 2, X = 3, X = 3, ... Under the so-called logical semantics [LO87] (now also the ISO semantics) the answer is X = 1, X = 2. Further answers, however, will be avilable to later queries. The logical semantics may or may not be logical, but it does enforce something like read consistency – let us call it query consistency. This may not be practically important for sequential systems but it is probably critical to multi-threaded systems. Unfortunately, unlike most Prologs, XSB does not implement the ISO semantics (For now. Usually.)

Terrance Swift Topics in Logic Programming Implementation Trie-Asserted and Trie-Interned Facts

By using the directive index(p/4,trie), p/4 asserting a p/4 fact causes it to be compiled into trie code, retracting at clause level it takes it out of the trie, and retracting it at predicate level removes the trie itself. By using special predicates, new trie(Trie), trie intern(Fact,Trie), trie interned(Fact,Trie), trie unintern(Fact,Trie), and delete trie(Trie) facts can be quickly added to a trie, accessed, and deleted from a trie. XSB’s assert is fast for dynamic rules. However trie-asserting is roughly 10x faster than regular assert, and trie-interning is roughly 100x faster. Note that tries are simpler – they give good indexing, but you lose the ordering of the clauses, and you cant directly call the bodies.

Terrance Swift Topics in Logic Programming Implementation Trie-Interned Facts

Interned tries are a promising data structure for shared dynamic code in a multi-threaded system.

Need to add read consistency by including in the trie leaf timestamps from which and to which the fact is valid Fact invalidation occurs by invalidating a node at a given position in the trie. A trie header structure keeps track of the readers of a trie, as well as the number of facts invalidated. When a reader enters a trie, the number of readers is increased, when a reader backtracks out of a trie, the number of readers is decreased using a special choice point instruction for the root of the trie. If the root choice point is removed via a cut or exception, a handler needs to be called to decrease the number of readers When the number of readers reaches 0, space for the table may be reclaimed (if there is much space to reclaim). While reclamation is active, any attempted reads will suspend on a condition variable

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling

Tabling doesn’t always work well when it depends on dynamic facts (or clauses) Consider this example: :- table p/2. p(X,Y) :- q(X,Y),Y =< 5.

:- dynamic q/2. q(a,1). q(b,3). q(c,5). q(d,7). and the following queries and results: | ?- p(X,Y),write([X,Y]),fail. [c,5] [b,3] [a,1]

no | ?- assert(q(d,4)).

yes | ?- p(X,Y),write([X,Y]),fail. [c,5] [b,3] [a,1]

no Terrance Swift Topics in Logic Programming Implementation Incremental Tabling

Incremental tabling in XSB [Sah06] provides a solution:

:- table p/2 as incremental. p(X,Y) :- q(X,Y),Y =< 5.

:- dynamic q/2 as incremental. q(a,1). q(b,3). q(c,5). q(d,7).

Now as before:

| ?- p(X,Y),write[X,Y]),fail. [c,5] [b,3] [a,1]

no

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling

However, we change the extension of tables when dynamic code is updated.

| ?- import incr_assert/1 from increval.

yes | ?- incr_assert(q(d,4)).

yes | ?- p(X,Y),write([X,Y]),fail. [d,4] [c,5] [b,3] [a,1]

no

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Conditional Answers

Incremental tabling works fine for conditional answers. Consider the program:

:- dynamic data/1 as incremental.

:- table opaque_undef/0 as opaque. opaque_undef:- tnot(opaque_undef).

:- table p/1 as incremental. p(_X):- opaque_undef. p(X):- data(X).

Note that in XSB, since p/1 depends on opaque undef/1, which is tabled, the latter predicate must be declared opaque.

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Conditional Answers

When the above program is loaded, XSB will behave as follows.

| ?- p1(1).

undefined | ?- incr_assert(data(1)).

yes | ?- p1(1).

yes | ?- incr_retract(data(1)).

yes | ?- p1(1).

undefined | ?- get_residual(p1(1),C).

C = [opaque_undef]

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: API

Other commands are allowed – such as incr retractall/1. Incremental tabling also works for trie indexed dynamic code and for interned tries (e.g, using the command incr trie intern/2). The commands incr < assert/retract > perform a database change operation and immediately update the affected tables. This may not be the right thing to do if 1 You want to do a bulk update. In this case you only want to updte once, after a sequence of asserts and retracts. 2 You aren’t sure which tables might be re-examined by the user For the first case, incr assert inval/1 (or related retracts) marks a table as needing an update, but does not update it. incr table update/0 and related predicates can then be used to update the invalid tables when needed. In fact, you don’t have to call incr assert inval/1: incremental tabling can perform lazy updates, so the next time you call an affected table it will aumatically update itself and all tables upon which it depends.

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Strategies

So a programmer can update immediately, after a batch, or lazily. In addition the user can just abolish a table T , and the system will ensure that any table that depends on T will also be abolished. The choice of which approach to use depends on when, and whether you want to pay the price for further updates. These features are in XSB 3.3.7. However, incremental tabling does not yet support call or answer subsumption, and is not integrated with the multi-threaded engine.

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: The Dynamic Dependency Graph

Incremental tabling – keeping tables in synch with dynamic data – could in principle be implemented in a number of different ways. The current implementation in XSB works broadly as follows A dynamic dependency graph is kept. The non-leaf nodes of this graph are the tables themselves. The leaf nodes are subgoals corresponding to calls to incrementally maintained dynamic predicates. If Tdep directly depends on Taff there is a depends link from Tdep to Taff and an affects link from Taff to Tdep. This is the same as SDG(F), except that the tables may be completed, and there are affects links in addition to dependency links.

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Invalidation

If a clause H :- B to an incremental dynamic predicate is asserted or retracted, then for each leaf node Dn that unifies with H, then all tables that (transitively) depend on Dn are marked as invalid. During the invalidation traversal, when a node is reached its falsity count is incremented. The falsitiy count for a node Tdep keeps track of how many of the nodes upon which Tdep immediately depends are invalid.

During the traversal, if a node Tdep is already invalid, its falsity count will be incremented, but nodes that Tdep affects will not be traversed.

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Lazy Recomputation

When an invalid table Tdep is called, the dynamic dependency subgraph on which Tdep is traversed, and the subgoals are queued in the order they need to be recomputed. When a table T is recomputed, if the extension of T does not change, the false count of all nodes that T immediately affects is decremented. During this step, if the falsity count of some table T 0 is decremented to 0, then the step is done recursively starting with T 0. During recomputation, any node with falsity count of 0 does not need to be recomputed, but can be skipped over.

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Eager Recomputation

The lazy recomputation of the previous slide occurs when an invalid tabled subgoal is called. Alternately, the tables can be recomputed at any time by traversing a list of the invalid subgoals in the dependency graph and recomputing them, using the same process. In the case of a massive update, it might be best simply to abolish the tables and start over. When abolishing an incrementally maintained table T , all tables that T transitively affects are also abolished.

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Dependency Graph Nodes

affected edges Calls that this subgoal affects dependency edges Calls upon which this subgoal depends subgoal pointer Pointer back to the subgoal frame nbr of answers CountS the number of answers rederived info deleted apparently invalid new answer set to true if a new answer has been derived recomputable determines if the call is recomputable using lazy evaluation falsecount determines whether subgoal is valid affected count count of directly affected calls previous call identifier

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Updating Tables

Let’s say that table T needs to be recomputed, and any table that T depends on has been updated. Let’s first assume there are only unconditional answers. Incremental tables maintain their answer list. The answer list is traversed to “soft delete” all answers – this simply sets a field in the leaf of each answer. Recall that the answer check/insert operation traverses a term and interns it into the trie: so we always know whether the answer is new or not. Thus, if the answer is old we simply undelete it. If the answer is new, we know that T has been changed, we set new answer to true and the change will need to be propagated. We also keep track of the number of answers before and after the updated (via nbr of answers). If the number is different, we know that T has changed. If nbr of answers is the same, and there are no new answers, we know that T hasn’t changed!

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Updating Tables

Now let’s consider the case where T has conditional answers. We now maintain nbr of unconds (nee nbr of answers) and nbr of conds. We also maintain a counter nbr of new unconds

If we previously had a conditional answer A :- D1| and now we derive a new answer A :- D2|. The first conditional answer for A will increment nbr of conds. Further conditional answers for A do not update this field. Recall that SLG answer resolution will only propagate A anyway.

If we previously had an answer A :- D1| and now we derive A unconditionally we increment nbr of unconds and nbr of new unconds, then call simplification. new answer is not set. If we previously had an unconditional answer A and now we only have conditional answers for A we will have to recompute tables affected by T . There are no simplification back-pointers to use.

Terrance Swift Topics in Logic Programming Implementation Incremental Tabling: Updating Tables

Let’s assume that new answer is false. When do we have to update? Note that if new answer is false, then

nbr of uncondsold + nbr of condsold = nbr of uncondsnew + nbr of condsnew But this alone isn’t enough as some answers may have turned conditional and others unconditional. In addition to the above equation, we want

nbr of uncondsold = nbr of uncondsnew − nbr of new unconds and

nbr of condsold = nbr of condsnew + nbr of new unconds If these three conditions (which can be easily checked) hold, we do not need to propagate.

Terrance Swift Topics in Logic Programming Implementation Dynamic Code: Summary

Prolog and Databases Prolog’s strength compared to a database is that it allows dynamic rules (viewable as data) that include unification, constraints, tabling, etc. Databases allow query optimization. Much work has been done on program analysis and optimization, but even simple query optimizers are not integrated into Prolog compilers or command-loop interpreters. New and better clause indexing methods have become available including trie indexing and YAP’s adaptive indexing. Read consistency is part of the ISO standard Good algorithms for accessing and maintaining dynamic code in multi-threaded systems have not yet been developed. More work needs to be done to maintain table validity with respect to dynamic data.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 9: Constraints and CHR; Tabled Constraints

Terrance Swift Topics in Logic Programming Implementation Constraints

The subfield of Constraint Logic Programming is a rich and highly developed field. We don’t have time to adequately cover all aspects of CLP in one or two lectures. All we can do here is to focus on its operational and implementational aspects. In CLP the variables of an answer may be associated with constraints in a given domain. For instance, in Prolog an answer to f(X,Y,Z) may have the form X = Y = Z While in CLP(R) the answer may have the form X = 2*Y +Z and in CLP(FD) the answer may have the form X = Y = Z, Z = {red,blue} As another example, Prolog does not have set unification: in set theory {a, b, c} = {c, b, a} but as terms it is not true that {a,b,c} = {c,b,a}

Terrance Swift Topics in Logic Programming Implementation Constraints

At this point, a skeptic might say: what good is CLP? Prolog is Turing-Complete, so I can always write a program in Prolog (with or without tabling) to compute equations, sets, etc. The answer to this is: yes you can. However, the addition of constraint domains to Prolog programs can give a Prolog system much more power, by giving good libraries to process real equations, temporal constraints, etc., and by allowing the constraint systems to be handled somewhat transparently to the user. The result is programming that is more declarative than otherwise. Constraints can also add efficiency by pruning the search space for the programmer (ex. 8-queens in CLP(FD)). Of course the programmer might prune the search space herself, but the pruning is done automatically using CLP systems.

Terrance Swift Topics in Logic Programming Implementation Examples: CLP(R)

Another View of Mt. Factorial

:- import {}/1 from clpr.

fact(0.0, 1). fact(N, NF) :- {N > 0,N1 = N-1,NF = N*F}, fact(N1,F).

The query fact(10,X) gives X = 3628800.0000 as before, but now we can also ask fact(N,3628800) which gives N = 10.0000 Note that this wouldn’t work in traditional Prolog using N1 is N - 1.

Terrance Swift Topics in Logic Programming Implementation Examples: CLP(R)

mortgage(Principal, Time, Rate, Balance, Payment) :- {0 < Time, Time =< 1}, {Balance + Payment = Principal * (1 + Rate * Time) }.

mortgage(Principal, Time, Rate, Balance, Payment) :- {1 < Time, Principal1 = Principal * (1 + Rate) - Payment, Time1 = Time - 1}, mortgage(Principal1, Time1, Rate, Balance, Payment).

| ?- mortgage(120000, 120, 0.01, 0, Payment). Payment = 1721.6514

| ?- mortgage(Principal, 120, 0.01, 0, 1721.65). Principal = 119999.9038

| ?- mortgage(Principal, 120, 0.01, 0, Payment). { Payment = 0.0143 * Principal }

| ?- mortgage(Principal, 120, 0.01, Balance, Payment). { Balance = 3.3004 * Principal - 230.0387 * Payment }

Terrance Swift Topics in Logic Programming Implementation Examples: CLP(FD)

SEND + M O R E ------MONEY

Assign numbers to each of the letters S,E,N,D,M,O,R,Y so that the number SEND plus the number MORE equals the number MONEY.

Terrance Swift Topics in Logic Programming Implementation Examples: CLP(FD)

send([[S,E,N,D], [M,O,R,E], [M,O,N,E,Y]]) :- Digits = [S,E,N,D,M,O,R,Y], Carries = [C1,C2,C3,C4], Digits in 0..9, Carries in 0..1, M #= C4, O + 10 * C4 #= M + S + C3, N + 10 * C3 #= O + E + C2, E + 10 * C2 #= R + N + C1, Y + 10 * C1 #= E + D, M #>= 1, S #>= 1, all_different(Digits), label(Digits).

Better CLP(FD) packages than XSB’s can solve Sudoku. I believe the best constraint systems may handle up to 36X36 Sudokus.

Terrance Swift Topics in Logic Programming Implementation Examples: CLP(FD)

Var in Set, e.g. Digits in 0..9

Expr1 #= Expr2, e.g. M #= C4. Constrain Expr1 to be equal to Expr2. Similar with #/2, etc. all different(List) All variables in List are constrained to be different. label(List) label all elements in List with elements of their attached domains. This allows derivation of concrete solutions.

Terrance Swift Topics in Logic Programming Implementation Attributed Variables

At the engine level, constraints are implemented by attributed variables Recall that in the WAM, a variable is simply a pointer, an aliased variable is a pointer to another variable, a free variable is a pointer to itself, etc. In XSB, a variable has the tag 0 for quick pointer dereferencing An attributed variable is like a variable, but has a different tag, and is associated with a structure of its attributes which represent its constraints E.g. in CLP(FD) the attributes might be the domain elements with which the variable may unify.

Terrance Swift Topics in Logic Programming Implementation Attributed Variables

Attributes of variables are affected by unification is a series of steps When an attributed variable is bound to another variable, constant or structure, an interrupt is generated so that a handler will be called to process the attributes. This interrupt is put onto a thread-private interrupt chain The interrupt handler may be written in Prolog, but to be called, the Prolog registers need to be in a state where it is safe to handle an interrupt

Terrance Swift Topics in Logic Programming Implementation Attributed Variables

Attributed variables are a new tagged WAM type, and affect most of the engine An example of how it affects the unification part of getcon is shown below This code can be made more efficient.

unify with con(OP1,OP2) /* OP1 is a register value, OP2 is a constant */ deref(OP1) if (isVariable(OP1)) bind OP1 to OP2, trailing if necessary else if (isatom(OP1)) if (atom val(OP1) == (char *)OP2) else Fail else if (isattv(OP1)) add interrupt(cell(((CPtr)dec addr(OP1) + 1)),OP2) bind OP1 to OP2, trailing if necessary else Fail

Terrance Swift Topics in Logic Programming Implementation Attributed Variables

Setting up calls to the interrupt handler

To handle interrupts, the set of interrupts in the interrupt vector is dynamically inserted between some WAM instructions. How is this done? At a call instruction that will call a goal G, we know that register 1 corresponds to argument 1 of the call, register 2 to argument 2, etc. To handle the interrupts,

1 Build the call on the heap obtaining the functor and arity from call 2 Copy the interrupt chain onto the heap as a list 3 Call the handler which will execute the list of interrupting calls, then call G as a continuation Interrupts can be handled similarly at the proceed instruction – and more simply. At proceed, the list of interrupts needs to be built but not the call – all we need to do is to ensure that the P register is reset to the CP register after all of the interrupts have succeeded.

Terrance Swift Topics in Logic Programming Implementation Attributed Variables

Handling the interrupt Once the calls are set up, ’ $attv int’/2 is called, with its first argument the list of interrupts and its second argument the continuation In XSB as in many Prologs, different constraint systems may be in effect at the same time. Thus, for each attributed variable, we check its effect on the different constraint systems (represented by Mod below). The handler typically has as its arguments Attr, the attributes of the unified variable, as well as the Value to which the variable was bound

’_$attv_int’(Intlist, Call) :- handle_interrupts(Intlist), call_c(Call). % low-level call/1

handle_interrupts([]). handle_interrupts([[Atts|Value]|Ints]) :- call_attribute_handlers(Atts,Value), handle_interrupts(Ints).

call_attribute_handlers([],_). call_attribute_handlers([Mod,Attr|Rest],Value) :- verify_attribute_handler(Mod,Attr,Value,Handler), call_c(Handler), call_attribute_handlers(Rest,Value). Terrance Swift Topics in Logic Programming Implementation A Toy Finite Domain Handler

The code below shows some prinicples of writing a constraint handler – of course a real handler and system for CLP(FD) is much more complex. The predicate is installed as an attribute handler via :- install_verify_attribute_handler(fd,AttrVal, Target,fd_handler(AttrVal,Target)). which installs it as the handler for the constraint domain fd

fd_handler(Da, Targ) :- (var(Targ), % Targ is an (attr) var get_attr(Targ, fd, Db) -> % has a domain intersection(Da, Db, [E|Es]), % intersection not empty (Es = [] -> % exactly one element Targ = E % bind Var (and Val) to E ; put_attr(Targ, fd, [E|Es]) % update Var’s (and Val’s) ) ; memberchk(Targ, Da) % is Targ a member of Da? ).

Terrance Swift Topics in Logic Programming Implementation Attributed Variables

get attr/3 is a Prolog predicate that depends on the C function get attr/2 which returns all attributes for a variable, regardless of the constraint domain. get attr/3 then recurses through the list, to find the right attributes for the module. Note that get attr/2 will fail if the input variables is not an attributed variable

get attr(Reg1,Reg2) /* R1: +Var; R2: -List */ addr = *(Reg1) deref(addr) if (isVariable(addr)) /* a non-attr var */ return FALSE else if (isattv(addr)) list = *(Reg2) deref(list) if (isref(addr)) bind addr to list (i.e. with trailing if necessary) else throw an instantiation error return TRUE

Terrance Swift Topics in Logic Programming Implementation Attributed Variables

The semantics of put attr/3 is based on put attr/2 in the same way that get attr/3 is based on get attr/2 Note the semantics of put attr/2: the empty list in the second argument makes the attributed variable point to a free variable

put attr(Reg1,Reg1) /* R1: -Var; R2: +List */ attv = *(Reg1) deref(attv) atts = *(Reg2) deref(atts) if (isVariable(attv)) /* attv is a free var */ if (!isnil(atts)) build an attributed variable A on the heap and bind attv to A else if (isattv(attv)) /* attv is already an attv */ if (isnil(atts)) /* change it back to normal var */ build a free variable A on the heap and bind attv to A else /* update the atts (another copy) */ build a new attributed variable A on the heap and bind attv to A else throw an instantiatino error

Terrance Swift Topics in Logic Programming Implementation Constraint Handling Rules

Understand all that? Ready to write a library to use attributed variables to solve constraints over a complex domain? This is indeed a low level interface, and many people find it easier to program using Constraint Handling Rules [Fru97]. The constraint handling rules are then compiled into attributed variables, using a CHR compiler and library. Constraint handling rules are based on the fact that in constraint domains, the two main operations are simplification and propagation. Constraint handling rules also can ensure that constraints are rewritten into a normal form

Terrance Swift Topics in Logic Programming Implementation Constraint Handling Rules

Lets consider a simple example from [Fru97] of the domain of partial orders. The CHR rules are: reflexivity @ X= X=Y | true antisymmetry @ X =< Y, Y =< X <=> X = Y transitivity @ X =< Y, Y =< Z ==> X =< Z

Reflexivity can be read as if there is a constraint of the form X =< Y and in addition, X = Y, then remove the constraint X =< Y from the system. Here, X = Y is a guard, a predicate to be applied to X and Y, but the constraint system does not have to have the constraint X = Y Antisymmetry can be read as if there is a constraint of the form X =< Y and another constraint of the form Y =< X, then these two constraints can be removed from the system and replaced with X = Y. Transititivity can be read as if there is a constraint of the form X =< Y and a constraint of the form Y =< Z, then add a constraint Y =< Z Terrance Swift Topics in Logic Programming Implementation A Toy Finite Domain Handler in CHR

:- chr_module(dom).

:- constraints dom/2.

dom(X,[]) <=> fail. dom(X,[Y]) <=> X = Y. dom(X,L1), dom(X,L2) <=> intersection(L1,L2,L3), dom(X,L3).

Terrance Swift Topics in Logic Programming Implementation Constraint Handling Rules

We don’t have time to cover the implementation of CHR in detail (its complicated) but a few points may give a general idea CHR requires two levels of access to constraints Access to the constraints in effect for a given variable (after all, CHR uses variable attributes) Access to a global constraint store so that when a variable is bound or has a new constraint attached to it, the simplification and propagation rules can be invoked. Debuggers can be written that allow stepping through the firing of CHR rules, so that CHR programs can be traced more easily than constraint libraries that compile directly to attributed variables (Sicstus, SWI and others have such a debugger, XSB does not).

Terrance Swift Topics in Logic Programming Implementation Constraints and Tabling

Constraints are pretty useful already, combined with tabling they can be useful for model checking of real time systems and constraint-based attribute grammars. If p/3 is tabled, then a constrained goal p(X,Y,Z): X > Z can also be tabled. Constrained answers may also be returned, such as p(X,Y,Z): X > Z + Y, Y > 0. Subsumption works for constrained goals in an analagous manner. p(X): X > 2 subsumes p(X): X > 3. In case this is confusing, note that the set X > 3 is smaller than the set X > 2, so that any answer to X > 3 is also an answer to X > 2 In the current version of XSB, constraints are not integrated with call subsumption. This means that p(X): X > 2 and p(X): X > 3 will have different table entries. The main idea behind the implementation of tabled constraints is to copy attributed variables into and out of tables properly. There are some intricacies in doing this that we won’t discuss [SWD03, CW00]

Terrance Swift Topics in Logic Programming Implementation CLP Implementations

As of March 2011 All major Prologs support some sort of CLP, usually implemented through attributed variables. For CLP(R) all Prologs support variants of Sicstus’ Holzbauer implementation. Some Prolog’s add other packages for linear programming via the simplex algorithm Most Prologs support CLP(Q). XSB currently does not as many CLP(Q) implementations require arbitrary precision integers. Most Prologs also support CLP(FD) – XSB does not currently have a full CLP(FD) package, but rather supports a simplified implementation. Both Sicstus and GNU Prolog have some of the leading implementations of CLP(FD), which they implement using bit vectors in addition to attributed variables. Most Prologs also support CHR, and use variants of the CHR package first implemented for Sicstus and currently maintained for SWI. XSB’s CHR system is an older version of that CHR system.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Topic 10: Answer Subsumption

Terrance Swift Topics in Logic Programming Implementation Shortest Path Problem

A simple problem that we all know – or think we do Can be written in pure Prolog Non-declarative and inefficient Cost may be proportional to number of paths in a graph, not number of edges Can be written in Prolog + constraints Declarative, but still inefficient Can use an ASP grounder...

Terrance Swift Topics in Logic Programming Implementation Shortest Path in ASP

An example would be: pref distance(X,Y,1, ):- edge(X,Y). pref distance(X,Z,N,Max):- pref distance(X,Y,N1,Max), edge(Y,Z), N is N1 + 1, N < Max, not(preferred distance(X,Z,N,Max)).

preferred distance(X,Y,N,Max):- pref distance(X,Y,M,Max),M < N. This is now polynomial in the size of the graph, but we’re still far from optimal complexity Is there a (significantly) better way to write this using an ASP grounder?

Terrance Swift Topics in Logic Programming Implementation Shortest Path using Tabling

:- table sp( , ,po(

The declaration indicates that the third argument is to be minimized: i.e. maximized on the partial order

Terrance Swift Topics in Logic Programming Implementation Partial Order Answer Subsumption

The shortest-path predicate uses partial order answer subsumption. We allow subsumption to be declared only on one argument (assume last, for purposes of presentation)

A partial order ≥O is defined. Let AD be a derived answer, and AT be an answer in the table, such that AD and AT have the same bindings apart from the subsuming argument. AD will only be added to the table if its subsuming argument is not ≤o the subsuming argument of AT

AD >O AT , AT will be removed from the table. Otherwise, if neither AD nor AT is greater, AD will be added and AT will be retained Partial-order answer subsumption can provide an excellent alternative to default-based methods for programming with preferred answers (e.g. preference grammars [GJM95, CS02])

Terrance Swift Topics in Logic Programming Implementation Answer Subsumption vs. Call Subsumption

For definite programs tabling can be thought of like this: If a subgoal is repeatedly encountered, then use answers from the table, rather than resolving against program clauses A subgoal S is “repeatedly encountered” if there is a entry for S in the table (call variance) or if there is a entry that subsumes S in the table (call subsumption) When a new answer is derived, add it to the table for S An answer A is “new” if it is not in the table for S (answer variance) or if it is not subsumed by any answer for S (partial order answer subsumption) Call subsumption can be useful for efficiency Answer subsumption can be useful to implement new logics

Terrance Swift Topics in Logic Programming Implementation Lattice Answer Subsumption

Consider AD and AT as before. If neither answer were greater the join of the subsuming argument can be taken. :- table sp( , ,lattice(min/3)). sp(X,Y,1):- edge(X,Y). sp(X,Z,N):- sp(X,Y,N1),edge(Y,Z),N is N1 + 1. Again, the join predicate could be any user-defined predicate For total orders, lattice and partial order answer subsumption act the same Given an associative, commutative and idempotent binary function F : then there is a partial order P such that P is an upper semi-lattice with join F .

Terrance Swift Topics in Logic Programming Implementation Lattice Answer Subsumption

Lattice answer subsumption is the basis for implementing Generalized Annotated Programs [KS92], Residuated Lattice Programs [DP01a], Bilattices [Fit91], and many other formalisms. For instance

Derivations of p(a):true and p(a):false might be joined as p(a):top. Derivations of p(a):(0.3,0,7) and p(a):(0.7,0.2) might be joined as p(a):(0.7,0.7) (actually these would be coded as e.g. p(a,(0.7,0.7))) These, in turn, can express paraconsistency, uncertainty, temporal reasoning, and much else. Logic Programs with Annotated Disjunctions [VVB04] (a type of Probabilistic Logic Programming) been implemented using Lattice Answer Subsumption in XSB PITA package [RS10]. As discussed in [RS11] the PITA package also implements probabilistic logic programs in the style of Prism [SZKI10], including Viturbi probabilities, as well as Possibilistic Logic Programs [DLP94].

Terrance Swift Topics in Logic Programming Implementation Lattice Answer Subsumption

Consider a model of quantitative degrees of belief [van86]

An atom A is annotated with ET , a number between 0 and 1 indicating a measure of evidence that A is true and EF , a number between 0 and 1 indicating that A is false. A :[ET , EF ] Resolution for these annotated literals can be defined. The main idea is:

A goal A :[ET , EF ] is true in a program P if there is a rule

0 0 0 A :[ET , EF ]: −Body 0 0 0 such that A unifies with A, ET ≥ ET and FT ≤ FT – and Body is true in P Generalizing this approach to upper semi-lattices, you get Generalized Annotated Programs (GAPs) [KS92], definite programs that can model many kinds of quantitative reasoning, paraconsistent reasoning, and temporal reasoning.

Terrance Swift Topics in Logic Programming Implementation Lattice Answer Subsumption

Lattice answer subsumption can implement courteous logic programming [Gro97] (a type of defeasible logic program) using the following lattice

top

true default false

mutually refuted refuted true default refuted false

mutually rebutted

bottom

Terrance Swift Topics in Logic Programming Implementation Partial Order Answer Subsumption with Abstraction

Abstract domains, used for program analysis [CC77] and model checking, are usually lattices An answer may be a function type, a configuration, etc. For some domains, not all pairs of answers have a least upper bound At the same time, you may need to abstract some answers to ensure termination A declaration such as :- table p( , ,po(rel/2,abs/3)) applies abstraction lazily

Terrance Swift Topics in Logic Programming Implementation Partial Order Answer Subsumption with Abstraction

A given Petri Net may have an infinite number of configurations

t1 s2 t3 s4

s1 t4 t2 s3

Repeated application of t1, for instance, leads to an arbitrary number of tokens in s2

Terrance Swift Topics in Logic Programming Implementation Partial Order Answer Subsumption with Abstraction

Reachability is decidable using a technique called ω-abstraction Intuitively, configurations have a “regular” form Certain places may be marked with the token ω

E.g. s1:1, s2:ω, s3:0, s4:0 >ω s1:1, s2:7, s3:0, s4:0 When a configuration C is reached, a set C of similar configurations is obtained. The set C ∪ C is checked to see if abstraction is required

If so, the abstraction CA is made, added to the table, and those answers <ω CA are removed If no abstraction is needed, C is handled just as with partial order answer subsumption (add CA if it is not <ω any other answer and delete answers <ω CA)

Terrance Swift Topics in Logic Programming Implementation Partial Order Answer Subsumption with Abstraction

Reachability analysis of Petri Nets came out of work for verifying properties of health care workflows. A program that implements this is available in the CVS version of the XSB test suite.

Terrance Swift Topics in Logic Programming Implementation All Pairs Shortest Path Performance on Sparse Graphs

Vertices Time Table Space (bytes) Answers 25000 1.7 44,146,000 960,588 50000 7.5 198,905,244 4,324,742 75000 12.8 307,611,736 6,683,493 100000 9.8 212,186,848 4,611,563 125000 57.6 1,128,215,852 24,617,754

Sparse graphs (i.e. those without a giant component) are useful for many types of social network analysis About 46 bytes/answer About 43,000 answers per second (2006 Mac)

Terrance Swift Topics in Logic Programming Implementation All Pairs Shortest Path Performance on Dense Graphs

Avg. Edges/Vert. 2 8 32 128 512 sp/3-Lattice Time 2.3 13.2 52.1 211.9 880 Table Space 26,249,826 41,213,664 41,213,664 41,213,664 41,213,664 Answers 631,509 1,000,000 1,000,000 1,000,000 1,000,000 sp/3-PO Time 4.1 16.5 56 218.2 890 Table Space 26,249,860 41,213,688 41,214,084 41,214,084 41,214,084 reach/3 Time 0.88 3.47 12.5 53.2 238 Table Space 26,241,796 41,205,624 41,205,624 41,205,624 41,205,624 sp del/3 Time 4.2 104.0 329 845 2392 Table Space 27,198,048 41,203,908 41,290,552 41,322,464 41,345,080 Answers 655,221 999,000 1,000,000 1,000,000 1,000,000 Deletes 281,834 2,416,658 4,917,751 6,960,565 8,407,883

Randomly generated graphs of 1000 vertices and various edges/vertix

:- table reach/3. reach(X,Y,1):- edge(X,Y). reach(X,Z,1):- reach(X,Y,N1),edge(Y,Z), N is N1 + 1.

:- table sp del(X,Y,lattice(min/3)). sp del(X,Y,D):- edge(X,Y,D). sp del(X,Z,D3):- sp del(X,Y,D1),edge(Y,Z,D2),D3 is D1 + D2

Terrance Swift Topics in Logic Programming Implementation Performance Summary

Lattice answer subsumption is slightly faster than partial order answer subsumption for this example. The implementation makes use of the fact that there can be only one answer in the table for a given substitution. The use of answer subsumption with deletions imposes an overhead of 3-4x for this example. For most practical examples, this overhead would be much less, of course. Answer subsumption is roughly linear in the number of derivations + deletions. Answer subsumption imposes essentially no space penalty over regular tabling

Terrance Swift Topics in Logic Programming Implementation System Integration of Answer Subsumption

In XSB, answer subsumption currently can be used with Thread-private and thread-shared tables Static and dynamic code With the following limitations Fixed-order stratified programs Call variance but not call subsumption Non-incremental tabling only

Terrance Swift Topics in Logic Programming Implementation Summary

Answer subsumption Can provide the underpinnings for putting more sophisticated logics into Prolog-based systems – from GAPs to defeasible logics to probabilistic logics. Answer subsumption has direct applications for analysis and model checking problems Subsumed arguments can also represent constraints, so that the join of constrained equations can also be taken (works in principle, but needs testing in XSB). Answer subsumption can be ported relatively easily to YAP, Ciao and other systems May be useful outside of tabling for grounders (or combine bottom-up grounding with top-down

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Call Abstraction

Terrance Swift Topics in Logic Programming Implementation Call Abstraction for Various Types of Programs

Definite Program “Stratified” Programs Non-Stratified Programs Abstraction for Attributed Variables

Terrance Swift Topics in Logic Programming Implementation Call Abstraction for Definite Programs

The action is to abstract subgoals whose depth is greater than some fixed N, e.g.

p(f (f (f (1)))) →abs p(f (f (X ))) This has been shown to provide completeness for definite programs with finite models [TS86] and for stratified programs [RS12]. However you don’t want to always abstract subgoals, e.g.

member(c, [a, b, c, d, e]) →abs member(c, [a, b, X ]) which will lead to non-termination Note that any program containing member/2 and at least one constant does not have a finite model. From the point of view of grammars, abstracting out a sentence changes the problem from recognition of whether a string is in a grammer to generating strings from a grammar.

Terrance Swift Topics in Logic Programming Implementation Call Abstraction for Normal Programs

Another problem for abstraction is with negation

tnot(p(f (f (f (1))))) → tnot(p(f (f (X )))

must handle the variable introduction in order not to flounder Actually, floundering programs do terminate, but that doesn’t really count!

Terrance Swift Topics in Logic Programming Implementation Call Abstraction for Non-stratified Programs

What is a finite 3-valued model. 2 out of the 3 truth values need to be finite. For instance, the program

p(f (X )) ← p(X ), undefined

p(s(1)) has finitely many true atoms, but has an infinite number of undefined atoms and false atoms. In general, for a 3-valued model to be finitely representable via sets, a finite number of atoms must be mapped to 2 out of the 3 truth values. Within WFS, tabling with call abstraction terminates on a class of programs that is very general compared to other termination classes in the literature [RS12].

Terrance Swift Topics in Logic Programming Implementation Call Abstraction for Attributed Variables

Regardless of the depth, the structure associated with an attributed variable must be entirely abstracted, or not abstracted at all. The current simple approach is to forget about depth abstraction in arguments that have attributed variables. A completeley different approach is to abstract all attributed variables, regardless of depth.

Terrance Swift Topics in Logic Programming Implementation Implementation Approach: Definite Programs

Want Call Abstraction to be so efficient that there is no hesitation in using it for predicates that might need it. When traversing a subgoal S to determine whether S is in a table, S may be abstracted to Sabs . During this traversal an abstraction vector is created. This abstraction vector can be thought of as representing bindings η such that Sabs η = S.

When an answer Sabs θ is returned to S, the bindings in the abstraction vector η are applied to Sabs θ. If they succeed, Sabs θ is an answer for Sabs η, otherwise, it isn’t and the engine backtracks to try other answers. There is no new traversal of S, and only a few checks that the abstraction vector has a non-zero size, so there is no measurable overhead if call abstraction is not used. Implementation is slightly tricky because of the delecacy of destructive assignment in the abstraction operation (non-variables are rewritten as variables), along with the extra post-unification step

Terrance Swift Topics in Logic Programming Implementation Implementation Approach: Negation

For stratified programs, tnot/1 must be changed to determine that no answer for Sabs unifies with the ground subgoal S. For non-stratified programs a bit more thought needs to be done. Simplification structures sometimes need to be linked to ground subgoals

Terrance Swift Topics in Logic Programming Implementation Status

Abstraction through positive literals is implemented in XSB and thoroughly tested. A test suite was created for call abstraction and The entire XSB test suite was run using an abstraction depth of 4. This latter test shook out numerous bugs As a temporary first step, abstraction of a subgoal called by tnot/1 will throw an exception.

Terrance Swift Topics in Logic Programming Implementation Summary

Call abstraction can be set in the following ways:

1 Setting the depth using the Prolog flag max table subgoal depth and setting the flag max table subgoal action to abstract rather than error. 2 Using a predicate-level declaration. This is not yet defined, but will be along the lines of :- table p/n as subgoal_abstract(N) The specific depth overrides the default depth. 3 Using a command line argument, e.g. xsb --call-abstract N which may be useful for testing At this time, there are no “smarts” for how to set the level.

Terrance Swift Topics in Logic Programming Implementation Summary

Does call abstraction work with... Call-variant tabling – yes. Incremental Tabling – yes. Multi-threading – yes. Changes affect a thread’s execution stack only – no changes to shared data atructures. Answer subsumption – yes. Heap, Table, String, and Dynamic Clause Garbage Collection – yes. Bindings and destructive assignment are safe for heap garbage collection. Call-subsumptive tabling – not implemented yet. Full WFS – does not yet abstract through tnot/1 or sknot/1 operators.

Terrance Swift Topics in Logic Programming Implementation Beyond the WAM: Topics in Contemporary Logic Programming Implementation

Summary

Terrance Swift Topics in Logic Programming Implementation Summary of Tabling Features

We’ve presented lots of tabling and system features: Call variance vs. Call Subsumption Negation Static vs. Dynamic Code Multi-threading Attribute variables Incremental Tabling Answer Subsumption Call Abstraction Altogether, that’s a lot of features to support. Which features actually work together in practice?

Terrance Swift Topics in Logic Programming Implementation Summary of Tabling Features: Negation

Negation is fully supported for call variance, call subsumption, dynamic code, incrmental tables, private and shared tables (where the shared tables are evaluated using local evaluation). Attributed variables are well-supported with negation and are maintained in the residual program. Space reclamation works fine for tables, including delay lists and delay elements. Answer subsumption only works for left-to-right dynamically stratified programs. Call abstraction does not abstract calls within the tnot/1 or sknot/1 operators

Terrance Swift Topics in Logic Programming Implementation Summary of Tabling Features: Attributed Variables

Fully supported for call variance, dynamic code, private and shared tables (where the shared tables are evaluated using local evaluation). As mentioned, attributed variables are well-supported with negation and are maintained in the residual program. Attributed variables work fine with call subsumption as long as the attributed variables are in answers only; work is under way to allow them with calls as well. Attributed variables should work ok with incremental tables and with answer subsumption – but systematic testing has not yet been done. ... and now for the rest of the story:

Terrance Swift Topics in Logic Programming Implementation Cross-compatibility of Tabling Features

variant static private nonincremental no answer subsumption yes variant static private nonincremental answer subsumption yes variant static private opaque no answer subsumption yes variant static private opaque answer subsumption no variant static private incremental no answer subsumption yes variant static private incremental answer subsumption no variant static shared nonincremental no answer subsumption yes variant static shared nonincremental answer subsumption yes variant static shared opaque no answer subsumption no variant static shared opaque answer subsumption no variant static shared incremental no answer subsumption no variant static shared incremental answer subsumption no variant dynamic private nonincremental no answer subsumption yes variant dynamic private nonincremental answer subsumption yes variant dynamic private opaque no answer subsumption no variant dynamic private opaque answer subsumption no variant dynamic private incremental no answer subsumption no variant dynamic private incremental answer subsumption no variant dynamic shared nonincremental no answer subsumption yes variant dynamic shared nonincremental answer subsumption yes variant dynamic shared opaque no answer subsumption no variant dynamic shared opaque answer subsumption no variant dynamic shared incremental no answer subsumption no variant dynamic shared incremental answer subsumption no

Terrance Swift Topics in Logic Programming Implementation Cross-compatibility of Tabling Features

subsumptive static private nonincremental no answer subsumption yes subsumptive static private nonincremental answer subsumption no subsumptive static private opaque no answer subsumption yes subsumptive static private opaque answer subsumption no subsumptive static private incremental no answer subsumption no subsumptive static private incremental answer subsumption no subsumptive static shared nonincremental no answer subsumption no subsumptive static shared nonincremental answer subsumption no subsumptive static shared opaque no answer subsumption no subsumptive static shared opaque answer subsumption no subsumptive static shared incremental no answer subsumption no subsumptive static shared incremental answer subsumption no subsumptive dynamic private nonincremental no answer subsumption yes subsumptive dynamic private nonincremental answer subsumption no subsumptive dynamic private opaque no answer subsumption yes subsumptive dynamic private opaque answer subsumption no subsumptive dynamic private incremental no answer subsumption no subsumptive dynamic private incremental answer subsumption no subsumptive dynamic shared nonincremental no answer subsumption no subsumptive dynamic shared nonincremental answer subsumption no subsumptive dynamic shared opaque no answer subsumption no subsumptive dynamic shared opaque answer subsumption no subsumptive dynamic shared incremental no answer subsumption no subsumptive dynamic shared incremental answer subsumption no

Terrance Swift Topics in Logic Programming Implementation ReferencesI

[AAB+04] J. J. Alferes, F. Azevedo, P. Barahona, C. Dam´asio,and T. Swift. Logic programming techniques for solving circuit diagnosis. In Artificial Intelligence Applications and Innovations, pages 155–166, 2004. [ABW88] 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. [ADP95] J.J. Alferes, C. Dam´asio,and L. M. Pereira. A logic programming system for non-monotonic reasoning. Journal of Automated Reasoning, 14(1):93–147, 1995.

[AK90a] H. Ait-Kaci. The WAM: a (real) tutorial. Technical Report 5, DEC Paris Research Report, 1990. [AK90b] K. Ali and R. Karlsson. The Muse or-parallel Prolog model and its performance. In NAACLP ’90, 1990. [ALPQ00] J. J. Alferes, J. A. Leite, L. M. Pereira, and P. Quaresma. Planning as abductive updating. In AISB Symposium on AI Planning and Intelligent Agents, pages 1–8, 2000. [APA94] Diagnostic and Statistical Manual of Mental Disorders. American Psychiatric Association, Washington,DC, 4th edition, 1994. Prepared by the Task Force on DSM-IV and other committees and work groups of the American Psychiatric Association.

Terrance Swift Topics in Logic Programming Implementation ReferencesII

[APPP02] J. J. Alferes, L. M. Pereira, H. Przymusinska, and T. Przymusinski. LUPS : A language for updating logic programs. Artificial Intelligence, 138(1-2), 2002.

[ARD08] H. Anh, C. Ramli, and C. Damsio. An implementation of extended P-Log using XASP. In Intl. Conf. on Logic Prog., pages 739–743, 2008. [BF91] N. Bidoit and C. Froidevaux. Negation by default and unstratifiable logic programs. Theoretical Computer Science, 78:85–112, 1991. [BG05] S. Bhansali and B. Grosof. Extending the SweetDeal approach for e-procurement using SweetRules and RuleML. In RULE-ML, pages 113–129, 2005. [BK94] A.J. Bonner and M. Kifer. An overview of transaction logic. Theoretical Computer Science, 133:205–265, October 1994. [BKPR02] S. Basu, N. Kumar, L.R. Pokorny, and C.R. Ramakrishnan. Resource-constrained model checking of recursive programs. In TACAS, pages 236–250, 2002. [BMSU86] F. Banchilhon, D. Maier, Y. Sagiv, and J. Ullman. Magic sets and other strange ways to implement logic programs. In ACM Principles of Database Systems. ACM, 1986. [Bou97] D. Boulanger. Fine-grained goal-directed declarative analysis of logic programs. International Workshop on Verification, Model Checking and Abstract Interpretation, 1997.

Terrance Swift Topics in Logic Programming Implementation ReferencesIII

[BR91] C. Beeri and R. Ramakrishnan. On the power of magic. Journal of Logic Prog., 10(3):255–299, 1991.

[BRO07] J. Barata, L. Ribeiro, and M. Onori. Diagnosis on evolvable production systems. In IEEE Intl. Symp. on Industrial Electronics, 2007. [Cal04] M. Calejo. Interprolog: Towards a declrative embedding of logic programming in Java. In JELIA, pages 714–717, 2004. [CC77] P. Cousot and R. Cousot. Abstract interpretation: A unified lattice model for static analyses of programs by construction or approximation of fixpoints. In ACM Principles of Prog. Languages. ACM Press, 1977. [CC03] Vtor Santos Costa and James Cussens. Clp(bn): Constraint logic programming for probabilistic knowledge. In In Proceedings of the 19th Conference on Uncertainty in Artificial Intelligence (UAI03, pages 517–524. Morgan Kaufmann, 2003. [CDD+98] B. Cui, Y. Dong, X. Du, K. Kumar, C. R. Ramakrishnan, I. V. Ramakrishnan, A. Roychoudhury, S. Smolka, and D. S. Warren. Logic programming and model checking. In Prog. Langs: Implementations, Logics and Progs., pages 1–20, 1998. [CDS98] M. Codish, B. Demoen, and K. Sagonas. Semantics-Based Program Analysis for Logic-Based Languages using XSB. Springer International Journal of Software Tools for Technology Transfer, 2(1):29–45, November 1998.

Terrance Swift Topics in Logic Programming Implementation ReferencesIV

[CFJ03] H. Chen, T. Finin, and A. Joshi. Using OWL in a pervasive computing broker. In AAMAS Workshop on Ontologies in Open Agent Systems, pages 9–16, 2003. [CHH89] A. Ciepielwski, S. Haridi, and B. Hausman. Or-parallel Prolog on shared memory multiprocessors. Journal of Logic Prog., 7:125–147, 1989. [CKW93] W. Chen, M. Kifer, and D. S. Warren. HiLog: A foundation for higher-order logic programming. Journal of Logic Prog., 15(3):187–230, 1993.

[CP04] J.F. Castro and L. M. Pereira. Abductive validation of a power-grid diagnoser. In IEA/AIE, pages 838–847, 2004.

[CR09] J. Costa and R. Rocha. One table fits all. In Practical Applications of Declarative Languages, pages 195–208, 2009. [CS01] L.F. Castro and V. Santos Costa. Understanding memory management in prolog systems. In Intl. Conf. on Logic Prog., pages 11–26, 2001. [CS02] B. Cui and T. Swift. Preference logic grammars: Fixed-point semantics and application to data standardization. Artificial Intelligence, 138:117–147, 2002. [CSW] L. Castro, T. Swift, and D. S. Warren. XASP: Answer Set Programming with XSB and Smodels. http://xsb.sourceforge.net/packages/xasp.pdf.

Terrance Swift Topics in Logic Programming Implementation ReferencesV

[CSW99] B. Cui, T. Swift, and D. S. Warren. From tabling to transformation: Implementing non-ground residual programs. In International Workshop on Implementations of Declarative Languages, 1999. [CSW02] L.F. Castro, T. Swift, and D.S. Warren. Suspending and resuming computations in engines for SLG evaluation. In Practical Applications of Declarative Languages, pages 332–346, 2002. [CW96] W. Chen and D. S. Warren. Tabled Evaluation with Delaying for General Logic Programs. Journal of the ACM, 43(1):20–74, 1996.

[CW00] B. Cui and D. S. Warren. A system for tabled constraint logic programming. In Computational Logic, page 478492, 2000. [DHM07] W. Drabent, J. Henriksson, and J. Maluszy´nski. Hybrid reasoning with rules and constraints under well-founded semantics. In Web Reasoning and Rules, pages 348–357, 2007. [DJP+02] H. Davulcu, J. Jones, L.R. Pokorny, C. Rued, T. Swift, T. Vidrevich, and D.S. Warren. Ensuring consistency in self-reported data: A case study. In Seventh International Conference on Information Quality, pages 155–166, 2002. [DKRR98] H. Davulcu, M. Kifer, C.R. Ramakrishnan, and I.V Ramakishnan. Logic-based modeling and analysis of workflows. In ACM Principles of Database Systems, pages 25–33, 1998. [dlC93] E. Villemont de la Clergerie. Layer sharing: an improved structure-sharing framework. In Proc. of the 20th. Symposium on Principles of Programming Languages, pages 345–359, 1993.

Terrance Swift Topics in Logic Programming Implementation ReferencesVI

[DLP94] D. Dubois, J. Lang, and H. Prade. Possibilistic logic. In D. M. Gabbay, C. J. Hogger, and J. A. Robinson, editors, Handbook of logic in artificial intelligence and logic programming,vol. 3, pages 439–514. Oxford University Press, 1994. [DP01a] C. V. Dam´asioand L. M. Pereira. Monotonic and residuated logic programs. In ECSQARU, pages 748–759, 2001. [DP01b] D. Diaz and Codognet P. Design and implementation of the prolog system. Journal of Functional and Logic Prog., 13(4):451–490, 2001.

[DRS00] X. Du, C. R. Ramakrishnan, and S. A. Smolka. Tabled resolution + constraints: A recipe for model checking real-time systems. In Real-Time Systems Symp., pages 175–184, 2000. [DRSS96] Steven Dawson, C. R. Ramakrishnan, Steven Skiena, and Terrance Swift. Principles and practice of unification factoring. ACM Transactions on Programming Languages and Systems, 18(5):528–563, 1996.

[DRW96] S. Dawson, C. R. Ramakrishnan, and D. S. Warren. Practical program analysis using general purpose logic programming systems — a case study. In ACM PLDI, pages 117–126, May 1996. [DS98] B. Demoen and K. Sagonas. CAT: A copying approach to tabling. In Prog. Langs: Implementations, Logics and Progs., pages 21–35, 1998. [DS99] B. Demoen and K. Sagonas. CHAT: the Copy-Hybrid Approach to Tabling. In Practical Applications of Declarative Languages, pages 106–121, 1999.

Terrance Swift Topics in Logic Programming Implementation ReferencesVII

[DS01] Bart Demoen and Konstantinos Sagonas. Heap memory management in prolog with tabling: Principles and practice. Journal of Functional and Logic Prog., 2001(9), 2001.

[dSC06] A.F. de Silva and V. Santos Costa. The design of the yap compiler: An optimizaing compiler for logic programming languages. Journal of Universal Computer Science, 12(7):764–787, 2006.

[dSSR04] M. Pereira dos Santos Silva and J. Robin. SKDQL: A structured language to specify knowledge discovery processes and queries. In SBIA, pages 325–335, 2004. [Dun91] P. Dung. Negation as hypothesis: An abductive foundation for logic programming. In Intl. Conf. on Logic Prog., pages 1–17, 1991. [DYKR00] H. Davulcu, G. Yang, M. Kifer, and I.V. Ramakrishnan. Design and implementation of the physical layer in webbases: The XRover experience. In Computational Logic, pages 1094–1105, 2000. [Ear70] Jay Earley. An efficient context-free parsing algorithm. CACM, 13(2):94–102, 1970.

[EH] E. A. Emerson and J. Halpern. Sometimes and not never revisited: On branching vs linear time temporal logics. Journal of the ACM, 33(1):151–178.

[FHSW95] J. Freire, R. Hu, T. Swift, and D. S. Warren. Parallelizing tabled evaluation. In Prog. Langs: Implementations, Logics and Progs., pages 115–132, 1995.

Terrance Swift Topics in Logic Programming Implementation ReferencesVIII

[Fit91] M. Fitting. Bilattices and the semantics of logic programming. Journal of Logic Prog., 11:91–116, 1991. [Fru97] Thom Fruhwirth. Constraint handling rules. Journal of Logic Prog., 37(1-3), 1997.

[FSW97] J. Freire, T. Swift, and D. S. Warren. Treating I/O seriously: Resolution reconsidered for disk. In Intl. Conf. on Logic Prog., pages 198–212, 1997. [FSW98] J. Freire, T. Swift, and D. S. Warren. Beyond depth-first: Improving tabled logic programs through alternative scheduling strategies. Journal of Functional and Logic Prog., 1998(3):243–268, 1998.

[GCH09] P. Guzman, M. Carro, and M. Hermenegildo. Towards a complete scheme for tabled execution based on program transformation. In Practical Applications of Declarative Languages, pages 212–226, 2009. [GG01] H. Guo and G. Gupta. A simple scheme for implementing tabled logic programming systems based on dynamic reordering of alternates. In Intl. Conf. on Logic Prog., pages 181–196, 2001. [GJM95] K. Govindarajan, B. Jayaraman, and S. Mantha. Preference logic programming. In Intl. Conf. on Logic Prog., pages 731–746, 1995. [GL90] M. Gelfond and V. Lifshitz. Logic programs with classical negation. In Intl. Conf. on Logic Prog., pages 579–597. MIT Press, 1990.

Terrance Swift Topics in Logic Programming Implementation ReferencesIX

[Gro97] B. Grosof. Prioritized conflict handling for logic programs. In Intl. Logic Prog. Symposium, pages 197–213, 1997. [Gro09] B. Grosof. SILK: Semantic rules take the next big step in power. http://silk.semwebcentral.org, 2009.

[GST+00] J. Gartner, T. Swift, A. Tien, L. M. Pereira, and C. Dam´asio. Psychiatric diagnosis from the viewpoint of computational logic. In Computational Logic, pages 1362–1376, 2000. [HR89] M. Hermenegildo and F. Rossi. On the correctness and efficiency of independant and-parallelism in logic programs. In N. Amer. Conference on Logic Programming., 1989. [HtCG] M. Hermenehildo and the CLIP Group. The lpdoc documentation generator. Technical report, School of Computer Science, Technical University of Madrid. Available from http://www.clip.dia.fi.upm.es.

[ISO95] ISO working group JTC1/SC22. Prolog international standard iso-iec 13211-1. Technical report, International Standards Organization, 1995. [JGM98] B. Jayaraman, K. Govindarajan, and S. Mantha. Preference logic grammars. Computer Languages, 24, 1998. 179-196.

Terrance Swift Topics in Logic Programming Implementation ReferencesX

[JRRR99] E. Johnson, C.R. Ramakrishnan, I.V. Ramakrishnan, and P. Rao. A space-efficient engine for subsumption based tabled evaluation of logic programs. In Symp. on Funct. and Log. Prog., pages 284–300, 1999. [JS98] G. Janssens and K. Sagonas. On the use of tabling for abstract interpretation: An experiment with abstract equation systems. In Tabling in Parsing and Deduction, pages 118–126, 1998. [KF04] L. Kagal and T. Finin. Modeling communicative behavior using permissions and obligations. In International Workshop on Agent Communication, pages 120–133, 2004. [KK93] T. Kanamori and T. Kawamura. Abstract interpretation based on oldt resolution. Journal of Logic Programming, 15:1–30, 1993. [Koz83] D. Kozen. Results on the propositional mu-calculus. Theoretical Computer Science, 27(333-354), 1983.

[KS92] M. Kifer and V. S. Subrahmanian. Theory of generalized annotated logic programming and its applications. Journal of Logic Prog., 12(4):335–368, 1992.

[KT02] L. Kalantari and E. Ternovska. A model checker for verifying ConGolog programs. In Eighteenth National Conference on Artificial intelligence, pages 953–954, 2002. [LCK01] I. Letia, F. Craciun, and Z. Kpe. Norms for DLP agents working in a warehouse scenario. In IEA/AIE, pages 728–733, 2001.

Terrance Swift Topics in Logic Programming Implementation ReferencesXI

[LFWK09] S. Liang, P. Fodor, H. Wan, and M. Kifer. OpenRuleBench: An analysis of the performance of rule engines. In WWW: Semantic Data Track, pages 601–608, 2009. [LGTH05] A. Lattner, J. Gehrke, I. Timm, and O. Herzog. A knowledge-based approach to behavior decision in intelligent vehicles. In IEEE Intelligent Vehicles Symp., pages 466–471, 2005. [LO87] T. Lindholm and R. A. O’Keefe. Efficient implementation of a defensible semantics for Prolog. In Proc of the 4th ICLP, pages 21–40, 1987. [LPB02] J. Li, A. Pease, and C. Barbee. Experimenting with ACSC semantic search. Technical report, Teknowlege Corporation, 2002. [LRP99] E. Lamma, F. Riguzzi, and L. M. Pereira. Learning three-valued logic programs. In International Workshop on Inductive Logic Programming, pages 30–35, 1999. [LRS98] X. Liu, C. R. Ramakrishnan, and S. Smolka. Fully local and efficient evaluation of alternating fixed points. In TACAS 98: Tools and Algorithms for Construction and Analysis of Systems, pages 5–19, 1998. [LTLH05] A. Lattner, I. Timm, M. Lorenz, and O. Herzog. Knowledge-based risk assessment for intelligent vehicles. In IEEE Conference on Integration of Knowledge Intensive Multi-Agent Systems, pages 191–196, 2005. [LWFS95] R. Larson, D. S. Warren, J. Freire, and K. Sagonas. Syntactica, Symantica. MIT Press, Cambridge Ma., 1995.

Terrance Swift Topics in Logic Programming Implementation ReferencesXII

[Man89] U. Manber. Introduction to Algorithms: A Creative Approach. Addison-Wesley, Reading Ma., 1989. [Mar07] R. Marques. Concurrent Tabling: Algorithms and Implementation. PhD thesis, Universidade Nova de Lisboa, 2007. [MCH04] J. Morales, M. Carro, and M. Hermenegildo. Improved compilation of prolog to c using moded types and determinism information. In Practical Applications of Declarative Languages, pages 86–103, 2004. [Mei96] I. Meiri. Combining qualitative and quantitative constraints in temporal reasoning. Artificial Intelligence, 87(1/2):343–385, 1996.

[MGR04] R. Muller, U. Greiner, and E. Rahm. Agentwork: a workflow system supporting rule-based workflow adaptation. IEEE Data and Knowledge Engineering, 51(2):223–256, 2004.

[Mil89] R. Milner. Communication and Concurrency. Prentice-Hall, New York, 1989. [Mou] Paulo Moura. LogTalk User Manual. Available online from http://logtalk.org. [MPW92a] R. Milner, J. Parrow, and D. Walker. A calculus of mobile processes, I. Information and Computation, 100(1):1–40, 1992.

Terrance Swift Topics in Logic Programming Implementation ReferencesXIII

[MPW92b] R. Milner, J. Parrow, and D. Walker. A calculus of mobile processes, II. Information and Computation, 100(1):41–77, 1992.

[MRRV00] M. Mukund, C. R. Ramakrishnan, I. V. Ramakrishnan, and R. Verma. Symbolic bisimulation using tabled constraint logic programming. In Tabling in Parsing and Deduction, pages 166–180, 2000. [MS08] R. Marques and T. Swift. Concurrent and local evaluation of normal programs. In Intl. Conf. on Logic Prog., pages 206–222, 2008. [Mun04] C. Mungall. Open bio-ontology language. In 7th Annual Bio-Ontologies Meeting, 2004. [Oqu04] F. Oquendo. Formally describing dynamic software architectures with π-ADL. World Scientific and Engineering Transactions on Systems, 3(8):673–679, 2004.

[PAE98] B.J. Peterson, W.A. Andersen, and J. Engel. Knowledge Bus: Generating application-focused databases from large ontologies. In KRDB-98, 1998. [PGP01] C.M. Papaterpos, N.P. Georgantis, and T.S. Papatheodorou. An ontology for modeling ill-structured domains in intelligent educational systems. In IEEE International Conference on Advanced Learning Technologies, pages 41–42, 2001. [PP88] H. Przymusinska and T. Przymusinski. Weakly perfect model semantics for logic programs. In Joint Intl. Conf./Symposium on Logic Prog., pages 1106–1123, 1988.

Terrance Swift Topics in Logic Programming Implementation References XIV

[PP05] L. M. Pereira and A. M. Pinto. Revised stable models - a semantics for logic programs. In Procs. 12th Portuguese Intl.Conf. on Artificial Intelligence, pages 29–42, 2005. [PR04] L.R. Pokorny and C.R. Ramakrishnan. Modeling and verification of distributed autonomous agents using logic programming. In Second International Workshop on Declarative Agent Languages and Technologies, pages 148–165, 2004. [PRR02] G. Pemmasani, C. R. Ramakrishnan, and I. V. Ramakrishnan. Efficient model checking of real time systems using tabled logic programming and constraints. In Intl. Conf. on Logic Prog., pages 100–114, 2002. [Prz88] T.C. Przymusinski. On the declarative semantics of deductive databases and logic programming. In J. Minker, editor, Foundations of Deductive Databases and Logic Programming, pages 193–216. Morgan Kaufmann, 1988. [Prz89a] T. Przymusinski. Every logic program has a natural stratification and an iterated least fixed point model. In ACM Principles of Database Systems, pages 11–21. ACM Press, 1989. [Prz89b] T.C. Przymusinski. The well-founded semantics coincides with the three-valued stable semantics. Fundamenta Informaticae, 1989. [PV07] L. M. Pereira and R. D. Viegas. Architectural design via declarative programming. In International Conference on Enterprise Information Systems, pages 363–369, 2007. [RL98] V. Rocio and J. Lopes. Partial parsing, deduction and tabling. In Tabling in Parsing and Deduction, 1998.

Terrance Swift Topics in Logic Programming Implementation ReferencesXV

[Ros94] K.A. Ross. Modular stratification and magic sets for datalog programs with negation. In Journal of the ACM, pages 1216–1266, 1994. [RRR+97] Y. S. Ramakrishna, C. R. Ramakrishnan, I. V. Ramakrishnan, S. Smolka, T. Swift, and D. S. Warren. Efficient model checking using tabled resolution. In Proceedings on the Conf. on Automated Verification, pages 143–154, 1997. [RRS97] I. V. Ramakrishnan, A. Roychoudhury, and T. Swift. A rule-based data standardizer for enterprise data bases. In Practical Applications of Prolog, pages 255–270, 1997. [RRS+99] I. V. Ramakrishnan, P. Rao, K. Sagonas, T. Swift, and D. S. Warren. Efficient access mechanisms for tabled logic programs. Journal of Logic Prog., 38(1):31–55, 1999.

[RRS+00] C.R. Ramakrishnan, I.V Ramakrishnan, S. Smolka, Y. Dong, X. Du, A. Roychoudhury, and V. Venkatakrishnan. XMC: A logic-programming-based verification toolset. In Proceedings on the Conf. on Automated Verification, pages 576–590, 2000. [RS10] F. Riguzzi and T. Swift. Tabling and answer subsumption for reasoning on logic programs with annotated disjunctions. In Intl. Conf. on Logic Prog., 2010. Available at www.cs.sunysb.edu/~tswift/papers. [RS11] F. Riguzzi and T. Swift. The PITA system: Tabling and answer subsumption for reasoning under uncertainty. 11(4-5):433–449, 2011.

Terrance Swift Topics in Logic Programming Implementation References XVI

[RS12] F. Riguzzi and T. Swift. Well-definedness and efficient inference for probabilistic logic programming under the distribution semantics. Theory and Practice of Logic Prog., 2012. To appear. Available at www.cs.sunysb.edu/~tswift/papers. [RSC02] R. Rocha, F. Silva, and V. Santos Costa. Achieving scalability in parallel tabled logic programs. In IPDPS, 2002. [RSC04a] R. Rocha, F. Silva, and V. S. Costa. Concurrent table access in parallel tabled logic programms. In EUROPAR, 2004. [RSC04b] R. Rocha, F. Silva, and V. S. Costa. On applying or-parallelism and tabling to logic programs. Theory and Practice of Logic Prog., 4(6), 2004.

[RSC05] R. Rocha, F. Silva, and V. Santos Costa. Dynamic mixed-strategy evaluation of tabled logic programs. In Intl. Conf. on Logic Prog., page 250264, 2005. [Sah06] D. Saha. Incremental Evaluation of Tabled Logic Programs. PhD thesis, SUNY Stony Brook, 2006. [SC99] V´ıtor Santos Costa. Optimising emulation for prolog. In Proceedings of PPDP’99, volume 1702 of LNCS, pages 261–267. Springer-Verlag, September 1999.

Terrance Swift Topics in Logic Programming Implementation References XVII

[SP06] P. Santana and L. M. Pereira. Emergence of cooperation through mutual preference revision. In IEA/AIE, pages 81–90, 2006.

[SPP09] T. Swift, A.M. Pinto, and L. M. Pereira. Incremental answer completion. In Intl. Conf. on Logic Prog., pages 519–524, 2009. [SR93] S. Sudarshan and R. Ramakrishnan. Optimizations of bottom-up evaluation with non-ground terms. In Proc. of the Symposium on Logic Programming, 1993. [SR05] D. Saha and C.R. Ramakrishnan. Incemental and demand-driven points-to analysis using logic programming. In Principles and Practice of Decl. Prog., pages 117–128, 2005. [SS98] K. Sagonas and T. Swift. An abstract machine for tabled execution of fixed-order stratified logic programs. ACM TOPLAS, 20(3):586 – 635, May 1998.

[SS05] B. Sarna-Starosta. Constraint-based Analysis of Security Protocols. PhD thesis, SUNY Stony Brook, 2005. [SS06] Z. Somogyi and K. Sagonas. Tabling in Mercury: Design and implementation. In Practical Applications of Declarative Languages, pages 150–164, 2006. [SSW00a] K. Sagonas, T. Swift, and D. S. Warren. An abstract machine for efficiently computing queries to well-founded models. Journal of Logic Prog., 45(1-3):1–41, 2000.

Terrance Swift Topics in Logic Programming Implementation References XVIII

[SSW00b] K. Sagonas, T. Swift, and D. S. Warren. The limits of fixed-order computation. Theoretical Computer Science, 254(1-2):465–499, 2000.

[Sti] C. Stirling. Modal and temporal logics. In Handbook of Logic in Computer Science, pages 477–562. Clarendon Press. [STI+06] C. Shankar, V. Talwar, S. Iyer, Y. Chen, D. Milojicic, and R. Campbell. Specification-enhanced policies for automated management of changes in it systems. In 20th Large Installation Systems Administration Conference, pages 101–115, 2006. [SW95] K. Sagonas and D. S. Warren. Efficient execution of HiLog in WAM-based Prolog implementations. In Intl. Conf. on Logic Prog., 1995. To Appear. [SW03] T. Swift and D. S. Warren. Coherent Description Framework, 2003. Available via xsb.sourceforge.net. [SW10] T. Swift and D.S. Warren. Tabling with answer subsumption: Implementation, applications and performance. In JELIA, pages 300–312, 2010. [SWD03] Tom Schrijvers, S Warren, D., and Bart Demoen. CHR for XSB. In Proceedings of CICLOPS 2003: Colloquium on Implementation of Constraint and LOgic Programming Systems, pages 7–20, 2003.

Terrance Swift Topics in Logic Programming Implementation References XIX

[Swi99a] T. Swift. A new formulation of tabled resolution with delay. In Progress in Art. Intel., pages 163–177, 1999. [Swi99b] T. Swift. Tabling for non-monotonic programming. Annals of Mathematics and Artificial Intelligence, 25(3-4):201–240, 1999.

[Swi04] T. Swift. Deduction in ontologies via answer set programming. In Intl. Conf. on Logic Prog. and Non-Monotonic Reasoning, pages 275–289, 2004. [Swi09] T. Swift. An engine for efficiently computing (sub-)models. In Intl. Conf. on Logic Prog., pages 514–518, 2009. [SZKI10] Taisuke Sato, Neng-Fa Zhou, Yoshitaka Kameya, and Yusuke Izumi. PRISM Users Manual (Version 2.0), 2010. http://sato-www.cs.titech.ac.jp/prism/download/prism20.pdf. [Tay01] A. Taylor. High-Performance Prolog Implementation. PhD thesis, University of Sydney, 2001. [TDK03] H. Tangmunarunkit, S. Decker, and C. Kesselman. Ontology-based resource matching in the grid — the grid meets the semantic web. In Intl. Semantic Web Conf., pages 706–721, 2003. [TS86] H. Tamaki and T. Sato. OLDT resolution with tabulation. In Intl. Conf. on Logic Prog., pages 84–98, 1986.

Terrance Swift Topics in Logic Programming Implementation ReferencesXX

[van86] M. van Emden. Quantitative deduction and its fixpoint theory. Journal of Logic Prog., 4:37–53, 1986. [van92] P. van Roy. High performance logic programming with the aquarius Prolog compiler. IEEE Computer, 39(1):54–68, 1992.

[Vie89] L. Vieille. Recursive query processing: The power of logic. Theoretical Computer Science, 69:1–53, 1989. [VRK+91] J. Vaghani, K. Ramamohanorao, D. Kemp, Z. Somogyi, and P. Stuckey. Design overview of the Aditi deductive database system. In Seventh International Conference on Data Engineering, pages 240–247, 1991. [vRS91] A. van Gelder, K.A. Ross, and J.S. Schlipf. Unfounded sets and well-founded semantics for general logic programs. Journal of the ACM, 38(3):620–650, 1991.

[VVB04] J. Vennekens, S. Verbaeten, and M. Bruynooghe. Logic programs with annotated disjunctions. In Intl. Conf. on Logic Prog., pages 195–209, 2004. [War87] D.H.D. Warren. The SRI model for or-parallel execution of Prolog — abstract design and implementation. In Proc of the 1987 Symposium on Logic Programming, pages 92–102, 1987. [WGK+09] H. Wan, B. Grosof, M. Kifer, P. Fodor, and S. Liang. Logic programming with defaults and argumentation theories. In Intl. Conf. on Logic Prog., pages 432–448, 2009.

Terrance Swift Topics in Logic Programming Implementation References XXI

[YKWZ12] G. Yang, M. Kifer, H. Wan, and C. Zhao. FLORA-2: User’s Manual Version 0.97, 2012. [YKZ03] G. Yang, M. Kifer, and C. Zhao. FLORA-2: A rule-based knowledge representation and inference infrastructure for the Semantic Web. In ODBASE-2003, pages 671–688, 2003. [ZFC04] Y. Zou, T. Finin, and H. Chen. F-OWL: An inference engine for the semantic web. In Formal Approaches to Agent-Based Systems, pages 238–248, 2004. [ZFD+03] Y. Zou, T. Finin, L. Ding, H. Chen, and R. Pan. Using semantic web technology in multi-agent systems: a case study in the TAGA trading agent environment. In Proceedings of the 5th international conference on electronic commerce, pages 95 – 101, 2003. [ZSS04] N. Zhou, Y. Shen, and T. Sato. Semi-naive evaluation in linear tabling. In Intl Conf. on Principles and Practice of Declarative Programming, 2004. [ZSYY01] N. Zhou, Y. Shen, L. Yuan, and J. You. Implementation of a linear tabling mechanism. Journal of Functional and Logic Prog., 2001(10), 2001.

Terrance Swift Topics in Logic Programming Implementation