logic/operators/
implies.rs

1use super::error::BinaryError;
2use crate::{Formula, Metric};
3
4pub struct Implies<A, C> {
5    antecedent: A,
6    consequent: C,
7}
8
9impl<A, C> Implies<A, C> {
10    pub fn new(antecedent: A, consequent: C) -> Implies<A, C> {
11        Implies { antecedent, consequent }
12    }
13}
14
15impl<T, A, C> Formula<T> for Implies<A, C>
16where
17    A: Formula<T>,
18    C: Formula<T>,
19{
20    type Error = BinaryError<A::Error, C::Error>;
21
22    fn satisfied_by(&self, value: &T) -> Result<bool, Self::Error> {
23        let antecedent = self.antecedent.satisfied_by(value).map_err(BinaryError::Left)?;
24
25        if !antecedent {
26            return Ok(true);
27        }
28
29        self.consequent.satisfied_by(value).map_err(BinaryError::Right)
30    }
31}
32
33impl<T, A, C> Metric<T> for Implies<A, C>
34where
35    A: Metric<T>,
36    C: Metric<T>,
37{
38    type Error = BinaryError<A::Error, C::Error>;
39
40    fn distance(&self, value: &T) -> Result<f64, Self::Error> {
41        // This method is derived from operator expansion
42        // a -> b === !a \/ b
43        // The operators are unrolled explicitly to improve performance
44
45        let ante_dist = self.antecedent.distance(value).map_err(BinaryError::Left)?;
46        let cons_dist = self.consequent.distance(value).map_err(BinaryError::Right)?;
47
48        Ok(f64::max(-ante_dist, cons_dist))
49    }
50}