use crate::domain::Qualitative;
use crate::fuzzy::membership::Trapezoidal;
use crate::valuation::Linguistic;
use crate::Valuation;
use std::fmt::{Display, Formatter};
#[derive(Debug, PartialEq)]
pub struct Unified<'domain> {
domain: &'domain Qualitative<Trapezoidal>,
measures: Vec<f32>,
}
#[derive(Debug, PartialEq)]
pub enum UnifiedError<'domain> {
NonBLTSDomain {
domain: &'domain Qualitative<Trapezoidal>,
},
InvalidMeasures {
domain: &'domain Qualitative<Trapezoidal>,
measures: Vec<f32>,
},
InvalidMeasureValue { measure: f32 },
}
impl<'domain> Display for UnifiedError<'domain> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
use UnifiedError::*;
match &self {
NonBLTSDomain { domain } => {
write!(f, "Domain {} is not a BLTS domain.", domain)
}
InvalidMeasures { domain, measures } => {
write!(
f,
"Invalid number of measures. #(measures) = {} != {} = domain cardinality.",
measures.len(),
domain.cardinality()
)
}
InvalidMeasureValue { measure } => {
write!(
f,
"Invalid measure value '{:.2}'. Value should be in range == [-0.0, 0.1].",
measure
)
}
}
}
}
impl<'domain> Linguistic for Unified<'domain> {}
impl<'domain> Valuation for Unified<'domain> {}
impl<'domain> Unified<'domain> {
pub fn new(
domain: &'domain Qualitative<Trapezoidal>,
measures: Vec<f32>,
) -> Result<Self, UnifiedError<'domain>> {
use UnifiedError::*;
if !domain.is_blts() {
Err(NonBLTSDomain { domain })
} else if measures.len() != domain.cardinality() {
Err(InvalidMeasures { domain, measures })
} else {
for measure in &measures {
if *measure < 0. || *measure > 1. {
return Err(InvalidMeasureValue { measure: *measure });
}
}
Ok(Self { domain, measures })
}
}
pub fn measures(&self) -> &Vec<f32> {
&self.measures
}
pub fn domain(&self) -> &'domain Qualitative<Trapezoidal> {
self.domain
}
pub fn chi(&self) -> f32 {
let mut numerator = 0.;
let mut denominator = 0.;
for (index, measure) in self.measures.iter().enumerate() {
numerator += *measure * index as f32;
denominator += *measure;
}
if denominator > 0. {
numerator / denominator
} else {
0.
}
}
pub fn neg(&self) -> Self {
Self {
domain: self.domain,
measures: self.measures.iter().copied().rev().collect(),
}
}
}