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.

A Clause is the fundamental unit of a Datalog program. It pairs a Head with a (possibly empty) list of Premise objects that form the body. The standard interpretation is that the head holds whenever every premise in the body holds. A clause with an empty body is a ground fact; a clause with one or more body premises is a rule. DatalogParser.parseProgram returns a Set<Clause>, and this set is passed directly to DatalogEngine.init or DatalogValidator.validate.

Constructor

public Clause(Head head, List<Premise> body)
head
Head
required
The head of the clause. In practice this is always a PositiveAtom.
body
List<Premise>
required
The list of body premises. Pass Collections.emptyList() to create a fact. The list is stored as-is and is accessible via getBody().

Methods

getHead

public Head getHead()
result
Head
The head of the clause. Cast to PositiveAtom when you know the clause was produced by the parser or built with a PositiveAtom head.

getBody

public List<Premise> getBody()
result
List<Premise>
The list of body premises in declaration order. An empty list means the clause is a fact. Premises may be PositiveAtom, NegatedAtom, BinaryUnifier, or BinaryDisunifier instances.

Facts vs. rules

ConditionMeaning
clause.getBody().isEmpty()The clause is a ground EDB fact.
!clause.getBody().isEmpty()The clause is a rule used to derive new facts.
DatalogValidator uses this distinction to separate EDB initial facts from IDB rules when building an UnstratifiedProgram.

Code example: parsing and inspecting clauses

import edu.harvard.seas.pl.abcdatalog.ast.Clause;
import edu.harvard.seas.pl.abcdatalog.ast.Head;
import edu.harvard.seas.pl.abcdatalog.ast.Premise;
import edu.harvard.seas.pl.abcdatalog.ast.PositiveAtom;
import edu.harvard.seas.pl.abcdatalog.parser.DatalogParser;
import edu.harvard.seas.pl.abcdatalog.parser.DatalogTokenizer;
import java.io.StringReader;
import java.util.Set;

String src = "edge(a,b). edge(b,c). tc(X,Y) :- edge(X,Y). tc(X,Y) :- tc(X,Z), tc(Z,Y).";
DatalogTokenizer t = new DatalogTokenizer(new StringReader(src));
Set<Clause> clauses = DatalogParser.parseProgram(t);

for (Clause c : clauses) {
    Head head = c.getHead();
    List<Premise> body = c.getBody();
    if (body.isEmpty()) {
        System.out.println("Fact: " + head);
    } else {
        System.out.println("Rule with " + body.size() + " premise(s): " + c);
    }
}

Building a clause programmatically

import edu.harvard.seas.pl.abcdatalog.ast.*;
import java.util.Arrays;
import java.util.Collections;

// Fact: edge(a, b).
PredicateSym edgePred = PredicateSym.create("edge", 2);
PositiveAtom factHead = PositiveAtom.create(edgePred,
    new Term[]{Constant.create("a"), Constant.create("b")});
Clause fact = new Clause(factHead, Collections.emptyList());

// Rule: tc(X, Y) :- edge(X, Y).
PredicateSym tcPred = PredicateSym.create("tc", 2);
Term x = Variable.create("X"), y = Variable.create("Y");
PositiveAtom ruleHead = PositiveAtom.create(tcPred, new Term[]{x, y});
PositiveAtom bodyAtom = PositiveAtom.create(edgePred, new Term[]{x, y});
Clause rule = new Clause(ruleHead, Arrays.asList(bodyAtom));
Programmatically constructed clauses are not validated until they are passed to DatalogEngine.init or DatalogValidator.validate. Safety violations (unbound head variables) and unsupported premise types will be detected at that point.

Build docs developers (and LLMs) love