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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use super::Bounds;
use crate::trace::Trace;
use crate::{Formula, Metric};

pub struct Always<P> {
    phi: P,
    bounds: Option<Bounds>,
}

impl<P> Always<P> {
    pub fn new(phi: P) -> Always<P> {
        Always { phi, bounds: None }
    }

    pub fn new_bounded<B: Into<Bounds>>(phi: P, bounds: B) -> Self {
        Self {
            phi,
            bounds: Some(bounds.into()),
        }
    }
}

impl<T, P> Formula<Trace<T>> for Always<P>
where
    P: Formula<Trace<T>>,
{
    type Error = P::Error;

    fn satisfied_by(&self, trace: &Trace<T>) -> Result<bool, Self::Error> {
        let mut bounded_trace = trace.clone();

        if let Some(bounds) = &self.bounds {
            bounded_trace.retain_between(bounds.lower.into_inner(), bounds.upper.into_inner());
        }

        let subtraces = bounded_trace.into_subtraces();

        for subtrace in subtraces {
            let result = self.phi.satisfied_by(&subtrace)?;

            if !result {
                return Ok(false);
            }
        }

        Ok(true)
    }
}

impl<T, P> Metric<Trace<T>> for Always<P>
where
    P: Metric<Trace<T>>,
{
    type Error = P::Error;

    fn distance(&self, trace: &Trace<T>) -> Result<f64, Self::Error> {
        let mut bounded_trace = trace.clone();

        if let Some(bounds) = &self.bounds {
            bounded_trace.retain_between(bounds.lower.into_inner(), bounds.upper.into_inner());
        }

        let subtraces = bounded_trace.into_subtraces();
        let mut min_dist = f64::INFINITY;

        for subtrace in subtraces {
            let dist = self.phi.distance(&subtrace)?;
            min_dist = f64::min(dist, min_dist);
        }

        Ok(min_dist)
    }
}