use std::{
fmt::{self, Display, Formatter},
iter::Sum,
ops::{Add, Div, Mul, Sub},
};
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Entropy(f64);
impl Entropy {
pub fn zero() -> Self {
Entropy(0.0)
}
pub fn one() -> Self {
Entropy(1.0)
}
pub fn from_bits<F: Into<f64>>(bits: F) -> Self {
Entropy(bits.into())
}
pub fn from_real<F: Into<f64>>(real: F) -> Self {
Entropy(real.into().log2())
}
pub fn bits(self) -> f64 {
self.0
}
}
impl Display for Entropy {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{} bits", self.bits())
}
}
impl Sum for Entropy {
#[inline]
fn sum<I>(iter: I) -> Self
where
I: Iterator,
I::Item: Into<Entropy>,
{
iter.fold(Entropy::zero(), |total, e| total + e.into())
}
}
macro_rules! derive_ops {
(impl $trait_: ident for $type_: ident { fn $method: ident }) => {
impl $trait_<$type_> for $type_ {
type Output = $type_;
#[inline]
fn $method(self, $type_(b): $type_) -> $type_ {
let $type_(a) = self;
$type_(a.$method(&b))
}
}
impl<B> $trait_<B> for $type_
where
B: Into<f64>,
{
type Output = $type_;
#[inline]
fn $method(self, b: B) -> $type_ {
let $type_(a) = self;
$type_(a.$method(&b.into()))
}
}
};
}
derive_ops! { impl Add for Entropy { fn add } }
derive_ops! { impl Sub for Entropy { fn sub } }
derive_ops! { impl Mul for Entropy { fn mul } }
derive_ops! { impl Div for Entropy { fn div } }
pub trait HasEntropy {
fn entropy(&self) -> Entropy;
}