2 unstable releases
0.2.0 | Jan 19, 2024 |
---|---|
0.1.0 | Jan 17, 2024 |
#226 in Simulation
25KB
485 lines
logprob
This crate defines a basic LogProb
wrapper for floats. The struct is designed so
that only values that are coherent for a log-probability are acceptable. This means that
LogProb
can store:
- Any finite negative float value (e.g. -0.23, -32535.05, -66.0).
- Negative infinity (corresponding to 0.0 probability)
- 0.0 and -0.0.
The crate is intended for careful implementations of computations involving log-probabilities.
Features:
- A way to add
LogProb
s (equivalent take the product of their corresponding raw probabilities) - Take the product of a
LogProb
and an unsigned integer (e.g. equivalent to p^n). Ord
andEq
trait onLogProb
as there is noNaN
.- A relatively efficient implementation of LogSumExp for slices and iterators.
For examples, see the documentation.
lib.rs
:
This crate defines a basic LogProb
wrapper for floats. The struct is designed so
that only values that are coherent for a log-probability are acceptable. This means that
LogProb
can store:
- Any finite negative float value (e.g. -0.23, -32535.05, -66.0).
- Negative infinity (corresponding to 0.0 probability)
- 0.0 and -0.0.
If any other value is passed, LogProb::new
returns a FloatIsNanOrPositive
error.
You can also construct new LogProb
from values in [0,1] by using
LogProb::from_raw_prob
The crate also includes the ability to add log probabilities (equivalent take the product of their corresponding raw probabilities):
use logprob::LogProb;
let x = LogProb::from_raw_prob(0.5).unwrap();
let y = LogProb::from_raw_prob(0.5).unwrap();
let z = x + y;
assert_eq!(z, LogProb::from_raw_prob(0.25).unwrap());
It is also possible to take product of a LogProb
and an unsigned integer, which
corresponds to taking the exponent of the log-probability to the power of the integer.
let x = LogProb::from_raw_prob(0.5_f64).unwrap();
let y: u8 = 2;
let z = x * y;
assert_eq!(z, LogProb::from_raw_prob(0.25).unwrap());
Finally, the crate also includes reasonably efficient implementations of
LogSumExp so that one can take the sum of
raw-probabilities directly with LogProb
.
let x = LogProb::from_raw_prob(0.5_f64).unwrap();
let y = LogProb::from_raw_prob(0.25).unwrap();
let z = x.add_log_prob(y).unwrap();
assert_eq!(z, LogProb::from_raw_prob(0.75).unwrap());
This can also work for slices or iterators (by importing log_sum_exp
or the trait,
LogSumExp
respectively. Note that for empty vectors or iterators, the
functions return a LogProb
with negative infinity, corresponding to 0 probability.
use logprob::{LogSumExp, log_sum_exp};
let x = LogProb::from_raw_prob(0.5_f64).unwrap();
let y = LogProb::from_raw_prob(0.25).unwrap();
let z = [x,y].iter().log_sum_exp().unwrap();
assert_eq!(z, LogProb::from_raw_prob(0.75).unwrap());
let v = log_sum_exp(&[x,y]).unwrap();
assert_eq!(z, LogProb::from_raw_prob(0.75).unwrap());
By default, the both log_sum_exp
and LogProb::add_log_prob
return a
ProbabilitiesSumToGreaterThanOne
error if the sum is overflows what is a possible
LogProb
value. However, one can use either the clamped
or float
versions of these
functions to return either a value clamped at 0.0 or the underlying float value which may be
greater than 0.0.
let x = LogProb::from_raw_prob(0.5_f64).unwrap();
let y = LogProb::from_raw_prob(0.75).unwrap();
let z = [x,y].into_iter().log_sum_exp_clamped();
assert_eq!(z, LogProb::new(0.0).unwrap());
let z = [x,y].into_iter().log_sum_exp_float();
approx::assert_relative_eq!(z, (1.25_f64).ln());
Dependencies
~150KB