#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Confidence {
TwoSided(f64),
UpperOneSided(f64),
LowerOneSided(f64),
}
impl Confidence {
pub fn new(confidence: f64) -> Self {
Self::new_two_sided(confidence)
}
pub fn new_two_sided(confidence: f64) -> Self {
if confidence > 0. && confidence < 1. {
Confidence::TwoSided(confidence)
} else {
panic!("Confidence level must be in the range (0, 1).")
}
}
pub fn new_upper(confidence: f64) -> Self {
if confidence > 0. && confidence < 1. {
Confidence::UpperOneSided(confidence)
} else {
panic!("Confidence level must be in the range (0, 1).")
}
}
pub fn new_lower(confidence: f64) -> Self {
if confidence > 0. && confidence < 1. {
Confidence::LowerOneSided(confidence)
} else {
panic!("Confidence level must be in the range (0, 1).")
}
}
pub fn level(&self) -> f64 {
match self {
Confidence::TwoSided(confidence)
| Confidence::UpperOneSided(confidence)
| Confidence::LowerOneSided(confidence) => *confidence,
}
}
pub fn percent(&self) -> f64 {
self.level() * 100.
}
pub fn kind(&self) -> &'static str {
match self {
Confidence::TwoSided(_) => "two-sided",
Confidence::UpperOneSided(_) => "upper one-sided",
Confidence::LowerOneSided(_) => "lower one-sided",
}
}
pub fn is_two_sided(&self) -> bool {
matches!(self, Confidence::TwoSided(_))
}
pub fn is_one_sided(&self) -> bool {
!self.is_two_sided()
}
pub fn is_upper(&self) -> bool {
matches!(self, Confidence::UpperOneSided(_))
}
pub fn is_lower(&self) -> bool {
matches!(self, Confidence::LowerOneSided(_))
}
pub fn flipped(&self) -> Self {
match self {
Confidence::TwoSided(_) => *self,
Confidence::UpperOneSided(confidence) => Confidence::LowerOneSided(*confidence),
Confidence::LowerOneSided(confidence) => Confidence::UpperOneSided(*confidence),
}
}
pub(crate) fn quantile(&self) -> f64 {
match self {
Confidence::TwoSided(confidence) => 1. - (1. - confidence) / 2.,
Confidence::UpperOneSided(confidence) | Confidence::LowerOneSided(confidence) => {
*confidence
}
}
}
}
impl Default for Confidence {
fn default() -> Self {
Confidence::new_two_sided(0.95)
}
}
impl PartialOrd for Confidence {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self, other) {
(Confidence::TwoSided(x), Confidence::TwoSided(y))
| (Confidence::UpperOneSided(x), Confidence::UpperOneSided(y))
| (Confidence::LowerOneSided(x), Confidence::LowerOneSided(y)) => x.partial_cmp(y),
_ => None,
}
}
}
use crate::error::CIError;
impl TryFrom<f64> for Confidence {
type Error = CIError;
fn try_from(confidence: f64) -> Result<Self, Self::Error> {
if confidence > 0. && confidence < 1. {
Ok(Confidence::new_two_sided(confidence))
} else {
Err(CIError::InvalidConfidenceLevel(confidence))
}
}
}
impl TryFrom<f32> for Confidence {
type Error = CIError;
fn try_from(confidence: f32) -> Result<Self, Self::Error> {
Confidence::try_from(confidence as f64)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ordering() {
let two_sided = Confidence::new_two_sided(0.95);
let upper = Confidence::new_upper(0.95);
let lower = Confidence::new_lower(0.95);
assert!(!(two_sided > upper));
assert!(!(two_sided < upper));
assert!(!(two_sided > lower));
assert!(!(two_sided < lower));
assert!(!(lower > upper));
assert!(!(lower < upper));
assert!(two_sided < Confidence::new_two_sided(0.99));
assert!(two_sided > Confidence::new_two_sided(0.9));
assert!(upper < Confidence::new_upper(0.99));
assert!(upper > Confidence::new_upper(0.9));
assert!(lower < Confidence::new_lower(0.99));
assert!(lower > Confidence::new_lower(0.9));
assert_eq!(two_sided, Confidence::new_two_sided(0.95));
assert_eq!(upper, Confidence::new_upper(0.95));
assert_eq!(lower, Confidence::new_lower(0.95));
}
#[test]
fn test_quantile() {
let two_sided = Confidence::new_two_sided(0.95);
let upper = Confidence::new_upper(0.95);
let lower = Confidence::new_lower(0.95);
assert_eq!(two_sided.quantile(), 0.975);
assert_eq!(upper.quantile(), 0.95);
assert_eq!(lower.quantile(), 0.95);
}
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Confidence>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Confidence>();
}
#[test]
#[should_panic]
fn test_invalid_two_sided_confidence_level_zero() {
Confidence::new_two_sided(0.);
}
#[test]
#[should_panic]
fn test_invalid_two_sided_confidence_level_one() {
Confidence::new_two_sided(1.);
}
#[test]
#[should_panic]
fn test_invalid_upper_confidence_level_zero() {
Confidence::new_upper(0.);
}
#[test]
#[should_panic]
fn test_invalid_upper_confidence_level_one() {
Confidence::new_upper(1.);
}
#[test]
#[should_panic]
fn test_invalid_lower_confidence_level_zero() {
Confidence::new_lower(0.);
}
#[test]
#[should_panic]
fn test_invalid_lower_confidence_level_one() {
Confidence::new_lower(1.);
}
}