pub struct WithMeta<D, M> { /* private fields */ }Expand description
A distribution D that carries metadata M for the handler that runs its
site (#63).
A handler sees only (addr, dist) at a site. When it needs more than the
distribution (the question to put to a model, the names of the options, a
slice of state), WithMeta carries it along with the distribution. A
handler that knows the type recovers both with
downcast_ref, and falls back to its usual
behaviour when the downcast returns None.
For sampling and scoring, a WithMeta<D, M> is just D. sample,
log_prob and support forward to the inner distribution, so the built-in
handlers and inference routines, and any handler that doesn’t look for M,
record the same values, log-probabilities and weights as with the bare D,
draw for draw from the same seed. clone_box
keeps the metadata.
§Metadata that belongs to the site, or to the handler
WithMeta is for metadata that belongs to the site. It is built with the
distribution, it can depend on values sampled earlier in the same
execution, and it needs no bookkeeping outside the model. Metadata that is
known outside the model, such as configuration keyed by address, can
instead live in a HashMap<Address, M> that the handler holds and looks up
by the site’s addr. That way the model doesn’t change at all.
§Naming the type
A downcast matches the exact type, so the handler names both parameters:
WithMeta<Categorical, Question>, not Categorical. The inner
distribution is reached through dist. Reading M
without knowing D would need a second hook on Distribution, and there
isn’t one; a handler that accepts several inner types tries each of them.
§Example
/// What a decision site asks, and the names of its options.
#[derive(Clone, Debug)]
struct Question {
text: &'static str,
options: Vec<&'static str>,
}
let site = WithMeta::new(
Categorical::new(vec![0.6, 0.3, 0.1]).unwrap(),
Question { text: "Which tool next?", options: vec!["search", "edit", "test"] },
);
// In a model it is the categorical: the same draw from the same seed.
let mut rng = StdRng::seed_from_u64(7);
let handler = PriorHandler { rng: &mut rng, trace: Trace::default() };
let (wrapped, _) = runtime::handler::run(handler, sample(addr!("tool"), site.clone()));
let mut rng = StdRng::seed_from_u64(7);
let handler = PriorHandler { rng: &mut rng, trace: Trace::default() };
let (bare, _) = runtime::handler::run(handler, sample(addr!("tool"), site.dist().clone()));
assert_eq!(wrapped, bare);
// A handler's `on_sample_usize` receives a `&dyn Distribution<usize>`. One
// that knows the type reads the question and the probabilities directly.
let dist: &dyn Distribution<usize> = &site;
let found = dist.downcast_ref::<WithMeta<Categorical, Question>>().unwrap();
assert_eq!(found.meta().text, "Which tool next?");
let edit = found.meta().options.iter().position(|&o| o == "edit").unwrap();
assert_eq!(found.dist().probs()[edit], 0.3);Implementations§
Source§impl<D, M> WithMeta<D, M>
impl<D, M> WithMeta<D, M>
Sourcepub fn new(dist: D, meta: M) -> Self
pub fn new(dist: D, meta: M) -> Self
Attach meta to dist.
let site = WithMeta::new(Bernoulli::new(0.9).unwrap(), "Is the build green?");
// Sampled exactly as the bare Bernoulli would be.
let model: Model<bool> = sample(addr!("green"), site);Sourcepub fn dist(&self) -> &D
pub fn dist(&self) -> &D
The wrapped distribution.
let site = WithMeta::new(Normal::new(1.0, 2.0).unwrap(), "offset");
assert_eq!(site.dist().mu(), 1.0);Sourcepub fn meta(&self) -> &M
pub fn meta(&self) -> &M
The metadata.
let site = WithMeta::new(Poisson::new(3.0).unwrap(), vec!["arrivals", "per hour"]);
assert_eq!(site.meta()[0], "arrivals");Sourcepub fn into_parts(self) -> (D, M)
pub fn into_parts(self) -> (D, M)
Split into the distribution and the metadata.
let (dist, meta) = WithMeta::new(Beta::new(2.0, 5.0).unwrap(), 42u32).into_parts();
assert_eq!(dist.alpha(), 2.0);
assert_eq!(meta, 42);Trait Implementations§
Source§impl<T, D, M> Distribution<T> for WithMeta<D, M>
impl<T, D, M> Distribution<T> for WithMeta<D, M>
Source§fn sample(&self, rng: &mut dyn RngCore) -> T
fn sample(&self, rng: &mut dyn RngCore) -> T
T, from the distribution, using the provided random number generator, rng. Read moreSource§fn log_prob(&self, x: &T) -> LogF64
fn log_prob(&self, x: &T) -> LogF64
x, from the distribution. Read moreSource§fn clone_box(&self) -> Box<dyn Distribution<T>>
fn clone_box(&self) -> Box<dyn Distribution<T>>
Box<dyn Distribution<T>>. Read more