Internals
This page is for engine authors and contributors. It lists the calls an engine makes to run a resolved rule, and the internal helpers a contributor needs.
The engine interface
An engine uses a rule in three steps:
- It resolves the rule once, when it sets a node up, with
find_message_ruleand its siblings. - It checks the rule with
check_servicesandcheck_reads_logscale. - It runs the rule on every update with
execute_rule.execute_rulebuilds noRuleResult, so it allocates nothing beyond the rule's own work.
These names are public, for engine authors. A rule author never calls them.
MessagePassingRulesBase.execute_rule — Function
execute_rule(spec::RuleSpec, output, algorithm, ctx, args, ann, target)
execute_rule(spec::RuleSpec, output, scratch, algorithm, ctx, args, ann, target)Run a resolved rule and return its bare result, building no RuleResult: the engine's entry point.
Arguments
spec: the rule, as resolution returned it;output: for an in-place rule, the buffer to write into, ornothingto have the rule preallocate one; ignored otherwise;scratch: the rule's working memory, which an engine builds once withrule_scratchand passes on every call; without it, or withnothing, a rule that declares scratch gets a fresh one;algorithm: the value to run under,rule_algorithm(spec, algorithm);ctx: theRuleContext; its services are not checked here, which ischeck_services's job, once, when the rule is resolved;args: theRuleArgs;ann: the annotations, aRuleAnnotationsor aNoAnnotations;target: theTarget,IndexedTargetorClusterTarget, ornothingfor an average energy.
Nothing here catches exceptions: whatever a rule throws propagates to the caller. The rule's log scale is not computed; an engine that tracks log scales calls execute_rule_with_logscale instead.
A rule never sees a missing input. When any input is missing, an engine does not call the rule at all, and does not run the annotation processors that follow a rule either; the result is missing, carrying only the annotations written before the call.
MessagePassingRulesBase.execute_rule_with_logscale — Function
execute_rule_with_logscale(spec::RuleSpec, output, scratch, algorithm, ctx, args, ann, target) -> TupleRun a resolved message rule and return (result, logscale), for an engine that tracks log scales. The arguments are execute_rule's. The log scale is the one the rule declares, a number or what its function or body computes, or an UndefinedLogScale naming the rule for a rule that declares none. It does not check that args carries log scales for a rule that reads them; check_reads_logscale does.
MessagePassingRulesBase.rule_scratch — Function
rule_scratch(spec::RuleSpec, algorithm, ctx, args, target)Build the working memory a rule declares with scratch from these inputs, or return nothing for a rule that declares none. An engine builds it once per outbound stream and passes it to every execute_rule of that rule. The rule writes it before reading it, so the engine may rebuild it whenever it likes.
MessagePassingRulesBase.rule_scratch_type — Function
rule_scratch_type(spec::RuleSpec, algorithm, ctx, args, target) -> TypeThe type of the working memory rule_scratch builds for these inputs, inferred from their types: concrete where inference pins it down, Any where it does not, and Nothing for a rule that declares no scratch. It depends only on the inputs' types, so it folds to a constant where the call is inferred, and an engine keeping the scratch between calls asserts it. It decides only whether a kept scratch is typed, never what a rule computes.
MessagePassingRulesBase.check_reads_logscale — Function
check_reads_logscale(spec::RuleSpec, args::RuleArgs) -> nothingCheck that args carries log scales when spec reads them (reads_logscale = true). Whoever resolves a rule calls it before running the rule; the calls in this package do.
Throws
ArgumentError naming the rule when it reads log scales and args.logscale is nothing: its caller does not track them.
MessagePassingRulesBase.check_selected_members — Function
check_selected_members(spec::RuleSpec, target, args::RuleArgs) -> nothingCheck that a group which spec selects members of by the target's index holds nothing where the selection leaves a member out, as an engine delivers it: for a target (:in, k), member k of m[:in][!k], and every member but k of m[:in][k]. A caller that writes a group's tuple by hand calls it before running the rule; this package's interactive calls and the tables of MessagePassingRulesTestUtils do. An engine, or code that builds its RuleArgs for message_passing_rule, builds the tuple itself and need not.
Throws
ArgumentError naming the selection and the member, and saying to pass nothing there: the rule would read a value no graph gives it.
Internal helpers
These names are not part of the public API. The macros' docstrings share text through const string fragments, DOC_RULE_*, DOC_CALL_*, DOC_MPR_* and DOC_DEPENDENCY_ENTRIES. The fragments have no docstrings of their own.
MessagePassingRulesBase.default_inputs_match — Function
default_inputs_match(args::RuleArgs, ::Val{required}, ::Type{types}) -> BoolWhether args holds each typed input a rule declared with default names beside it, (container, key, selection), with its type in types, for a single interface, a cluster or a whole group. The guard the definition macro generates for such a rule, which returns a RuleNotFound where it is false. Computed from the types alone, so it folds to a constant.
MessagePassingRulesBase.WithLogScale — Type
WithLogScale(result, logscale)A rule's result paired with its log scale, as with_logscale builds it. Only the body of a rule declared with logscale = from_body returns one, and whoever runs the rule unwraps it; no rule receives one, and a caller never sees one.
MessagePassingRulesBase.FromBody — Type
FromBodyThe type of from_body, the marker a rule's logscale declaration is compared against.
MessagePassingRulesBase.Improper — Type
ImproperThe type of improper, the marker of a rule whose message has no log scale to declare.