Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/HarvardPL/AbcDatalog/llms.txt

Use this file to discover all available pages before exploring further.

DatalogExecutor provides an event-driven model for Datalog evaluation that differs from the batch DatalogEngine interface. Instead of computing all facts up front, an executor allows you to register listeners that fire whenever a new fact matching a given predicate is derived, and to inject new EDB facts into the running evaluation at any time. This is useful for streaming or reactive scenarios where input data arrives incrementally. DatalogParallelExecutor is the concrete implementation. It runs the Datalog evaluation concurrently in separate threads using ExtensibleBottomUpEvalManager under the hood.

Lifecycle

An executor must be used in the following order:
  1. initialize — load the program and declare which EDB relations are extensible
  2. registerListener — attach callbacks (must happen before start)
  3. start — begin evaluation
  4. addFactAsynchronously — feed new facts during evaluation
  5. shutdown — terminate the executor

Methods

initialize

void initialize(Set<Clause> program, Set<PredicateSym> extendibleEdbPreds)
    throws DatalogValidationException
Loads the Datalog program and specifies which EDB relations may receive new facts during evaluation via addFactAsynchronously. Should be called exactly once.
program
Set<Clause>
required
The program: EDB facts (body-less clauses) and IDB rules.
extendibleEdbPreds
Set<PredicateSym>
required
Predicate symbols whose extensions may grow after evaluation starts. Only facts whose predicate is in this set may be added via addFactAsynchronously.

start

void start()
Begins the Datalog evaluation. Throws IllegalStateException if the executor has not been initialized or if evaluation has already been started.

addFactAsynchronously

void addFactAsynchronously(PositiveAtom edbFact)
Injects a new ground EDB fact into the running evaluation. The fact is processed asynchronously; derived consequences may arrive via registered listeners at any point after this call returns.
edbFact
PositiveAtom
required
A ground atom (no variables) belonging to one of the extendible EDB predicates declared in initialize.
Throws IllegalArgumentException if the atom is not ground or if its predicate was not declared as extendible in initialize. Throws IllegalStateException if the executor has not been initialized.

registerListener

void registerListener(PredicateSym p, DatalogListener listener)
Registers a callback to be invoked each time a new fact with predicate symbol p is derived during evaluation. The listener may be called from an arbitrary thread.
p
PredicateSym
required
The predicate symbol to watch.
listener
DatalogListener
required
The callback to invoke. Must be registered before start() is called.
Listeners are invoked from arbitrary evaluation threads. They must not block and must be thread-safe. Performing long-running work or acquiring locks inside a listener risks deadlocking or stalling the evaluation.

shutdown

void shutdown()
Terminates the executor and releases its internal thread pool. The executor cannot be reused after shutdown is called.

DatalogListener

DatalogListener is a single-method interface with a single method:
void newFactDerived(PositiveAtom fact)
fact
PositiveAtom
required
The newly derived ground fact. fact.isGround() is guaranteed to return true.
Because DatalogListener has exactly one abstract method, it can be provided as a lambda expression.

DatalogParallelExecutor

DatalogParallelExecutor is the concrete DatalogExecutor implementation:
DatalogParallelExecutor ex = new DatalogParallelExecutor();
It implements all five methods above and executes evaluation work in a background thread pool managed by ExtensibleBottomUpEvalManager.

Code example

The following is adapted from ExecutorExample.java:
import edu.harvard.seas.pl.abcdatalog.ast.Clause;
import edu.harvard.seas.pl.abcdatalog.ast.PositiveAtom;
import edu.harvard.seas.pl.abcdatalog.ast.PredicateSym;
import edu.harvard.seas.pl.abcdatalog.executor.DatalogParallelExecutor;
import edu.harvard.seas.pl.abcdatalog.parser.DatalogParser;
import edu.harvard.seas.pl.abcdatalog.parser.DatalogTokenizer;
import java.io.StringReader;
import java.util.Collections;
import java.util.Set;

String program =
    "edge(0,1). edge(1,2). tc(X,Y) :- edge(X,Y)."
    + "tc(X,Y) :- edge(X,Z), tc(Z,Y). cycle :- tc(X,X).";

DatalogTokenizer t = new DatalogTokenizer(new StringReader(program));
Set<Clause> ast = DatalogParser.parseProgram(t);

PredicateSym edge  = PredicateSym.create("edge",  2);
PredicateSym tc    = PredicateSym.create("tc",    2);
PredicateSym cycle = PredicateSym.create("cycle", 0);

// 1. Initialize
DatalogParallelExecutor ex = new DatalogParallelExecutor();
ex.initialize(ast, Collections.singleton(edge));

// 2. Register listeners before start()
ex.registerListener(tc,    fact -> System.out.println("Derived: " + fact));
ex.registerListener(cycle, fact -> System.out.println("*** Cycle detected. ***"));

// 3. Start evaluation
ex.start();

// 4. Feed new facts asynchronously
String newFacts = "edge(2,3). edge(3,4). edge(4,0).";
DatalogTokenizer ft = new DatalogTokenizer(new StringReader(newFacts));
while (ft.hasNext()) {
    ex.addFactAsynchronously(DatalogParser.parseClauseAsPositiveAtom(ft));
}

ex.shutdown();

Build docs developers (and LLMs) love