Epilog Compiler

This document is the beginning of a reference manual for the Javascript version of the Epilog compiler. Very sketchy at the moment. We will be adding more material in incremental fashion.

The Javascript compiler for Epilog converts Epilog rule sets into Javascript subroutines. In writing code, a Javascript programmer can use these relation-specific subroutines in place of the general subroutines defined in the interpreter. The answers will be the same, but the runtime in many cases is likely to be substantially reduced.

The easiest way to use the compiler is to go the the Epilog website, click on Compiler, paste your rules into the Rules window, press the Compile button, and copy the resulting subroutines out of the Javascript window.

The compiler generates two groupings of subroutines for each relation in the given rule set - two general subroutines and a collection of specialized subroutines. Each grouping includes both singular and plural subroutines (in analogy with compfindx and compfinds). Each singular subroutine returns a single factoid that satisfies the query supplied as argument; each plural subroutine return lists of all factoids that satisfy the query.

The two general subroutines work for arbitrary combinations of arguments - symbols, distinct or repeated variables, ground compound expressions, and compound expressions containing distinct or repeated variables.

The specialized subroutines work only for specific combinations of arguments, e.g. all ground expressions, two ground expressions, one ground expression and one variable, one variable and one ground expression, two unrelated variables, and so forth. (The compiler uses this information to produce code that is significantly faster than would be otherwise possible.) Specialized subroutines for all bound arguments return booleans. Specialized subroutines for cases with just one free argument return values of that argument. Specialized subroutines with more than one free argument return ground factoids.

The subroutines for each relation are named by the addition of varying numbers of $ characters to the name of the relation, together with combinations of the letters b and f to denote bound and free arguments.

The singular general subroutine for relation r is named $r$, and the plural general subroutine is named $$r$$.

The singular subroutine for a binary relation r with both arguments bound $r$bb$, and there is no plural version (as there can be at most one answer). The singular subroutine for a binary relation r with first argument bound and second argument free $r$bf$, and the plural version is named $$r$bf$$. The singular subroutine for a binary relation r with first argument free and second argument bound $r$fb$, and the plural version is named $$r$fb$$. The singular subroutine for a binary relation r with both arguments free is $r$ff$, and the plural version is named $$r$ff$$.

As an example, consider the rule shown below. The relation goal is defined in terms of the unary relation p and binary relation q.

goal(X,Y) :- p(X) & q(X,Y)

The general subroutines produced for this ruleset are shown below. Note that there is one singular and one plural subroutine.

function $goal$ (query,al,facts,rules) {var answer = false; {var head = ['goal','X','Y']; var sub1 = ['p','X']; var sub2 = ['q','X','Y']; var bl = {}; var ol = []; if (vnify(query,al,head,bl,ol)) {{var l1 = $$p$$(sub1,bl,facts,rules); for (var i1=0; i1<l1.length; i1++) {var ol1 = []; maatchify(sub1,bl,l1[i1],bl,ol1); {var l2 = $q$(sub2,bl,facts,rules); if (l2) {var answer = ['goal',l1[i1][1],l2[2]];};}; backup(ol1);};}; backup(ol); if (answer) return answer;};}; return false} function $$goal$$ (query,al,facts,rules) {var answers = []; {var head = ['goal','X','Y']; var sub1 = ['p','X']; var sub2 = ['q','X','Y']; var bl = {}; var ol = []; if (vnify(query,al,head,bl,ol)) {{var l1 = $$p$$(sub1,bl,facts,rules); for (var i1=0; i1<l1.length; i1++) {var ol1 = []; maatchify(sub1,bl,l1[i1],bl,ol1); {var l2 = $$q$$(sub2,bl,facts,rules); for (var i2=0; i2<l2.length; i2++) {var ol2 = []; maatchify(sub2,bl,l2[i2],bl,ol2); {answers.push(['goal',l1[i1][1],l2[i2][2]]);}; backup(ol2);};}; backup(ol1);};}; backup(ol);};}; return answers}

See below for the special subroutines produced for our ruleset. There are four singular subroutines and three plural subroutines (for all but the case of ground inputs).

