Skip to main content

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}