Engine · 6
Prediction
For each of a set of candidate observations, predict projects its effect on the recognition
result and ranks the candidates by how much they change it. Where
frontier chains backward from one goal, predict projects forward across many.
Information gain
The default mode scores each candidate by information gain — the reduction in the coverage a diagnosis
still leaves unexplained (its residual) — after feeding it through evaluation's fixpoint, so an
observation that completes a derived anchor counts. --fast skips the fixpoint for a
single-hop re-score. Against this corpus and a chart in which the patient has only presented:
// tropes/cystitis.trl — Dysuria carries evidence weight 4 (a likelihood ratio)
// @prevalence 5
rule Cystitis { when: evt $e [&Presents(agent=$p)] $p [=Dysuria*4] then: $p [+Cystitis] }
// tropes/pyelo.trl — Pyuria weighted 9
// @prevalence 5
rule Pyelo { when: evt $e [&Presents(agent=$p)] $p [=Pyuria*9] then: $p [+Pyelo] } // chart.trl — the patient has presented; nothing distinguishing yet
char pt
scene visit { beat 1 { evt e [&Presents(agent=pt)] } } $ tropelang predict chart.trl --observe Pyuria,Dysuria --corpus file://trl
== predict (through-derivation) — by info gain ==
Pyuria infoGain 0.75 Pyelo absent → confirmed 1.00
Dysuria infoGain 0.75 Cystitis absent → confirmed 1.00 Each observation confirms its own diagnosis — equal gain here, since each is the sole anchor of a live hypothesis.
The Bayesian posterior
--bayesian swaps coverage-residual for the normalized posterior over the
differential and scores each observation by its value of information — how much
it sharpens that posterior. It reads the [=Sign*w] weights as likelihood ratios and the
@prevalence tier as the prior:
$ tropelang predict chart.trl --observe Pyuria,Dysuria --bayesian --corpus file://trl
== predict (bayesian) — posterior over the differential ==
Cystitis 0.500
Pyelo 0.500
-- value of information, by observation --
Pyuria VOI 0.368 Pyelo 0.500 → 0.900
Dysuria VOI 0.193 Cystitis 0.500 → 0.800
Nothing VOI 0.000
With a uniform prior and no distinguishing evidence yet, the differential sits at 0.5 / 0.5. Because
Pyuria is weighted 9 against Dysuria's 4, acquiring it sharpens the posterior
further, to 0.90, ranking it first. The posterior is
P(dx | chart) ∝ prior(tier) · ∏ present-anchor weights, normalized.
Interpreting the output
- signed VOI
- A negative VOI means the observation would muddy the differential — lift a trailing hypothesis toward the leader — rather than sharpen it. Surfaced so a workup can avoid it.
- exclusion
- A diagnosis the chart rules out — a missing
!-necessary anchor, or a type violation — is dropped from the differential entirely; it isn't a live hypothesis. - unweighted = LR 1
- An anchor with no
*wis uninformative in Bayesian mode. With no authored weights the posterior is just the normalized prior (correctly: no evidence, no update) — so weight the facets that actually distinguish competing diagnoses.
Two coarse, domain-neutral modeling defaults a consumer can refine: the prior is linear in the
(log) prevalence tier (only ratios matter, normalized), and the *w weight is
the likelihood ratio. The engine evaluates the corpus's own rules and learns no domain concept. Authoring
for reasoning uses the recognition marks plus these weights and
@prevalence; the style guide covers where to put them.
Interfaces
- CLI
tropelang predict <chart> --observe A,B,C [--corpus <url>…] [--fast | --bayesian] [--json].- WASM
predict(src, observables_json, fast)— info-gain mode;predict_bayesian(src, observables_json)— posterior + VOI. Both return{ predictions, posterior, chartParseError }.