fugue/runtime/delegate.rs
1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/docs/runtime/delegate.md"))]
2
3use crate::core::address::Address;
4use crate::core::distribution::Distribution;
5use crate::runtime::handler::Handler;
6use crate::runtime::trace::Trace;
7
8/// What a [`Delegate`] does at each kind of site.
9///
10/// Every method defaults to forwarding to the inner handler, so an
11/// implementation overrides only the sites it cares about. The hooks mirror
12/// [`Handler`]'s methods, with the same names and argument order, and take the
13/// inner handler as an extra argument after `self`. To forward a site, call the
14/// same method on `inner`, before or after your own work; a hook that does not
15/// forward answers the site itself, and the inner handler never sees it.
16///
17/// Implement it for every `H: Handler` to get a decorator that wraps any
18/// handler, or for one concrete handler to reach its fields, such as a
19/// [`PriorHandler`](crate::runtime::interpreters::PriorHandler)'s `trace`.
20/// `()` implements it and overrides nothing.
21///
22/// Example (count the `f64` sample sites and forward every site):
23/// ```rust
24/// # use fugue::*;
25/// # use fugue::runtime::interpreters::PriorHandler;
26/// # use rand::rngs::StdRng;
27/// # use rand::SeedableRng;
28/// /// Counts the f64 sample sites. Every other hook keeps its default: forward.
29/// struct CountF64<'a>(&'a mut usize);
30///
31/// impl<H: Handler> Overrides<H> for CountF64<'_> {
32/// fn on_sample_f64(
33/// &mut self,
34/// inner: &mut H,
35/// addr: &Address,
36/// dist: &dyn Distribution<f64>,
37/// ) -> f64 {
38/// *self.0 += 1;
39/// inner.on_sample_f64(addr, dist)
40/// }
41/// }
42///
43/// let model = prob! {
44/// let mu <- sample(addr!("mu"), Normal::new(0.0, 1.0).unwrap());
45/// let heads <- sample(addr!("coin"), Bernoulli::new(0.5).unwrap());
46/// observe(addr!("y"), Normal::new(mu, 1.0).unwrap(), 0.3);
47/// pure(heads)
48/// };
49///
50/// let mut count = 0;
51/// let mut rng = StdRng::seed_from_u64(42);
52/// let handler = Delegate::with(
53/// PriorHandler { rng: &mut rng, trace: Trace::default() },
54/// CountF64(&mut count),
55/// );
56/// let (_heads, trace) = runtime::handler::run(handler, model);
57///
58/// assert_eq!(count, 1); // "mu": the bool site and the observation were only forwarded
59/// assert_eq!(trace.choices.len(), 2); // PriorHandler recorded both samples
60/// ```
61pub trait Overrides<H: Handler> {
62 /// Hook for an `f64` sample site. Defaults to `inner.on_sample_f64(addr, dist)`.
63 fn on_sample_f64(
64 &mut self,
65 inner: &mut H,
66 addr: &Address,
67 dist: &dyn Distribution<f64>,
68 ) -> f64 {
69 inner.on_sample_f64(addr, dist)
70 }
71
72 /// Hook for a `bool` sample site. Defaults to `inner.on_sample_bool(addr, dist)`.
73 fn on_sample_bool(
74 &mut self,
75 inner: &mut H,
76 addr: &Address,
77 dist: &dyn Distribution<bool>,
78 ) -> bool {
79 inner.on_sample_bool(addr, dist)
80 }
81
82 /// Hook for a `u64` sample site. Defaults to `inner.on_sample_u64(addr, dist)`.
83 fn on_sample_u64(
84 &mut self,
85 inner: &mut H,
86 addr: &Address,
87 dist: &dyn Distribution<u64>,
88 ) -> u64 {
89 inner.on_sample_u64(addr, dist)
90 }
91
92 /// Hook for a `usize` sample site. Defaults to `inner.on_sample_usize(addr, dist)`.
93 fn on_sample_usize(
94 &mut self,
95 inner: &mut H,
96 addr: &Address,
97 dist: &dyn Distribution<usize>,
98 ) -> usize {
99 inner.on_sample_usize(addr, dist)
100 }
101
102 /// Hook for an `i64` sample site. Defaults to `inner.on_sample_i64(addr, dist)`,
103 /// so a delegate panics at an `i64` site only if its inner handler does
104 /// (see [`Handler::on_sample_i64`]).
105 fn on_sample_i64(
106 &mut self,
107 inner: &mut H,
108 addr: &Address,
109 dist: &dyn Distribution<i64>,
110 ) -> i64 {
111 inner.on_sample_i64(addr, dist)
112 }
113
114 /// Hook for an `f64` observation. Defaults to `inner.on_observe_f64(addr, dist, value)`.
115 fn on_observe_f64(
116 &mut self,
117 inner: &mut H,
118 addr: &Address,
119 dist: &dyn Distribution<f64>,
120 value: f64,
121 ) {
122 inner.on_observe_f64(addr, dist, value)
123 }
124
125 /// Hook for a `bool` observation. Defaults to `inner.on_observe_bool(addr, dist, value)`.
126 fn on_observe_bool(
127 &mut self,
128 inner: &mut H,
129 addr: &Address,
130 dist: &dyn Distribution<bool>,
131 value: bool,
132 ) {
133 inner.on_observe_bool(addr, dist, value)
134 }
135
136 /// Hook for a `u64` observation. Defaults to `inner.on_observe_u64(addr, dist, value)`.
137 fn on_observe_u64(
138 &mut self,
139 inner: &mut H,
140 addr: &Address,
141 dist: &dyn Distribution<u64>,
142 value: u64,
143 ) {
144 inner.on_observe_u64(addr, dist, value)
145 }
146
147 /// Hook for a `usize` observation. Defaults to
148 /// `inner.on_observe_usize(addr, dist, value)`.
149 fn on_observe_usize(
150 &mut self,
151 inner: &mut H,
152 addr: &Address,
153 dist: &dyn Distribution<usize>,
154 value: usize,
155 ) {
156 inner.on_observe_usize(addr, dist, value)
157 }
158
159 /// Hook for an `i64` observation. Defaults to
160 /// `inner.on_observe_i64(addr, dist, value)`, so, as for `i64` samples, a
161 /// delegate panics only if its inner handler does.
162 fn on_observe_i64(
163 &mut self,
164 inner: &mut H,
165 addr: &Address,
166 dist: &dyn Distribution<i64>,
167 value: i64,
168 ) {
169 inner.on_observe_i64(addr, dist, value)
170 }
171
172 /// Hook for a factor. Defaults to `inner.on_factor(logw)`.
173 fn on_factor(&mut self, inner: &mut H, logw: f64) {
174 inner.on_factor(logw)
175 }
176
177 /// Hook for the end of the run: takes the overrides and the inner handler by
178 /// value and returns the trace. Defaults to `inner.finish()`.
179 fn finish(self, inner: H) -> Trace
180 where
181 Self: Sized,
182 {
183 inner.finish()
184 }
185}
186
187/// `()` overrides nothing: `Delegate<H, ()>`, what [`Delegate::new`] builds,
188/// forwards every site to `H`.
189impl<H: Handler> Overrides<H> for () {}
190
191/// A [`Handler`] that forwards every site to an inner handler, through the
192/// hooks of an [`Overrides`] value.
193///
194/// Each site goes to the matching hook of `overrides`, with `inner` as its
195/// extra argument, and each hook defaults to forwarding the site to `inner`. So
196/// `Delegate::new(h)` (overrides `()`) behaves exactly like `h`, and
197/// `Delegate::with(h, o)` behaves like `h` except at the sites `o` overrides.
198///
199/// Delegates nest. In `Delegate<Delegate<H, A>, B>` the hooks of `B` see each
200/// site first, and their `inner` is the `Delegate<H, A>`, which passes the site
201/// on through `A` to `H`. At the end of the run `B::finish` runs first, and
202/// `A::finish` runs when `B::finish` finishes its inner handler.
203///
204/// A `Delegate` is a plain struct of its two fields: no boxing, and every hook
205/// call is statically dispatched.
206///
207/// Example (two decorators nested around a `PriorHandler`):
208/// ```rust
209/// # use fugue::*;
210/// # use fugue::runtime::interpreters::PriorHandler;
211/// # use rand::rngs::StdRng;
212/// # use rand::SeedableRng;
213/// /// Logs the f64 sample sites it sees, under a name, and forwards them.
214/// struct Log<'a>(&'static str, &'a std::cell::RefCell<Vec<String>>);
215///
216/// impl<H: Handler> Overrides<H> for Log<'_> {
217/// fn on_sample_f64(
218/// &mut self,
219/// inner: &mut H,
220/// addr: &Address,
221/// dist: &dyn Distribution<f64>,
222/// ) -> f64 {
223/// self.1.borrow_mut().push(format!("{} saw {}", self.0, addr));
224/// inner.on_sample_f64(addr, dist)
225/// }
226/// }
227///
228/// let log = std::cell::RefCell::new(Vec::new());
229/// let mut rng = StdRng::seed_from_u64(1);
230/// let prior = PriorHandler { rng: &mut rng, trace: Trace::default() };
231/// let handler = Delegate::with(Delegate::with(prior, Log("inner", &log)), Log("outer", &log));
232///
233/// let (_x, trace) =
234/// runtime::handler::run(handler, sample(addr!("x"), Normal::new(0.0, 1.0).unwrap()));
235///
236/// assert_eq!(log.into_inner(), ["outer saw x", "inner saw x"]);
237/// assert!(trace.get_f64(&addr!("x")).is_some()); // recorded by the PriorHandler
238/// ```
239#[derive(Clone, Debug)]
240pub struct Delegate<H, O = ()> {
241 /// The handler that every site not overridden is forwarded to.
242 pub inner: H,
243 /// The hooks, and whatever state they keep.
244 pub overrides: O,
245}
246
247impl<H> Delegate<H> {
248 /// Wrap `inner` with no overrides, so every site is forwarded to it.
249 ///
250 /// The result behaves exactly like `inner`: same values, same trace.
251 ///
252 /// Example:
253 /// ```rust
254 /// # use fugue::*;
255 /// # use fugue::runtime::interpreters::PriorHandler;
256 /// # use rand::rngs::StdRng;
257 /// # use rand::SeedableRng;
258 /// let model = || sample(addr!("x"), Normal::new(0.0, 1.0).unwrap());
259 ///
260 /// let mut rng = StdRng::seed_from_u64(7);
261 /// let (x, _) = runtime::handler::run(
262 /// PriorHandler { rng: &mut rng, trace: Trace::default() },
263 /// model(),
264 /// );
265 ///
266 /// let mut rng = StdRng::seed_from_u64(7);
267 /// let delegate = Delegate::new(PriorHandler { rng: &mut rng, trace: Trace::default() });
268 /// let (y, trace) = runtime::handler::run(delegate, model());
269 ///
270 /// assert_eq!(x, y); // same seed, same draw
271 /// assert_eq!(trace.get_f64(&addr!("x")), Some(x));
272 /// ```
273 pub fn new(inner: H) -> Self {
274 Delegate {
275 inner,
276 overrides: (),
277 }
278 }
279}
280
281impl<H, O> Delegate<H, O> {
282 /// Wrap `inner`, sending each site through the hooks of `overrides` first.
283 ///
284 /// Example (clamp every `f64` sample to `[-1, 1]` before the model sees it;
285 /// the trace keeps the value the inner handler drew):
286 /// ```rust
287 /// # use fugue::*;
288 /// # use fugue::runtime::interpreters::PriorHandler;
289 /// # use rand::rngs::StdRng;
290 /// # use rand::SeedableRng;
291 /// struct Clamp;
292 ///
293 /// impl<H: Handler> Overrides<H> for Clamp {
294 /// fn on_sample_f64(
295 /// &mut self,
296 /// inner: &mut H,
297 /// addr: &Address,
298 /// dist: &dyn Distribution<f64>,
299 /// ) -> f64 {
300 /// inner.on_sample_f64(addr, dist).clamp(-1.0, 1.0)
301 /// }
302 /// }
303 ///
304 /// let mut rng = StdRng::seed_from_u64(3);
305 /// let handler = Delegate::with(PriorHandler { rng: &mut rng, trace: Trace::default() }, Clamp);
306 /// let (x, _trace) =
307 /// runtime::handler::run(handler, sample(addr!("x"), Normal::new(0.0, 10.0).unwrap()));
308 ///
309 /// assert!((-1.0..=1.0).contains(&x));
310 /// ```
311 pub fn with(inner: H, overrides: O) -> Self {
312 Delegate { inner, overrides }
313 }
314}
315
316/// Every method calls the hook of the same name on `overrides`, passing `inner`.
317impl<H: Handler, O: Overrides<H>> Handler for Delegate<H, O> {
318 fn on_sample_f64(&mut self, addr: &Address, dist: &dyn Distribution<f64>) -> f64 {
319 self.overrides.on_sample_f64(&mut self.inner, addr, dist)
320 }
321
322 fn on_sample_bool(&mut self, addr: &Address, dist: &dyn Distribution<bool>) -> bool {
323 self.overrides.on_sample_bool(&mut self.inner, addr, dist)
324 }
325
326 fn on_sample_u64(&mut self, addr: &Address, dist: &dyn Distribution<u64>) -> u64 {
327 self.overrides.on_sample_u64(&mut self.inner, addr, dist)
328 }
329
330 fn on_sample_usize(&mut self, addr: &Address, dist: &dyn Distribution<usize>) -> usize {
331 self.overrides.on_sample_usize(&mut self.inner, addr, dist)
332 }
333
334 fn on_sample_i64(&mut self, addr: &Address, dist: &dyn Distribution<i64>) -> i64 {
335 self.overrides.on_sample_i64(&mut self.inner, addr, dist)
336 }
337
338 fn on_observe_f64(&mut self, addr: &Address, dist: &dyn Distribution<f64>, value: f64) {
339 self.overrides
340 .on_observe_f64(&mut self.inner, addr, dist, value)
341 }
342
343 fn on_observe_bool(&mut self, addr: &Address, dist: &dyn Distribution<bool>, value: bool) {
344 self.overrides
345 .on_observe_bool(&mut self.inner, addr, dist, value)
346 }
347
348 fn on_observe_u64(&mut self, addr: &Address, dist: &dyn Distribution<u64>, value: u64) {
349 self.overrides
350 .on_observe_u64(&mut self.inner, addr, dist, value)
351 }
352
353 fn on_observe_usize(&mut self, addr: &Address, dist: &dyn Distribution<usize>, value: usize) {
354 self.overrides
355 .on_observe_usize(&mut self.inner, addr, dist, value)
356 }
357
358 fn on_observe_i64(&mut self, addr: &Address, dist: &dyn Distribution<i64>, value: i64) {
359 self.overrides
360 .on_observe_i64(&mut self.inner, addr, dist, value)
361 }
362
363 fn on_factor(&mut self, logw: f64) {
364 self.overrides.on_factor(&mut self.inner, logw)
365 }
366
367 fn finish(self) -> Trace {
368 self.overrides.finish(self.inner)
369 }
370}
371
372#[cfg(test)]
373mod tests {
374 use super::*;
375 use crate::addr;
376 use crate::core::distribution::*;
377 use crate::core::model::{factor, observe, pure, sample, Model};
378 use crate::runtime::handler::run;
379 use crate::runtime::interpreters::{PriorHandler, ReplayHandler, ScoreGivenTrace};
380 use crate::runtime::trace::ChoiceValue;
381 use rand::rngs::StdRng;
382 use rand::{RngCore, SeedableRng};
383 use std::cell::RefCell;
384
385 type Sites = (f64, bool, u64, usize, i64);
386
387 /// A sample site and an observation of each of the five value types, then a
388 /// factor. The observations and the factor depend on the sampled values, so
389 /// every accumulator depends on what the handler did at the sample sites.
390 fn all_sites() -> Model<Sites> {
391 crate::prob! {
392 let f <- sample(addr!("f"), Normal::new(0.0, 1.0).unwrap());
393 let b <- sample(addr!("b"), Bernoulli::new(0.3).unwrap());
394 let u <- sample(addr!("u"), Poisson::new(2.5).unwrap());
395 let z <- sample(addr!("z"), Categorical::new(vec![0.2, 0.5, 0.3]).unwrap());
396 let i <- sample(addr!("i"), DiscreteUniform::new(-3, 3).unwrap());
397 observe(addr!("f_obs"), Normal::new(f, 1.0).unwrap(), 0.4);
398 observe(addr!("b_obs"), Bernoulli::new(if b { 0.8 } else { 0.2 }).unwrap(), true);
399 observe(addr!("u_obs"), Poisson::new(1.0 + u as f64).unwrap(), 3);
400 observe(addr!("z_obs"), Categorical::new(vec![0.6, 0.3, 0.1]).unwrap(), z);
401 observe(addr!("i_obs"), DiscreteUniform::new(i - 2, i + 4).unwrap(), i + 1);
402 factor(-0.5 * f * f);
403 pure((f, b, u, z, i))
404 }
405 }
406
407 /// The same trace, bit for bit: the same choices (address, value, logp) and
408 /// the same three accumulators.
409 fn assert_same_trace(a: &Trace, b: &Trace) {
410 let keys = |t: &Trace| t.choices.keys().cloned().collect::<Vec<_>>();
411 assert_eq!(keys(a), keys(b));
412 for (addr, ca) in &a.choices {
413 let cb = &b.choices[addr];
414 assert_eq!(ca.addr, cb.addr);
415 assert_eq!(ca.value, cb.value, "value at {}", addr);
416 assert_eq!(ca.logp.to_bits(), cb.logp.to_bits(), "logp at {}", addr);
417 }
418 assert_eq!(a.log_prior.to_bits(), b.log_prior.to_bits());
419 assert_eq!(a.log_likelihood.to_bits(), b.log_likelihood.to_bits());
420 assert_eq!(a.log_factors.to_bits(), b.log_factors.to_bits());
421 }
422
423 /// Guards the comparisons against passing vacuously: every site was
424 /// visited and every accumulator is a finite, nonzero number.
425 fn assert_every_site_recorded(t: &Trace) {
426 assert_eq!(t.choices.len(), 5);
427 assert!(t.get_f64(&addr!("f")).is_some());
428 assert!(t.get_bool(&addr!("b")).is_some());
429 assert!(t.get_u64(&addr!("u")).is_some());
430 assert!(t.get_usize(&addr!("z")).is_some());
431 assert!(t.get_i64(&addr!("i")).is_some());
432 for w in [t.log_prior, t.log_likelihood, t.log_factors] {
433 assert!(w.is_finite() && w != 0.0, "accumulator {}", w);
434 }
435 }
436
437 fn prior_run(seed: u64) -> (Sites, Trace) {
438 let mut rng = StdRng::seed_from_u64(seed);
439 run(
440 PriorHandler {
441 rng: &mut rng,
442 trace: Trace::default(),
443 },
444 all_sites(),
445 )
446 }
447
448 #[test]
449 fn delegate_new_matches_prior_handler() {
450 let mut rng_a = StdRng::seed_from_u64(11);
451 let (va, ta) = run(
452 PriorHandler {
453 rng: &mut rng_a,
454 trace: Trace::default(),
455 },
456 all_sites(),
457 );
458 let mut rng_b = StdRng::seed_from_u64(11);
459 let (vb, tb) = run(
460 Delegate::new(PriorHandler {
461 rng: &mut rng_b,
462 trace: Trace::default(),
463 }),
464 all_sites(),
465 );
466
467 assert_every_site_recorded(&ta);
468 assert_eq!(va, vb);
469 assert_same_trace(&ta, &tb);
470 // The delegate consumed exactly the randomness the handler did.
471 assert_eq!(rng_a.next_u64(), rng_b.next_u64());
472 }
473
474 #[test]
475 fn delegate_new_matches_replay_handler() {
476 // A base trace missing two sites, so the replay reuses three values and
477 // samples two fresh from the RNG.
478 let (_, mut base) = prior_run(12);
479 base.choices.remove(&addr!("u"));
480 base.choices.remove(&addr!("i"));
481
482 let mut rng_a = StdRng::seed_from_u64(13);
483 let (va, ta) = run(
484 ReplayHandler {
485 rng: &mut rng_a,
486 base: base.clone(),
487 trace: Trace::default(),
488 },
489 all_sites(),
490 );
491 let mut rng_b = StdRng::seed_from_u64(13);
492 let (vb, tb) = run(
493 Delegate::new(ReplayHandler {
494 rng: &mut rng_b,
495 base,
496 trace: Trace::default(),
497 }),
498 all_sites(),
499 );
500
501 assert_every_site_recorded(&ta);
502 assert_eq!(va, vb);
503 assert_same_trace(&ta, &tb);
504 assert_eq!(rng_a.next_u64(), rng_b.next_u64());
505 }
506
507 #[test]
508 fn delegate_new_matches_score_given_trace() {
509 let (_, base) = prior_run(14);
510
511 let (va, ta) = run(
512 ScoreGivenTrace {
513 base: base.clone(),
514 trace: Trace::default(),
515 },
516 all_sites(),
517 );
518 let (vb, tb) = run(
519 Delegate::new(ScoreGivenTrace {
520 base,
521 trace: Trace::default(),
522 }),
523 all_sites(),
524 );
525
526 assert_every_site_recorded(&ta);
527 assert_eq!(va, vb);
528 assert_same_trace(&ta, &tb);
529 }
530
531 /// Logs the `usize` sites it sees, samples and observations, and forwards them.
532 struct UsizeSites<'a>(&'a mut Vec<String>);
533
534 impl<H: Handler> Overrides<H> for UsizeSites<'_> {
535 fn on_sample_usize(
536 &mut self,
537 inner: &mut H,
538 addr: &Address,
539 dist: &dyn Distribution<usize>,
540 ) -> usize {
541 let value = inner.on_sample_usize(addr, dist);
542 self.0.push(format!("sample {} = {}", addr, value));
543 value
544 }
545
546 fn on_observe_usize(
547 &mut self,
548 inner: &mut H,
549 addr: &Address,
550 dist: &dyn Distribution<usize>,
551 value: usize,
552 ) {
553 self.0.push(format!("observe {} = {}", addr, value));
554 inner.on_observe_usize(addr, dist, value)
555 }
556 }
557
558 #[test]
559 fn overrides_see_their_own_sites_and_forward_the_rest() {
560 let mut seen = Vec::new();
561 let mut rng = StdRng::seed_from_u64(21);
562 let (v, t) = run(
563 Delegate::with(
564 PriorHandler {
565 rng: &mut rng,
566 trace: Trace::default(),
567 },
568 UsizeSites(&mut seen),
569 ),
570 all_sites(),
571 );
572
573 let z = v.3;
574 assert_eq!(
575 seen,
576 [
577 format!("sample z = {}", z),
578 format!("observe z_obs = {}", z)
579 ]
580 );
581 // Every site, overridden or not, reached the PriorHandler as it would
582 // have without the delegate.
583 let (pv, pt) = prior_run(21);
584 assert_eq!(v, pv);
585 assert_same_trace(&t, &pt);
586 }
587
588 /// Resolves the `usize` sample sites itself, recording the choice in the
589 /// `PriorHandler`'s trace the way `PriorHandler` records a draw.
590 struct Pick(usize);
591
592 impl<R: RngCore> Overrides<PriorHandler<'_, R>> for Pick {
593 fn on_sample_usize(
594 &mut self,
595 inner: &mut PriorHandler<'_, R>,
596 addr: &Address,
597 dist: &dyn Distribution<usize>,
598 ) -> usize {
599 let logp = dist.log_prob(&self.0);
600 inner.trace.log_prior += logp;
601 inner
602 .trace
603 .insert_choice(addr.clone(), ChoiceValue::Usize(self.0), logp);
604 self.0
605 }
606 }
607
608 #[test]
609 fn an_override_can_answer_a_site_itself() {
610 for pick in 0..3 {
611 let mut rng = StdRng::seed_from_u64(31);
612 let (v, t) = run(
613 Delegate::with(
614 PriorHandler {
615 rng: &mut rng,
616 trace: Trace::default(),
617 },
618 Pick(pick),
619 ),
620 all_sites(),
621 );
622
623 // The model and the trace both see the forced value, scored under
624 // the site's own distribution, and the observation of it is scored
625 // at it too.
626 assert_eq!(v.3, pick);
627 assert_eq!(t.get_usize(&addr!("z")), Some(pick));
628 let prior = [0.2_f64, 0.5, 0.3][pick].ln();
629 assert!((t.choices[&addr!("z")].logp - prior).abs() < 1e-12);
630 assert_every_site_recorded(&t);
631
632 // Re-scoring the trace from scratch gives the same weights.
633 let (_, rescored) = run(
634 ScoreGivenTrace {
635 base: t.clone(),
636 trace: Trace::default(),
637 },
638 all_sites(),
639 );
640 assert!((rescored.log_prior - t.log_prior).abs() < 1e-12);
641 assert!((rescored.log_likelihood - t.log_likelihood).abs() < 1e-12);
642 }
643 }
644
645 /// Logs each `f64` sample and the end of the run under a name, then forwards.
646 struct Tap<'a> {
647 name: &'static str,
648 log: &'a RefCell<Vec<String>>,
649 }
650
651 impl<H: Handler> Overrides<H> for Tap<'_> {
652 fn on_sample_f64(
653 &mut self,
654 inner: &mut H,
655 addr: &Address,
656 dist: &dyn Distribution<f64>,
657 ) -> f64 {
658 self.log
659 .borrow_mut()
660 .push(format!("{}: sample {}", self.name, addr));
661 inner.on_sample_f64(addr, dist)
662 }
663
664 fn finish(self, inner: H) -> Trace {
665 self.log.borrow_mut().push(format!("{}: finish", self.name));
666 inner.finish()
667 }
668 }
669
670 #[test]
671 fn nested_delegates_compose() {
672 let log = RefCell::new(Vec::new());
673 let mut seen = Vec::new();
674 let mut rng = StdRng::seed_from_u64(41);
675 let prior = PriorHandler {
676 rng: &mut rng,
677 trace: Trace::default(),
678 };
679 // Three layers around the PriorHandler: `UsizeSites` innermost, then
680 // two taps on the f64 sites.
681 let handler = Delegate::with(
682 Delegate::with(
683 Delegate::with(prior, UsizeSites(&mut seen)),
684 Tap {
685 name: "inner",
686 log: &log,
687 },
688 ),
689 Tap {
690 name: "outer",
691 log: &log,
692 },
693 );
694 let (v, t) = run(handler, all_sites());
695
696 assert_eq!(
697 log.into_inner(),
698 [
699 "outer: sample f",
700 "inner: sample f",
701 "outer: finish",
702 "inner: finish"
703 ]
704 );
705 assert_eq!(seen.len(), 2);
706 let (pv, pt) = prior_run(41);
707 assert_eq!(v, pv);
708 assert_same_trace(&t, &pt);
709 }
710
711 /// Adds a fixed log-weight to the trace at the end of the run.
712 struct Bonus(f64);
713
714 impl<H: Handler> Overrides<H> for Bonus {
715 fn finish(self, inner: H) -> Trace {
716 let mut trace = inner.finish();
717 trace.log_factors += self.0;
718 trace
719 }
720 }
721
722 #[test]
723 fn a_finish_override_runs() {
724 let mut rng = StdRng::seed_from_u64(51);
725 let (_, t) = run(
726 Delegate::with(
727 PriorHandler {
728 rng: &mut rng,
729 trace: Trace::default(),
730 },
731 Bonus(2.0),
732 ),
733 all_sites(),
734 );
735
736 let (_, pt) = prior_run(51);
737 assert_eq!(t.log_factors, pt.log_factors + 2.0);
738 // Everything else is the inner handler's trace, untouched.
739 assert_eq!(t.log_prior.to_bits(), pt.log_prior.to_bits());
740 assert_eq!(t.log_likelihood.to_bits(), pt.log_likelihood.to_bits());
741 assert_eq!(t.choices.len(), pt.choices.len());
742 }
743}