Path Weights¶
A path is one concrete execution of an IR with particular runtime inputs. If the IR contains branches, loops, batched inputs, or LM calls, different inputs can reach different equations and produce different intermediate values.
A path weight is an extra scalar carried alongside that execution. It is useful when the program output should stay unchanged, but the caller also needs a score for the route that produced it. Examples include ranking candidate actions, keeping or rejecting generated paths, or attaching evidence scores to outputs.
The public primitive that changes this score is factor.
import autoform as af
def label_path(label: str, weight: float) -> str:
af.factor(weight, name="score")
return label
During ordinary execution, factor is a no-output effect. During
weighted execution, each reached factor
multiplies the returned path weight:
ir = af.trace(label_path)("p1", 1.0)
output, path_weight = af.weighted(ir).call("p1", 0.9)
Mathematically, for one concrete execution path p:
That value is the accumulated score for that concrete path.
Accumulation¶
def program(x: str, a: float, b: float) -> str:
af.factor(a, name="a")
af.factor(b, name="b")
return x
ir = af.trace(program)("x1", 1.0, 1.0)
output, path_weight = af.weighted(ir).call("x1", 0.5, 0.25)
factor contributes to the path-weight channel. It does not change the
function’s returned value.
For the call above:
Value |
Result |
|---|---|
|
|
|
|
Both multipliers are included because both factor calls are reached on the
same concrete execution path.
Batch Path Scoring¶
Use batch around weighted when each input path should get its own independent path
weight:
scored = af.batch(af.weighted(ir), in_axes=(True, True))
labels = ["p1", "p2"]
weights = [0.9, 0.2]
outputs, path_weights = scored.call(labels, weights)
This is the common shape when several paths should be scored:
Prepare the batched inputs.
Run
batch(weighted(ir)).Use the returned
path_weightsin the caller.
Order matters:
Expression |
Meaning |
|---|---|
|
Score many paths independently. The result has one weight per path. |
|
Score one batched path. Reached factors across the whole batched execution multiply into one weight. |
Boundaries¶
factor does not produce a value in the user program. It only contributes to the
path weight returned by weighted.
weighted(ir) does not change the original output. It wraps that output with a
second value:
output, path_weight = af.weighted(ir).call(...)
The returned path_weight is an ordinary Python number. Caller code decides what
to do with it after the IR call returns.
Probability Reading¶
Probability is an interpretation layer over the same execution result. Treat
each candidate path as a candidate x, and treat each reached factor as
evidence compatibility. Then the path weight can be used as a likelihood-style
score.
For a small discrete example:
Term |
Meaning |
|---|---|
Candidate |
A concrete value being scored. |
Evidence |
An observed condition used to score candidates. |
Prior |
The probability of candidate |
Likelihood |
How likely candidate |
Path weight |
The value returned by |
Posterior |
The normalized result after combining the prior and path weight. |
When each reached factor represents calibrated evidence compatibility, the
path weight can stand in for L(e | x).
For exact enumeration, caller code can compute:
AutoForm only returns w(x). The prior, aggregation, and normalization stay in
the caller.
The posterior reading depends on the meaning of the factors. If the factors are calibrated likelihood terms, the normalized masses have the form of a posterior. If the factors are heuristic scores, the same calculation is a normalized decision score.
If candidates are sampled from the prior instead of enumerated once, the prior is already represented by sample frequency. In that case, aggregate the returned path weights by candidate and normalize those masses.
Candidate source |
Caller-side mass |
|---|---|
Enumerate each unique candidate once |
|
Sample candidates from the prior |
Sum |