#![warn(missing_docs)]
extern crate num;
use num::Num;
use std::ops;
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
pub struct Probability<T: Num>(pub T);
impl<T: Num + PartialOrd> Probability<T> {
pub fn certain() -> Probability<T> {
Probability(T::one())
}
pub fn never() -> Probability<T> {
Probability(T::zero())
}
pub fn half(self) -> Probability<T> {
Probability(self.check().0 / (T::one() + T::one())).check()
}
pub fn fifty() -> Probability<T> {
Probability::certain().half()
}
pub fn disjointed_or(self, rhs: Probability<T>) -> Probability<T> {
Probability(self.check().0 + rhs.check().0).check()
}
fn check(self) -> Probability<T> {
debug_assert!(self.0 >= Probability::never().0, "Negative probability.");
debug_assert!(self.0 <= Probability::certain().0, "Probability overflow (>1).");
self
}
}
impl<T: Num + PartialOrd> ops::Not for Probability<T> {
type Output = Probability<T>;
fn not(self) -> Probability<T> {
Probability(T::one() - self.check().0).check()
}
}
impl<T: Num + PartialOrd> ops::BitAnd for Probability<T> {
type Output = Probability<T>;
fn bitand(self, rhs: Probability<T>) -> Probability<T> {
Probability(self.check().0 * rhs.check().0).check()
}
}
impl<T: Num + Clone + PartialOrd> ops::BitOr for Probability<T> {
type Output = Probability<T>;
fn bitor(self, rhs: Probability<T>) -> Probability<T> {
Probability(self.clone().check().0 + rhs.clone().check().0.clone() - self.0 * rhs.0).check()
}
}
impl<T: Num + Clone + PartialOrd> ops::BitXor for Probability<T> {
type Output = Probability<T>;
fn bitxor(self, rhs: Probability<T>) -> Probability<T> {
(self.clone().check() & !rhs.clone().check()).disjointed_or(rhs & !self).check()
}
}
#[cfg(test)]
mod tests {
use super::*;
type F32Probability = Probability<f32>;
#[test]
fn and() {
assert_eq!(F32Probability::fifty() & F32Probability::fifty(), F32Probability::fifty().half());
assert_eq!(F32Probability::certain() & F32Probability::certain(), F32Probability::certain());
assert_eq!(F32Probability::never() & F32Probability::certain(), F32Probability::never());
assert_eq!(F32Probability::never() & F32Probability::never(), F32Probability::never());
assert_eq!(F32Probability::fifty() & F32Probability::fifty(), Probability::fifty().half());
}
#[test]
fn or() {
assert_eq!(F32Probability::fifty() | F32Probability::never(), F32Probability::fifty());
assert_eq!(F32Probability::fifty() | F32Probability::never(), F32Probability::fifty());
assert_eq!(F32Probability::never() | F32Probability::never(), F32Probability::never());
assert_eq!(F32Probability::certain() | F32Probability::certain(), F32Probability::certain());
assert_eq!(Probability::fifty() | Probability::fifty(), Probability(0.75));
}
#[test]
fn xor() {
assert_eq!(F32Probability::fifty() ^ F32Probability::never(), F32Probability::fifty());
assert_eq!(F32Probability::fifty() ^ F32Probability::never(), F32Probability::fifty());
assert_eq!(F32Probability::never() ^ F32Probability::never(), F32Probability::never());
assert_eq!(F32Probability::certain() ^ F32Probability::certain(), F32Probability::never());
assert_eq!(F32Probability::certain() ^ F32Probability::never(), F32Probability::certain());
assert_eq!(F32Probability::fifty() ^ F32Probability::fifty(), F32Probability::fifty());
}
#[test]
fn not() {
assert_eq!(!F32Probability::fifty(), F32Probability::fifty());
assert_eq!(!F32Probability::fifty(), F32Probability::fifty());
assert_eq!(!Probability(0.75), Probability::fifty().half());
}
}