Agenda-based Deduction¶
The concrete chart implementation underlying every weighted
deduction in the DSL. DeductionSystem ties an axiom injector,
a rule system, a semiring, and an agenda schedule into an
nn.Module; ChartView is the differentiable presheaf returned
from DeductionSystem.__call__.
For the user-facing surface (fit, sample, NUTS wrap), see
api/stochastic/deduction.
agenda
¶
Agenda-based weighted-deduction engine.
A general framework for evaluating weighted deductive systems by
agenda-driven semi-naïve enumeration. Subsumes CKY, Earley,
Viterbi, A* parsing, Knuth's algorithm, semi-naïve Datalog
evaluation, and bidirectional MLTT type-checking under one
runtime, parameterized by an Item algebra, a list of
arity-n InferenceRule hyperedges, a ChartSemiring,
an Agenda data structure, a priority function, and a
goal predicate.
Categorical denotation: the chart is the least pre-fixed point of the rule-system functor
.. math::
F : \mathbf{Set}^{I^{\mathrm{op}}}_{K} \to \mathbf{Set}^{I^{\mathrm{op}}}_{K}
in the :math:K-enriched lattice of charts (Tarski-Knaster). The
chart is the :math:K-presheaf :math:I^{\mathrm{op}} \to K
assigning the aggregate inside weight to each item. The agenda is
an operational realisation of the fixed-point computation; the
strategy-independence theorem (Goodman 1999 §3) guarantees that
the chart's final value is independent of the agenda discipline
when the semiring is idempotent.
References
- Shieber, Schabes & Pereira (1995) "Principles and Implementation of Deductive Parsing." Journal of Logic Programming 24(1-2):3-36. doi:10.1016/0743-1066(95)00035-I
- Pereira & Warren (1983) "Parsing as Deduction." Proceedings of the 21st Annual Meeting of the ACL, pp. 137-144. doi:10.3115/981311.981338
- Knuth (1977) "A Generalization of Dijkstra's Algorithm." Information Processing Letters 6(1):1-5. doi:10.1016/0020-0190(77)90002-3
- Goodman (1999) "Semiring Parsing." Computational Linguistics 25(4):573-605. https://aclanthology.org/J99-4004/
- Klein & Manning (2001) "Parsing and Hypergraphs." Proceedings of IWPT, pp. 123-134. doi:10.1007/1-4020-2295-6_18
- McAllester (2002) "On the Complexity Analysis of Static Analyses." Journal of the ACM 49(4):512-537. doi:10.1145/581771.581774
- Nederhof (2003) "Weighted Deductive Parsing and Knuth's Algorithm." Computational Linguistics 29(1):135-143. doi:10.1162/089120103321337467
- Eisner, Goldlust & Smith (2005) "Compiling Comp Ling: Practical Weighted Dynamic Programming and the Dyna Language." Proceedings of HLT-EMNLP, pp. 281-290. https://aclanthology.org/H05-1036/
- Eisner & Blatz (2007) "Program Transformations for Optimization of Parsing Algorithms and other Weighted Logic Programs." Proceedings of the 11th Conference on Formal Grammar.
Item
module-attribute
¶
Item = tuple[Any, ...]
An item is a tuple of (constructor_name, *arguments).
The constructor name disambiguates item shapes; the remaining
slots are the item's payload. Arguments may be other items
(structural), strings (atoms), integers (positions / cardinals),
or Wildcard placeholders in patterns.
Pattern
module-attribute
¶
Pattern = tuple[Any, ...]
A pattern is an item-shaped tuple that may contain Wildcard
positions. A pattern matches an item if (a) the constructor name
matches, (b) the arities match, (c) each non-wildcard slot is
structurally equal to the corresponding item slot, and (d) all
wildcards with the same name bind to equal values.
Bindings
module-attribute
¶
Bindings = dict[str, Any]
A bindings environment maps wildcard variable names to the values they captured during pattern-matching.
Wildcard
dataclass
¶
Wildcard(name: str)
Pattern-position wildcard.
A wildcard matches any value in the corresponding slot and
binds it to name for use in the conclusion. Two wildcards
with the same name in a single rule's premise list must
bind to equal values (variable-sharing).
InferenceRule
dataclass
¶
InferenceRule(name: str, premises: tuple[Pattern, ...], conclusion: Pattern, weight_fn: Callable[[Bindings, tuple, ChartSemiring], Any] | None = None, side_condition: Callable[[Bindings], bool] | None = None)
A weighted inference rule — an arity-n hyperedge.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Rule identifier (used for diagnostics and provenance).
TYPE:
|
premises
|
Patterns the rule's antecedents must match.
TYPE:
|
conclusion
|
Pattern of the item the rule produces. Wildcards must appear in the premises (so they are bound by the time the conclusion is constructed).
TYPE:
|
weight_fn
|
Function
TYPE:
|
side_condition
|
Predicate
TYPE:
|
Chart
¶
Bases: ABC
A K-valued presheaf on the item algebra.
Categorically, a chart is the K-presheaf
:math:C : I^{\mathrm{op}} \to K produced by the deduction
system on an input. The chart is the least pre-fixed point of
the rule-system functor; operationally, the agenda engine
populates it bottom-up.
Concrete subclasses choose a storage strategy: dense tensor-indexed (for CKY-style spans), sparse hash-indexed (for Datalog atoms), or term-structural (for MLTT judgments).
lookup
abstractmethod
¶
Enumerate (item, weight) pairs matching a pattern.
Source code in src/quivers/stochastic/agenda.py
240 241 242 243 | |
insert_or_aggregate
abstractmethod
¶
insert_or_aggregate(item: Item, weight: Tensor, semiring: ChartSemiring) -> bool
Insert or aggregate an item's weight.
Returns True if the item's stored weight changed
(so it should be re-enqueued for downstream firings);
False if the weight was unchanged (the inference was
redundant under the semiring's idempotent join).
Source code in src/quivers/stochastic/agenda.py
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | |
get
abstractmethod
¶
get(item: Item) -> Tensor | None
Return the chart's weight at an item, or None if absent.
Source code in src/quivers/stochastic/agenda.py
261 262 263 264 | |
items
abstractmethod
¶
items() -> Iterable[tuple[Item, Tensor]]
Enumerate all (item, weight) pairs in the chart.
Source code in src/quivers/stochastic/agenda.py
266 267 268 269 | |
HashChart
¶
HashChart(tolerance: float = 0.0)
Bases: Chart
Dictionary-backed chart for arbitrary item algebras.
Stores items as keys in a Python dict; supports linear-scan
pattern matching. Suitable for Datalog atoms, MLTT
judgments, and any deduction whose items don't have a dense
integer encoding. Falls back to O(|chart| · |pattern|) match
cost per lookup; faster specializations should override
lookup with an indexed structure.
Weights are stored as torch.Tensor values; autograd
flows through insert_or_aggregate's
semiring.plus(torch.stack([…])) reduction, so the chart's
final values carry gradients with respect to any
requires_grad=True rule-weight parameters that fed into
the agenda.
Source code in src/quivers/stochastic/agenda.py
290 291 292 | |
insert_or_aggregate
¶
insert_or_aggregate(item: Item, weight: Tensor, semiring: ChartSemiring) -> bool
Aggregate weight into the chart at item.
For non-idempotent semirings (LogProb, Counting, Inside)
with cyclic rule graphs, every re-derivation of an item via
a new path increases its weight via semiring.plus,
even when the item itself is already in the chart. With an
unconstrained cycle weight, this sequence is unbounded:
either the cycle is contractive (cycle log-weight :math:<
0), in which case the chart's weight converges to a
finite Kleene-star limit; or the cycle is non-contractive
(:math:\ge 0), in which case the chart total is :math:+
\infty and the model is mathematically ill-posed.
We make this distinction observable by terminating the
agenda when the per-item update falls below
_tolerance. The default tolerance 0.0 recovers
the original strict-equality semantics; positive
tolerances expose convergent cyclic fixed points while
still routing divergent systems through the agenda's
max_iterations safety net.
Source code in src/quivers/stochastic/agenda.py
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | |
ChartView
¶
ChartView(result: 'AgendaResult')
A first-class, differentiable view onto a chart.
Wraps a Chart produced by an agenda run and exposes
the user-facing presheaf-evaluation operations:
weight— query the aggregated weight at a single ground item; returns a differentiabletorch.Tensor.enumerate— enumerate items matching a pattern with their weights.derivations— extract the derivation forest at an item (under the derivation semiring; for the basic Boolean / LOG_PROB / Viterbi semirings, returns the flat list of matched derivations as a placeholder).goal_weight— return the weight at the goal items identified at run time.
Categorically, the chart is the K-presheaf
:math:I^{\mathrm{op}} \to K produced by the deduction
system; ChartView's methods are presheaf evaluations.
Gradients flow through these operations because the
underlying tensors carry requires_grad from the rule
weights.
Source code in src/quivers/stochastic/agenda.py
378 379 | |
attached_loss
property
¶
attached_loss: Tensor | None
The sum of rule-attached and chart-attached loss values
fired during this deduction's run, or None if no losses
were declared at those sites.
goal_items
property
¶
goal_items: list[tuple[Item, Tensor]]
List of (item, weight) pairs matching the goal predicate.
weight
¶
weight(item: Item) -> Tensor
Return the aggregated weight at a concrete item.
Raises KeyError if the item was never derived.
Returns a differentiable torch.Tensor.
Source code in src/quivers/stochastic/agenda.py
398 399 400 401 402 403 404 405 406 407 | |
try_weight
¶
try_weight(item: Item, default: Tensor | None = None) -> Tensor
Return the weight at item or default (or the
semiring's zero) if the item is absent.
Source code in src/quivers/stochastic/agenda.py
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | |
enumerate
¶
Enumerate (item, weight) pairs matching pattern.
Wildcards in pattern (instances of Wildcard)
match any slot value. The returned weights are
differentiable.
Source code in src/quivers/stochastic/agenda.py
428 429 430 431 432 433 434 435 | |
embedding
¶
embedding(item: Item) -> Tensor
Return the vector embedding of item under the deduction's
attached encoder.
Requires the originating DeductionSystem to carry an
_item_encoder attribute (set by the DSL compiler when
the deduction's body declares encoder C). Items are
converted to quivers.structural.Term form on the fly.
Source code in src/quivers/stochastic/agenda.py
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | |
derivations
¶
Return the set of items derived under item in the
chart's derivation forest.
For the current implementation (which records only the aggregate weight at each item), this returns the chart's item set as a flat enumeration. The full derivation forest — a tree-structured object whose leaves are axioms and whose internal nodes are rule firings — is recoverable by re-running the agenda with the derivation semiring (a follow-up upgrade); the public surface here keeps the entry point in place for that upgrade.
Source code in src/quivers/stochastic/agenda.py
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | |
goal_weight
¶
goal_weight() -> Tensor
Aggregate weight over all goal items.
If a single goal item was identified, returns its weight
directly; otherwise aggregates via the semiring's
plus reduction (the standard parse-as-marginal
computation).
Source code in src/quivers/stochastic/agenda.py
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 | |
Agenda
¶
Bases: ABC
A queue of items pending further inference.
The agenda discipline (FIFO / LIFO / priority) determines the evaluation order; correctness is independent of discipline for idempotent semirings (Goodman 1999 §3) but efficiency depends on it (McAllester 2002).
FIFOAgenda
¶
FIFOAgenda()
Bases: Agenda
First-in-first-out agenda (semi-naïve Datalog discipline).
The agenda processes items in the order they were derived. Correct for any monotone semiring; the canonical choice for Datalog and Earley parsing.
Source code in src/quivers/stochastic/agenda.py
542 543 | |
LIFOAgenda
¶
LIFOAgenda()
Bases: Agenda
Last-in-first-out agenda (depth-first proof-search discipline).
The agenda processes items in reverse-derivation order. Suitable for goal-directed search like Agda elaboration and Twelf-style MLTT type-checking, where depth-first proof construction is the natural strategy.
Source code in src/quivers/stochastic/agenda.py
564 565 | |
PriorityQueueAgenda
¶
PriorityQueueAgenda(priority_fn: Callable[[Item, Tensor], float])
Bases: Agenda
Priority-queue agenda parameterized by a priority function.
Items are processed in decreasing priority order. Used by Knuth's algorithm (priority = current best score), A* parsing (priority = g + h with admissible h), and any best-first chart algorithm.
| PARAMETER | DESCRIPTION |
|---|---|
priority_fn
|
TYPE:
|
Source code in src/quivers/stochastic/agenda.py
594 595 596 597 | |
AgendaResult
dataclass
¶
AgendaResult(chart: Chart, semiring: ChartSemiring, goal_items: list[tuple[Item, Tensor]] = list(), iterations: int = 0, encoder: Encoder | None = None, attached_loss: Tensor | None = None)
The chart produced by an agenda-driven deduction.
| ATTRIBUTE | DESCRIPTION |
|---|---|
chart |
The final K-presheaf on the item algebra.
TYPE:
|
semiring |
The semiring used for weight aggregation.
TYPE:
|
goal_items |
Items in the chart matching the goal predicate, with their final aggregated weights.
TYPE:
|
iterations |
Number of agenda steps consumed (diagnostic).
TYPE:
|
DeductionSystem
dataclass
¶
DeductionSystem(rules: tuple[InferenceRule, ...], semiring: ChartSemiring, axiom_injector: Callable[[Any], list[tuple[Item, Tensor]]], goal: Callable[[Item], bool], agenda_factory: Callable[[], Agenda] = FIFOAgenda, chart_factory: Callable[[], Chart] = HashChart, max_iterations: int = 100000, tolerance: float = 0.0)
A weighted deductive system parameterized over its components.
The system is parameterized by:
- An item algebra (implicit in the patterns the rules use).
- A list of arity-n
InferenceRulehyperedges. - A
ChartSemiringfor weight aggregation. - An axiom injector
In -> [(Item, Weight)]producing the input's lexical / boundary items. - A goal predicate
Item -> boolselecting the result items. - (Optional) a chart constructor and an agenda strategy.
The same data structure subsumes CKY (FIFO agenda, span items, Boolean / inside semiring), Viterbi (priority agenda with the current weight as priority, max-times semiring), A* parsing (priority agenda with an admissible heuristic, tropical semiring), MLTT type-checking (LIFO agenda, judgment items, Boolean semiring), and weighted Datalog (FIFO, atoms, any naturally-ordered semiring).
run
¶
run(input_value: Any) -> AgendaResult
Run the deduction system on an input value.
Source code in src/quivers/stochastic/agenda.py
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | |
__call__
¶
__call__(input_value: Any) -> ChartView
Run the deduction and return a ChartView.
Convenience for the user-facing presheaf-evaluation API:
the chart's weights are differentiable tensors, and the
view exposes weight, enumerate, derivations,
and goal_weight methods for downstream programs.
Source code in src/quivers/stochastic/agenda.py
1040 1041 1042 1043 1044 1045 1046 1047 1048 | |
parameters
¶
parameters(recurse: bool = True) -> Iterable[Parameter]
Yield every learnable parameter owned by this system.
Walks the optional _axiom_module (lexicon log-weights)
and _rule_module (per-rule, per-binding log-weights)
submodules attached by the compiler. The recurse flag
is the standard torch.nn.Module.parameters signature
so user code can pass a DeductionSystem anywhere a
nn.Module parameter iterator is expected.
Source code in src/quivers/stochastic/agenda.py
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 | |
named_parameters
¶
named_parameters(prefix: str = '', recurse: bool = True) -> Iterable[tuple[str, Parameter]]
Yield (name, parameter) pairs over all learnable parameters.
Source code in src/quivers/stochastic/agenda.py
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 | |
make_wildcard
¶
make_wildcard(name: str) -> Wildcard
Build a fresh wildcard with the given variable name.
Source code in src/quivers/stochastic/agenda.py
107 108 109 | |
instantiate
¶
Substitute wildcards in a pattern with their bound values.
Returns a concrete item with no wildcards. Raises
KeyError if a wildcard in the pattern has no binding.
The pattern may be a bare Wildcard (treated as "the
entire item is the wildcard"), a structural tuple, or a leaf
value (returned unchanged). Recursion runs over tuple
children.
Source code in src/quivers/stochastic/agenda.py
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | |
match
¶
Match an item against a pattern.
Source code in src/quivers/stochastic/agenda.py
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | |
run_agenda
¶
run_agenda(axioms: Iterable[tuple[Item, Tensor]], rules: Iterable[InferenceRule], semiring: ChartSemiring | None = None, agenda: Agenda | None = None, goal: Callable[[Item], bool] | None = None, max_iterations: int = 100000, chart: Chart | None = None, rule_callback: Callable[[str, list[tuple[Item, Tensor]], Item, Tensor], None] | None = None) -> AgendaResult
Run the agenda-driven deduction engine to fixed point.
Categorical denotation: returns the least pre-fixed point of
the rule-system functor on the input axioms. The
strategy-independence theorem (Goodman 1999) guarantees that
the chart's final value is independent of the agenda
discipline when semiring is idempotent.
Algorithm (Shieber-Schabes-Pereira 1995, Fig. 2 with semiring-weighted aggregation per Goodman 1999):
- Push every axiom onto the agenda.
- While the agenda is non-empty:
a. Pop an item.
b. Insert-or-aggregate into the chart.
c. If the chart's weight changed, fire every rule for which
the popped item is a premise: scan the chart for matching
siblings, compute the conclusion's weight via the rule's
weight_fn, and push the conclusion onto the agenda. - Return the chart with all items that match
goal.
| PARAMETER | DESCRIPTION |
|---|---|
axioms
|
Initial items with their input-derived weights.
TYPE:
|
rules
|
The deduction system's hyperedges.
TYPE:
|
semiring
|
Weight aggregation. Defaults to log-prob.
TYPE:
|
agenda
|
Evaluation strategy. Defaults to FIFO (semi-naïve).
TYPE:
|
goal
|
Predicate selecting result items. Defaults to "every item".
TYPE:
|
max_iterations
|
Safety bound on agenda steps; raises if exceeded.
TYPE:
|
chart
|
Initial chart (defaults to empty
TYPE:
|
Source code in src/quivers/stochastic/agenda.py
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | |
cky_agenda
¶
cky_agenda() -> Agenda
The CKY (bottom-up sweep) agenda — semi-naïve FIFO.
For context-free + Boolean / inside semirings, FIFO order
suffices to reach the chart's fixed point in
:math:O(n^3 \cdot |R|) time (McAllester 2002).
Source code in src/quivers/stochastic/agenda.py
1087 1088 1089 1090 1091 1092 1093 1094 | |
earley_agenda
¶
earley_agenda() -> Agenda
The Earley (predict / scan / complete) agenda — FIFO.
Earley's algorithm is identical to FIFO agenda-driven deduction over the predict / scan / complete items (Pereira & Warren 1983).
Source code in src/quivers/stochastic/agenda.py
1097 1098 1099 1100 1101 1102 1103 1104 | |
viterbi_agenda
¶
Viterbi-style best-first agenda.
Priorities are the current best weight in the
:math:(\max, \times) semiring; the agenda is a priority
queue. Equivalent to Knuth's algorithm when the semiring is
superior (Nederhof 2003).
Source code in src/quivers/stochastic/agenda.py
1107 1108 1109 1110 1111 1112 1113 1114 1115 | |
astar_agenda
¶
A* parsing agenda (Klein & Manning 2003).
Priority is :math:g + h where :math:g is the current
accumulated cost and :math:h is an admissible heuristic on
the remaining cost. With an admissible :math:h, the agenda
enumerates items in optimal order (Knuth 1977).
Source code in src/quivers/stochastic/agenda.py
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | |
knuth_agenda
¶
knuth_agenda() -> Agenda
Knuth's best-first hyperpath search.
Priority is the current chart weight (the item's best-so-far score). For a superior semiring, this is Dijkstra's algorithm on AND-OR hypergraphs (Knuth 1977; Nederhof 2003).
Source code in src/quivers/stochastic/agenda.py
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 | |