function $goal$bb$ (x1,x2,facts,rules) {if (and) if ($p$b$(x1,facts,rules)) return $q$bb$(x1,x2,facts,rules); return false} function $goal$bf$ (x1,facts,rules) {if (true) if ($p$b$(x1,facts,rules)) {var l2 = $$q$bf$$(x1,facts,rules); for (var i2=0; i2<l2.length; i2++) return l2[i2];}; return false} function $goal$fb$ (x2,facts,rules) {if (true) {var l1 = $$p$f$$(facts,rules); for (var i1=0; i1<l1.length; i1++) if ($q$bb$(l1[i1][1],x2,facts,rules)) return l1[i1][1];}; return false} function $goal$ff$ (facts,rules) {{var l1 = $$p$f$$(facts,rules); for (var i1=0; i1<l1.length; i1++) {var l2 = $$q$bf$$(l1[i1][1],facts,rules); for (var i2=0; i2<l2.length; i2++) return ['goal',l1[i1][1],l2[i2]];};}; return false} function $$goal$bf$$ (x1,facts,rules) {var answers = []; if (true) if ($p$b$(x1,facts,rules)) {var l2 = $$q$bf$$(x1,facts,rules); for (var i2=0; i2<l2.length; i2++) answers.push(l2[i2]);}; return answers} function $$goal$fb$$ (x2,facts,rules) {var answers = []; if (true) {var l1 = $$p$f$$(facts,rules); for (var i1=0; i1<l1.length; i1++) if ($q$bb$(l1[i1][1],x2,facts,rules)) answers.push(l1[i1][1]);}; return answers} function $$goal$ff$$ (facts,rules) {var answers = []; {var l1 = $$p$f$$(facts,rules); for (var i1=0; i1<l1.length; i1++) {var l2 = $$q$bf$$(l1[i1][1],facts,rules); for (var i2=0; i2<l2.length; i2++) answers.push(['goal',l1[i1][1],l2[i2]]);};}; return answers}

The compiler also generates analogous subroutines for efficiently accessing subroutines for base relations. See below for the subroutines generated in this case.

function $p$ (query,al,facts,rules) {return dataanswerx(query,al,facts,rules)} function $$p$$ (query,al,facts,rules) {return dataanswers(query,al,facts,rules)} function $q$ (query,al,facts,rules) {return dataanswerx(query,al,facts,rules)} function $$q$$ (query,al,facts,rules) {return dataanswers(query,al,facts,rules)} function $p$b$ (x1,facts) {{var data = indexees('p',facts); var dum = fullindexps(x1,facts); if (dum && dum.length<data.length) {var data = dum;}; for (var i=0; i<data.length; i++) if (equalp(data[i][1],x1)) return true; return false;}} function $p$f$ (facts,rules) {var data = indexees('p',facts); if (data.length>0) return data[0]; return false} function $$p$f$$ (facts,rules) {return indexees('p',facts).map(x => x[1])} function $q$bb$ (x1,x2,facts) {{var data = indexees('q',facts); var dum = fullindexps(x1,facts); if (dum && dum.length<data.length) {var data = dum;}; var dum = fullindexps(x2,facts); if (dum && dum.length<data.length) {var data = dum;}; for (var i=0; i<data.length; i++) if (equalp(data[i][1],x1) && equalp(data[i][2],x2)) return true; return false;}} function $$q$bf$$ (x1,facts,rules) {var data = indexees('q',facts); var dum = fullindexps(x1,facts); if (dum && dum.length<data.length) {var data = dum;}; var answers = []; for (var i=0; i<data.length; i++) if (equalp(data[i][1],x1)) return data[i][2]; return false} function $$q$fb$$ (x2,facts,rules) {var data = indexees('q',facts); var dum = fullindexps(x2,facts); if (dum && dum.length<data.length) {var data = dum;}; var answers = []; for (var i=0; i<data.length; i++) if (equalp(data[i][2],x2)) return data[i][1]; return false} function $q$ff$ (facts,rules) {var data = indexees('q',facts); if (data.length>0) return data[0][1]; return false} function $$q$bf$$ (x1,facts,rules) {var data = indexees('q',facts); var dum = fullindexps(x1,facts); if (dum && dum.length<data.length) {var data = dum;}; var answers = []; for (var i=0; i<data.length; i++) if (equalp(data[i][1],x1)) answers.push(data[i][2]); return answers} function $$q$fb$$ (x2,facts,rules) {var data = indexees('q',facts); var dum = fullindexps(x2,facts); if (dum && dum.length<data.length) {var data = dum;}; var answers = []; for (var i=0; i<data.length; i++) if (equalp(data[i][2],x2)) answers.push(data[i][1]); return answers} function $$q$ff$$ (facts,rules) {return indexees('q',facts)}

At present, the compiler generates specialized subroutines for all combinations of arguments for 0-ary, unary, and binary relations (except that it does not generate a plural subroutine for the case when all arguments are bound). For all other relations, it generates only general subroutines.