diff --git a/journal/src/types/dose.rs b/journal/src/types/dose.rs index 312fa09..7c4c37b 100644 --- a/journal/src/types/dose.rs +++ b/journal/src/types/dose.rs @@ -1,5 +1,3 @@ -use std::ops::{Add, Mul}; - use super::Estimation; #[derive(Default, PartialEq, Debug, Clone)] @@ -9,221 +7,5 @@ pub struct Dose { pub estimation: Estimation, } -impl Add for Dose { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - self + &rhs - } -} - -impl Add for &Dose { - type Output = Dose; - - fn add(self, rhs: Self) -> Self::Output { - self.clone() + rhs - } -} - -impl Add for &Dose { - type Output = Dose; - - fn add(self, lhs: Dose) -> Self::Output { - lhs + self - } -} - -impl Add<&Dose> for Dose { - type Output = Self; - - fn add(self, rhs: &Self) -> Self::Output { - let contains_unknown = self.contains_unknown || rhs.contains_unknown; - let estimation = match self.estimation + &rhs.estimation { - Estimation::Precise => { - if contains_unknown { - Estimation::Estimate - } else { - Estimation::Precise - } - } - value => value, - }; - - Dose { - value: self.value + rhs.value, - contains_unknown, - estimation, - } - } -} - -impl Mul for Dose { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - self * &rhs - } -} - -impl Mul for &Dose { - type Output = Dose; - - fn mul(self, rhs: Self) -> Self::Output { - self.clone() * rhs - } -} - -impl Mul for &Dose { - type Output = Dose; - - fn mul(self, lhs: Dose) -> Self::Output { - lhs * self - } -} - -impl Mul<&Dose> for Dose { - type Output = Self; - - fn mul(self, rhs: &Self) -> Self::Output { - let contains_unknown = self.contains_unknown || rhs.contains_unknown; - let estimation = match self.estimation * &rhs.estimation { - Estimation::Precise => { - if contains_unknown { - Estimation::Estimate - } else { - Estimation::Precise - } - } - value => value, - }; - - Dose { - value: self.value * rhs.value, - contains_unknown, - estimation, - } - } -} - -#[cfg(test)] -mod tests { - use super::{Dose, Estimation}; - - #[test] - fn add() { - let lhs = Dose { - value: 10.0, - ..Dose::default() - }; - let rhs = Dose { - value: 10.0, - ..Dose::default() - }; - let result = Dose { - value: 20.0, - ..Dose::default() - }; - - assert_eq!(lhs.clone() + rhs.clone(), result); - assert_eq!(lhs.clone() + &rhs.clone(), result); - assert_eq!(&lhs.clone() + rhs.clone(), result); - assert_eq!(&lhs.clone() + &rhs.clone(), result); - } - - #[test] - fn add_with_estimate() { - assert_eq!( - Dose { - value: 10.0, - ..Dose::default() - } + Dose { - value: 10.0, - estimation: Estimation::Estimate, - ..Dose::default() - }, - Dose { - value: 20.0, - estimation: Estimation::Estimate, - ..Dose::default() - } - ); - } - - #[test] - fn add_with_unknown() { - assert_eq!( - Dose { - value: 10.0, - ..Dose::default() - } + Dose { - value: 10.0, - contains_unknown: true, - ..Dose::default() - }, - Dose { - value: 20.0, - contains_unknown: true, - estimation: Estimation::Estimate - } - ); - } - - #[test] - fn mul() { - let lhs = Dose { - value: 10.0, - ..Dose::default() - }; - let rhs = Dose { - value: 10.0, - ..Dose::default() - }; - let result = Dose { - value: 100.0, - ..Dose::default() - }; - - assert_eq!(lhs.clone() * rhs.clone(), result); - assert_eq!(lhs.clone() * &rhs.clone(), result); - assert_eq!(&lhs.clone() * rhs.clone(), result); - assert_eq!(&lhs.clone() * &rhs.clone(), result); - } - - #[test] - fn mul_with_estimate() { - assert_eq!( - Dose { - value: 10.0, - ..Dose::default() - } * Dose { - value: 10.0, - estimation: Estimation::Estimate, - ..Dose::default() - }, - Dose { - value: 100.0, - estimation: Estimation::Estimate, - ..Dose::default() - } - ); - } - - #[test] - fn mul_with_unknown() { - assert_eq!( - Dose { - value: 10.0, - ..Dose::default() - } * Dose { - value: 10.0, - contains_unknown: true, - ..Dose::default() - }, - Dose { - value: 100.0, - contains_unknown: true, - estimation: Estimation::Estimate - } - ); - } -} +mod add; +mod multiply; diff --git a/journal/src/types/dose/add.rs b/journal/src/types/dose/add.rs new file mode 100644 index 0000000..1d66d4d --- /dev/null +++ b/journal/src/types/dose/add.rs @@ -0,0 +1,115 @@ +use super::{Dose, Estimation}; + +use std::ops::Add; + +impl Add for Dose { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + self + &rhs + } +} + +impl Add for &Dose { + type Output = Dose; + + fn add(self, rhs: Self) -> Self::Output { + self.clone() + rhs + } +} + +impl Add for &Dose { + type Output = Dose; + + fn add(self, lhs: Dose) -> Self::Output { + lhs + self + } +} + +impl Add<&Dose> for Dose { + type Output = Self; + + fn add(self, rhs: &Self) -> Self::Output { + let contains_unknown = self.contains_unknown || rhs.contains_unknown; + let estimation = match self.estimation + &rhs.estimation { + Estimation::Precise => { + if contains_unknown { + Estimation::Estimate + } else { + Estimation::Precise + } + } + value => value, + }; + + Dose { + value: self.value + rhs.value, + contains_unknown, + estimation, + } + } +} + +#[cfg(test)] +mod tests { + use super::{Dose, Estimation}; + + #[test] + fn add() { + let lhs = Dose { + value: 10.0, + ..Dose::default() + }; + let rhs = Dose { + value: 10.0, + ..Dose::default() + }; + let result = Dose { + value: 20.0, + ..Dose::default() + }; + + assert_eq!(lhs.clone() + rhs.clone(), result); + assert_eq!(lhs.clone() + &rhs.clone(), result); + assert_eq!(&lhs.clone() + rhs.clone(), result); + assert_eq!(&lhs.clone() + &rhs.clone(), result); + } + + #[test] + fn add_with_estimate() { + assert_eq!( + Dose { + value: 10.0, + ..Dose::default() + } + Dose { + value: 10.0, + estimation: Estimation::Estimate, + ..Dose::default() + }, + Dose { + value: 20.0, + estimation: Estimation::Estimate, + ..Dose::default() + } + ); + } + + #[test] + fn add_with_unknown() { + assert_eq!( + Dose { + value: 10.0, + ..Dose::default() + } + Dose { + value: 10.0, + contains_unknown: true, + ..Dose::default() + }, + Dose { + value: 20.0, + contains_unknown: true, + estimation: Estimation::Estimate + } + ); + } +} diff --git a/journal/src/types/dose/multiply.rs b/journal/src/types/dose/multiply.rs new file mode 100644 index 0000000..c6acb32 --- /dev/null +++ b/journal/src/types/dose/multiply.rs @@ -0,0 +1,115 @@ +use super::{Dose, Estimation}; + +use std::ops::Mul; + +impl Mul for Dose { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * &rhs + } +} + +impl Mul for &Dose { + type Output = Dose; + + fn mul(self, rhs: Self) -> Self::Output { + self.clone() * rhs + } +} + +impl Mul for &Dose { + type Output = Dose; + + fn mul(self, lhs: Dose) -> Self::Output { + lhs * self + } +} + +impl Mul<&Dose> for Dose { + type Output = Self; + + fn mul(self, rhs: &Self) -> Self::Output { + let contains_unknown = self.contains_unknown || rhs.contains_unknown; + let estimation = match self.estimation * &rhs.estimation { + Estimation::Precise => { + if contains_unknown { + Estimation::Estimate + } else { + Estimation::Precise + } + } + value => value, + }; + + Dose { + value: self.value * rhs.value, + contains_unknown, + estimation, + } + } +} + +#[cfg(test)] +mod tests { + use super::{Dose, Estimation}; + + #[test] + fn mul() { + let lhs = Dose { + value: 10.0, + ..Dose::default() + }; + let rhs = Dose { + value: 10.0, + ..Dose::default() + }; + let result = Dose { + value: 100.0, + ..Dose::default() + }; + + assert_eq!(lhs.clone() * rhs.clone(), result); + assert_eq!(lhs.clone() * &rhs.clone(), result); + assert_eq!(&lhs.clone() * rhs.clone(), result); + assert_eq!(&lhs.clone() * &rhs.clone(), result); + } + + #[test] + fn mul_with_estimate() { + assert_eq!( + Dose { + value: 10.0, + ..Dose::default() + } * Dose { + value: 10.0, + estimation: Estimation::Estimate, + ..Dose::default() + }, + Dose { + value: 100.0, + estimation: Estimation::Estimate, + ..Dose::default() + } + ); + } + + #[test] + fn mul_with_unknown() { + assert_eq!( + Dose { + value: 10.0, + ..Dose::default() + } * Dose { + value: 10.0, + contains_unknown: true, + ..Dose::default() + }, + Dose { + value: 100.0, + contains_unknown: true, + estimation: Estimation::Estimate + } + ); + } +} diff --git a/journal/src/types/estimate.rs b/journal/src/types/estimate.rs index 567d448..04f821a 100644 --- a/journal/src/types/estimate.rs +++ b/journal/src/types/estimate.rs @@ -1,4 +1,3 @@ -use std::ops::{Add, Mul}; #[derive(PartialEq, Debug, Copy, Clone, Default)] pub enum Estimation { @@ -14,159 +13,6 @@ pub struct StandardDeviation { pub deviation: f64, } -impl Estimation { - pub fn is_precise(&self) -> bool { - matches!(self, Estimation::Precise) - } - pub fn is_estimate(&self) -> bool { - !matches!(self, Estimation::Precise) - } - pub fn is_standard_deviation(&self) -> bool { - matches!(self, Estimation::StandardDeviation(_)) - } -} - -impl Add<&Estimation> for Estimation { - type Output = Self; - - fn add(self, rhs: &Self) -> Self::Output { - match (self, rhs) { - (Estimation::StandardDeviation(lhs), Estimation::StandardDeviation(rhs)) => { - Estimation::StandardDeviation(StandardDeviation { - expectation: lhs.expectation + rhs.expectation, - deviation: lhs.deviation + rhs.deviation, - }) - } - (Estimation::StandardDeviation(deviation), _) => { - Estimation::StandardDeviation(deviation) - } - (_, Estimation::StandardDeviation(deviation)) => { - Estimation::StandardDeviation(*deviation) - } - (Estimation::Estimate, _) | (_, Estimation::Estimate) => Estimation::Estimate, - (Estimation::Precise, Estimation::Precise) => Estimation::Precise, - } - } -} - -impl Mul<&Estimation> for Estimation { - type Output = Self; - - fn mul(self, rhs: &Self) -> Self::Output { - match (self, rhs) { - (Estimation::StandardDeviation(lhs), Estimation::StandardDeviation(rhs)) => { - let lhs_sum = lhs.deviation.powi(2) + lhs.expectation.powi(2); - let rhs_sum = rhs.deviation.powi(2) + rhs.expectation.powi(2); - - let expectations = lhs.expectation.powi(2) * rhs.expectation.powi(2); - - let product_variance = (lhs_sum * rhs_sum) - expectations; - - if product_variance > 0.0000001 { - let deviation = product_variance.sqrt(); - let expectation = lhs.expectation * rhs.expectation; - - Estimation::StandardDeviation(StandardDeviation { - expectation, - deviation: deviation.round(), - }) - } else { - Estimation::Estimate - } - } - (Estimation::StandardDeviation(deviation), _) => { - Estimation::StandardDeviation(deviation) - } - (_, Estimation::StandardDeviation(deviation)) => { - Estimation::StandardDeviation(*deviation) - } - (Estimation::Estimate, _) | (_, Estimation::Estimate) => Estimation::Estimate, - (Estimation::Precise, Estimation::Precise) => Estimation::Precise, - } - } -} - -#[cfg(test)] -mod tests { - use super::{Estimation::*, StandardDeviation as Deviation}; - - #[test] - fn is() { - let deviation = StandardDeviation(Deviation::default()); - - assert!(Precise.is_precise()); - assert!(!Precise.is_estimate()); - assert!(!Precise.is_standard_deviation()); - - assert!(!Estimate.is_precise()); - assert!(Estimate.is_estimate()); - assert!(!Estimate.is_standard_deviation()); - - assert!(!deviation.is_precise()); - assert!(deviation.is_estimate()); - assert!(deviation.is_standard_deviation()); - } - - #[test] - fn add() { - let deviation = StandardDeviation(Deviation { - expectation: 10.0, - deviation: 10.0, - }); - - assert_eq!(Precise + &Precise, Precise); - assert_eq!(Precise + &Estimate, Estimate); - assert_eq!(Precise + &deviation, deviation); - - assert_eq!(Estimate + &Precise, Estimate); - assert_eq!(Estimate + &Estimate, Estimate); - assert_eq!(Estimate + &deviation, deviation); - - assert_eq!(deviation + &Precise, deviation); - assert_eq!(deviation + &Estimate, deviation); - assert_eq!( - deviation + &deviation, - StandardDeviation(Deviation { - expectation: 20.0, - deviation: 20.0, - }) - ); - } - - #[test] - fn mul() { - let deviation = StandardDeviation(Deviation { - expectation: 10.0, - deviation: 10.0, - }); - - assert_eq!(Precise * &Precise, Precise); - assert_eq!(Precise * &Estimate, Estimate); - assert_eq!(Precise * &deviation, deviation); - - assert_eq!(Estimate * &Precise, Estimate); - assert_eq!(Estimate * &Estimate, Estimate); - assert_eq!(Estimate * &deviation, deviation); - - assert_eq!(deviation * &Precise, deviation); - assert_eq!(deviation * &Estimate, deviation); - assert_eq!( - deviation * &deviation, - StandardDeviation(Deviation { - expectation: 100.0, - deviation: 173.0, - }) - ); - - assert_eq!( - StandardDeviation(Deviation { - expectation: 100.0, - deviation: 0.0, - }) * &StandardDeviation(Deviation { - expectation: 100.0, - deviation: 0.0, - }), - Estimate - ) - } -} +mod add; +mod multiply; +mod is; diff --git a/journal/src/types/estimate/add.rs b/journal/src/types/estimate/add.rs new file mode 100644 index 0000000..f804fdc --- /dev/null +++ b/journal/src/types/estimate/add.rs @@ -0,0 +1,57 @@ +use std::ops::Add; + +use super::{Estimation, StandardDeviation}; + +impl Add<&Estimation> for Estimation { + type Output = Self; + + fn add(self, rhs: &Self) -> Self::Output { + match (self, rhs) { + (Estimation::StandardDeviation(lhs), Estimation::StandardDeviation(rhs)) => { + Estimation::StandardDeviation(StandardDeviation { + expectation: lhs.expectation + rhs.expectation, + deviation: lhs.deviation + rhs.deviation, + }) + } + (Estimation::StandardDeviation(deviation), _) => { + Estimation::StandardDeviation(deviation) + } + (_, Estimation::StandardDeviation(deviation)) => { + Estimation::StandardDeviation(*deviation) + } + (Estimation::Estimate, _) | (_, Estimation::Estimate) => Estimation::Estimate, + (Estimation::Precise, Estimation::Precise) => Estimation::Precise, + } + } +} + +#[cfg(test)] +mod tests { + use super::{Estimation::*, StandardDeviation as Deviation}; + + #[test] + fn add() { + let deviation = StandardDeviation(Deviation { + expectation: 10.0, + deviation: 10.0, + }); + + assert_eq!(Precise + &Precise, Precise); + assert_eq!(Precise + &Estimate, Estimate); + assert_eq!(Precise + &deviation, deviation); + + assert_eq!(Estimate + &Precise, Estimate); + assert_eq!(Estimate + &Estimate, Estimate); + assert_eq!(Estimate + &deviation, deviation); + + assert_eq!(deviation + &Precise, deviation); + assert_eq!(deviation + &Estimate, deviation); + assert_eq!( + deviation + &deviation, + StandardDeviation(Deviation { + expectation: 20.0, + deviation: 20.0, + }) + ); + } +} diff --git a/journal/src/types/estimate/is.rs b/journal/src/types/estimate/is.rs new file mode 100644 index 0000000..45cb8f1 --- /dev/null +++ b/journal/src/types/estimate/is.rs @@ -0,0 +1,36 @@ +use super::Estimation; + +impl Estimation { + pub fn is_precise(&self) -> bool { + matches!(self, Estimation::Precise) + } + pub fn is_estimate(&self) -> bool { + !matches!(self, Estimation::Precise) + } + pub fn is_standard_deviation(&self) -> bool { + matches!(self, Estimation::StandardDeviation(_)) + } +} + +#[cfg(test)] +mod tests { + use super::Estimation::*; + use crate::types::StandardDeviation as Deviation; + + #[test] + fn is() { + let deviation = StandardDeviation(Deviation::default()); + + assert!(Precise.is_precise()); + assert!(!Precise.is_estimate()); + assert!(!Precise.is_standard_deviation()); + + assert!(!Estimate.is_precise()); + assert!(Estimate.is_estimate()); + assert!(!Estimate.is_standard_deviation()); + + assert!(!deviation.is_precise()); + assert!(deviation.is_estimate()); + assert!(deviation.is_standard_deviation()); + } +} diff --git a/journal/src/types/estimate/multiply.rs b/journal/src/types/estimate/multiply.rs new file mode 100644 index 0000000..dd9187b --- /dev/null +++ b/journal/src/types/estimate/multiply.rs @@ -0,0 +1,82 @@ +use std::ops::Mul; + +use super::{Estimation, StandardDeviation}; + +impl Mul<&Estimation> for Estimation { + type Output = Self; + + fn mul(self, rhs: &Self) -> Self::Output { + match (self, rhs) { + (Estimation::StandardDeviation(lhs), Estimation::StandardDeviation(rhs)) => { + let lhs_sum = lhs.deviation.powi(2) + lhs.expectation.powi(2); + let rhs_sum = rhs.deviation.powi(2) + rhs.expectation.powi(2); + + let expectations = lhs.expectation.powi(2) * rhs.expectation.powi(2); + + let product_variance = (lhs_sum * rhs_sum) - expectations; + + if product_variance > 0.0000001 { + let deviation = product_variance.sqrt(); + let expectation = lhs.expectation * rhs.expectation; + + Estimation::StandardDeviation(StandardDeviation { + expectation, + deviation: deviation.round(), + }) + } else { + Estimation::Estimate + } + } + (Estimation::StandardDeviation(deviation), _) => { + Estimation::StandardDeviation(deviation) + } + (_, Estimation::StandardDeviation(deviation)) => { + Estimation::StandardDeviation(*deviation) + } + (Estimation::Estimate, _) | (_, Estimation::Estimate) => Estimation::Estimate, + (Estimation::Precise, Estimation::Precise) => Estimation::Precise, + } + } +} + +#[cfg(test)] +mod tests { + use super::{Estimation::*, StandardDeviation as Deviation}; + + #[test] + fn multiply() { + let deviation = StandardDeviation(Deviation { + expectation: 10.0, + deviation: 10.0, + }); + + assert_eq!(Precise * &Precise, Precise); + assert_eq!(Precise * &Estimate, Estimate); + assert_eq!(Precise * &deviation, deviation); + + assert_eq!(Estimate * &Precise, Estimate); + assert_eq!(Estimate * &Estimate, Estimate); + assert_eq!(Estimate * &deviation, deviation); + + assert_eq!(deviation * &Precise, deviation); + assert_eq!(deviation * &Estimate, deviation); + assert_eq!( + deviation * &deviation, + StandardDeviation(Deviation { + expectation: 100.0, + deviation: 173.0, + }) + ); + + assert_eq!( + StandardDeviation(Deviation { + expectation: 100.0, + deviation: 0.0, + }) * &StandardDeviation(Deviation { + expectation: 100.0, + deviation: 0.0, + }), + Estimate + ) + } +}