Rete.Engine (Rete v0.2.0)

Copy Markdown View Source

The propagation loop and the fire cycle.

Internal. Not part of the public API. Call it through Rete.Session.

Propagation drains a queue of pending work. A node consumes one unit, and returns the work it produced. Firing pops the most salient activation, runs its right hand side, and inserts what it returned. Propagation drains to completion before the next activation fires, so a rule always sees a settled network.

fire_rules/2 returns at quiescence. Every rule whose left hand side holds has fired, and nothing whose support has gone is still asserting anything.

See docs/design/engine.md §2 for the loops, §8 for truth maintenance, and docs/design/observability.md §3 for the loop guard.

Summary

Functions

Every fact the session holds, inserted or concluded.

Fires until the agenda is empty.

Inserts facts and propagates them.

The state a listener has accumulated, or nil if it is not attached.

A state over a network, with nothing inserted.

Runs a query: one result per match, computed by the query's body.

Retracts facts and propagates the retraction.

Attaches a listener with its initial state.

Functions

facts(state)

@spec facts(Rete.Engine.State.t()) :: [term()]

Every fact the session holds, inserted or concluded.

This excludes the marker facts an extracted compound negation inserts. They express a negated conjunction to the network, and no rule of the user's concluded them. Everywhere else, they are ordinary facts.

fire_rules(state, opts \\ [])

@spec fire_rules(
  Rete.Engine.State.t(),
  keyword()
) :: Rete.Engine.State.t()

Fires until the agenda is empty.

Options:

  • :max_cycles — how many cycles one call may fire. A cycle is one pass of the fire loop: one activation at the default concurrency, one whole activation group above it. :infinity by default, so an oscillating ruleset spins rather than raising. Firing that many and still having work pending raises with the rules that fired most. Firing that many and settling is fine. See docs/design/observability.md §3.
  • :concurrency — how many rule bodies of one activation group run at once. 1 by default, which is the sequential path. Above 1, the bodies of a group run on tasks and their conclusions are applied in group order. Worth raising only when a body is expensive: a body that just builds a tuple is about 1.5% of firing, and a task costs more than that. See docs/design/engine.md §11.
  • :timeout — milliseconds a single body may take, or :infinity, the default. Only applies when :concurrency is above 1.

insert(state, facts, origin \\ :asserted)

Inserts facts and propagates them.

A fact equal to one already present bumps its count and propagates nothing. The matches it would make already exist.

listener_state(state, module)

@spec listener_state(Rete.Engine.State.t(), module()) :: term()

The state a listener has accumulated, or nil if it is not attached.

new(network)

A state over a network, with nothing inserted.

Plants the root token now rather than on the first propagation. A rule whose whole left hand side is an absence or an empty collection is true of the empty session, and must be able to fire before a fact arrives. See docs/design/engine.md §6.

query(state, ref, filters \\ [])

@spec query(
  Rete.Engine.State.t(),
  {module(), atom()},
  keyword() | %{required(atom()) => term()}
) :: [
  term()
]

Runs a query: one result per match, computed by the query's body.

A query is named by the {module, name} pair it was defined under. defquery summary(...) also defines summary/2 in its own module. MyRuleset.summary(session, filters) is the readable form of this call.

filters narrows the matches by equality on the bindings, before the body runs. It may name any variable the left hand side binds.

Row order is unspecified. It is deterministic for a given set of facts. But nothing about that order is a guarantee to build on.

retract(state, facts, origin \\ :asserted)

Retracts facts and propagates the retraction.

Only the last occurrence of a fact propagates. Anything concluded from it is retracted in turn, until the network settles.

with_listener(state, module, init)

@spec with_listener(Rete.Engine.State.t(), module(), term()) :: Rete.Engine.State.t()

Attaches a listener with its initial state.