1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
use super::error::BinaryError;
use crate::{Formula, Metric};

pub struct Implies<A, C> {
    antecedent: A,
    consequent: C,
}

impl<A, C> Implies<A, C> {
    pub fn new(antecedent: A, consequent: C) -> Implies<A, C> {
        Implies { antecedent, consequent }
    }
}

impl<T, A, C> Formula<T> for Implies<A, C>
where
    A: Formula<T>,
    C: Formula<T>,
{
    type Error = BinaryError<A::Error, C::Error>;

    fn satisfied_by(&self, value: &T) -> Result<bool, Self::Error> {
        let antecedent = self.antecedent.satisfied_by(value).map_err(BinaryError::Left)?;

        if !antecedent {
            return Ok(true);
        }

        self.consequent.satisfied_by(value).map_err(BinaryError::Right)
    }
}

impl<T, A, C> Metric<T> for Implies<A, C>
where
    A: Metric<T>,
    C: Metric<T>,
{
    type Error = BinaryError<A::Error, C::Error>;

    fn distance(&self, value: &T) -> Result<f64, Self::Error> {
        // This method is derived from operator expansion
        // a -> b === !a \/ b
        // The operators are unrolled explicitly to improve performance

        let ante_dist = self.antecedent.distance(value).map_err(BinaryError::Left)?;
        let cons_dist = self.consequent.distance(value).map_err(BinaryError::Right)?;

        Ok(f64::max(-ante_dist, cons_dist))
    }
}