prospicio_prob/severity.rs
1//! Operations on a loss severity that are exact for parametric (and later
2//! discretized) distributions: limited expected values, stop-loss and layers.
3//!
4//! `Sampled` does not implement [`Severity`]; an estimate from draws is
5//! [`crate::Empirical::mean_of`]. See `docs/design/distributions.md`.
6
7use crate::distribution::Distribution;
8
9/// A non-negative loss severity with exact limited moments.
10///
11/// The first three methods are related by `lev(d) + stop_loss(d) = mean()`
12/// and `layer(l, a) = stop_loss(a) - stop_loss(a + l)`. Implementations should
13/// compute `stop_loss` directly rather than as `mean() - lev(d)`, which
14/// loses all precision for retentions far in the tail.
15pub trait Severity: Distribution {
16 /// Limited expected value `E[min(X, limit)]`.
17 ///
18 /// `limit <= 0` gives `limit` (the loss is never below 0) and
19 /// `limit = +inf` gives the mean.
20 fn lev(&self, limit: f64) -> f64;
21
22 /// Expected excess over a retention, `E[max(X - retention, 0)]`.
23 fn stop_loss(&self, retention: f64) -> f64 {
24 self.mean() - self.lev(retention)
25 }
26
27 /// Expected loss to the layer `limit` xs `attachment`,
28 /// `E[min(max(X - attachment, 0), limit)]`.
29 fn layer(&self, limit: f64, attachment: f64) -> f64 {
30 self.stop_loss(attachment) - self.stop_loss(attachment + limit)
31 }
32
33 /// Second moment of the loss to the layer `limit` xs `attachment`,
34 /// `E[min(max(X - attachment, 0), limit)^2]`. `limit = +inf` gives the
35 /// unlimited layer (infinite if the second moment is).
36 fn layer_second_moment(&self, limit: f64, attachment: f64) -> f64;
37
38 /// Variance of the loss to the layer `limit` xs `attachment`.
39 fn layer_variance(&self, limit: f64, attachment: f64) -> f64 {
40 let m = self.layer(limit, attachment);
41 self.layer_second_moment(limit, attachment) - m * m
42 }
43}
44
45impl<T: Severity + ?Sized> Severity for Box<T> {
46 fn lev(&self, limit: f64) -> f64 {
47 (**self).lev(limit)
48 }
49
50 fn stop_loss(&self, retention: f64) -> f64 {
51 (**self).stop_loss(retention)
52 }
53
54 fn layer(&self, limit: f64, attachment: f64) -> f64 {
55 (**self).layer(limit, attachment)
56 }
57
58 fn layer_second_moment(&self, limit: f64, attachment: f64) -> f64 {
59 (**self).layer_second_moment(limit, attachment)
60 }
61
62 fn layer_variance(&self, limit: f64, attachment: f64) -> f64 {
63 (**self).layer_variance(limit, attachment)
64 }
65}