Lattice Datalog — When and Why

The Lattice Datalog reference documents every function and GUC. This page answers a different question: should you reach for a lattice at all? Most users never need one. This page helps you decide.


The short answer

Use a lattice when you need to propagate a value along a graph edge — not just whether a node is reachable, but how much something is worth at that node — and the propagation is recursive.

If your rules are not recursive, standard Datalog aggregates (COUNT, SUM, AVG over strata) are simpler.


A concrete intuition

Standard Datalog asks: can you get from A to B?

Lattice Datalog asks: what is the best way to get from A to B?

The same graph, two different questions:

A ──0.9──► B ──0.85──► C ──0.95──► D
QuestionAnswerTool
Is D reachable from A?yesStandard Datalog
What is the maximum single-hop weight on any path to D?0.95Standard Datalog + MAX aggregate (non-recursive)
What is the minimum weight along the best path from A to D?0.85 (the bottleneck)Lattice Datalog with min
What is the product of weights along the best path from A to D?0.726Custom lattice
Which intermediate nodes does every path from A to D pass through?{B, C}SetLattice

The moment "best path" is recursive — you don't know in advance which direction is best — you need a lattice.


Choosing the right built-in lattice

The strength of a chain is the strength of its weakest link.

Use min when:

  • Propagating trust / confidence through a network (the result is only as trustworthy as the least-trusted step).
  • Computing shortest path where the path cost is the maximum edge weight.
  • Finding bottleneck capacity in a flow network (the flow is limited by the narrowest pipe).
-- Load rules (trust propagates, bottlenecked by the weakest hop).
SELECT pg_ripple.load_rules($RULES$
?x ex:trusts ?y :- ?x ex:directlyTrusts ?y .
?x ex:trusts ?z :- ?x ex:directlyTrusts ?y, ?y ex:trusts ?z .
@lattice ex:trusts confidence min .
$RULES$, 'trust');

SELECT pg_ripple.infer_lattice('trust', 'min');

max — best-case reasoning

Use max when:

  • Propagating reputation / endorsement scores where having one highly-rated connection is enough.
  • Finding the longest path weight in a DAG.
  • Any "optimistic" or "best evidence wins" scenario.
@lattice ex:endorses score max .

set — provenance and multi-valued reasoning

Use set when:

  • You need to track which source triples justify a derived fact (provenance semiring).
  • You need the union of all witnesses along all derivation paths, not just one.
  • Each node collects contributions from multiple parents and you need all of them.
-- Collect the set of all papers that support a hypothesis.
@lattice ex:supports evidence set .

Note: set-lattice results can be large. Consider a maximum set size or a bloom-filter approximation for large graphs.

interval — when truth has a time range

Use interval when reasoning about temporal overlap: "A and B are both true during the period when both of their valid intervals overlap".

-- Derived fact is valid only during the intersection of the body's intervals.
@lattice ex:validDuring interval interval .

Picking between min and a custom multiplicative lattice

The difference matters when the graph has many hops:

Hopsmin resultMultiplicative result
A→B (0.9)0.90.9
A→B→C (×0.85)0.850.765
A→B→C→D (×0.95)0.850.726
  • min: "how reliable is my weakest source?" — appropriate for trust chains where one bad link invalidates everything.
  • Multiplicative: "what is the combined probability, assuming independence?" — appropriate for Bayesian-style confidence propagation.

For the multiplicative case, register a custom aggregate:

-- Step 1: create the multiplicative aggregate.
CREATE OR REPLACE FUNCTION prob_mul(state FLOAT8, val FLOAT8)
    RETURNS FLOAT8 LANGUAGE sql IMMUTABLE AS $$ SELECT COALESCE(state, 1.0) * val $$;

CREATE AGGREGATE prob_product(FLOAT8) (SFUNC = prob_mul, STYPE = FLOAT8, INITCOND = '1.0');

-- Step 2: register the lattice.
SELECT pg_ripple.create_lattice('probability', 'prob_product', '0.0');

-- Step 3: run inference.
SELECT pg_ripple.infer_lattice('my_rules', 'probability');

Do I really need a lattice?

Before reaching for a lattice, check whether a simpler approach works:

ScenarioSimpler alternative
Count edges reachableStandard WITH RECURSIVE in SQL
Sum weights along a fixed-depth pathSPARQL SELECT with arithmetic
Aggregate over non-recursive rulesStandard Datalog with @agg directive
Confidence is additive, not multiplicative or minSUM aggregate in a non-recursive rule

Lattices add one piece of complexity: the fixpoint loop. If you can express the same computation as a single SQL WITH RECURSIVE query or a non-recursive Datalog rule, that is almost always simpler and faster.


Convergence and termination

Every lattice computation is guaranteed to terminate if the lattice has the ascending chain condition — no infinite strictly ascending chains. All four built-in lattices satisfy this:

  • min over bounded integers / floats: descending-only.
  • max over bounded integers / floats: ascending but bounded.
  • set of a finite universe: a finite powerset, every chain terminates.
  • interval over bounded timestamps: bounded.

Custom lattices over unbounded domains can diverge. Set pg_ripple.lattice_max_iterations (default: 1000) as a safety cap. The engine emits a PT540 warning if the cap is hit and returns the current (partial) fixpoint.


See also