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
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

mod merge;
pub use merge::merge_neighbours_with_same_class;

/// An interval represents a mapping from a range of values of type `A`, to a class, `C`.
///
/// # Examples
///
/// ```
/// use oner_quantize::Interval;
/// let interval = Interval::lower(100, "true");
/// assert_eq!(interval.matches(25), true);
/// assert_eq!(interval.matches(100), false);
/// assert_eq!(interval.matches(125), false);
/// ```
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Interval<A, C> {
    /// A lower bound, such as `< 100`
    Lower { below: A, class: C },
    /// A half-open exclusive range, such as `>= 100 and < 200` aka `[100,200)`
    Range { from: A, below: A, class: C },
    /// An upper range, such as `>= 200`
    Upper { from: A, class: C },
    /// The interval that covers all values
    Infinite { class: C },
}

impl<A, C> Interval<A, C>
where
    A: PartialOrd + Copy,
    C: Copy,
{
    pub fn lower(below: A, class: C) -> Self {
        Interval::Lower { below, class }
    }

    pub fn range(from: A, below: A, class: C) -> Self {
        Interval::Range { from, below, class }
    }

    pub fn upper(from: A, class: C) -> Self {
        Interval::Upper { from, class }
    }

    /// Does the given `value` fall inside this interval?
    pub fn matches(&self, value: A) -> bool {
        match self {
            Interval::Lower { below, .. } => value < *below,
            Interval::Range { from, below, .. } => value >= *from && value < *below,
            Interval::Upper { from, .. } => value >= *from,
            Interval::Infinite { .. } => true,
        }
    }

    /// The class that this interval predicts.
    pub fn class(&self) -> &C {
        match self {
            Interval::Lower { class, .. } => class,
            Interval::Range { class, .. } => class,
            Interval::Upper { class, .. } => class,
            Interval::Infinite { class } => class,
        }
    }
}