Skip to main content

oximo_core/
domain.rs

1/// The domain of a variable, which determines the type of values it can take.
2///
3/// Real: any real number.
4/// Integer: any integer.
5/// Binary: 0 or 1.
6/// SemiContinuous: either 0 or any value >= threshold.
7/// SemiInteger: either 0 or any integer >= threshold.
8#[derive(Copy, Clone, Debug, Default, PartialEq)]
9pub enum Domain {
10    #[default]
11    Real,
12    Integer,
13    Binary,
14    SemiContinuous {
15        threshold: f64,
16    },
17    SemiInteger {
18        threshold: f64,
19    },
20}
21
22impl Domain {
23    /// Whether this domain is integer-valued (Integer, Binary, SemiInteger)
24    pub fn is_integer(self) -> bool {
25        matches!(self, Self::Integer | Self::Binary | Self::SemiInteger { .. })
26    }
27
28    /// The semicontinuity gap floor: `Some(threshold)` for `SemiContinuous` /
29    /// `SemiInteger`, `None` otherwise. Such a variable takes either 0 or a
30    /// value `>= threshold`, so backends emit `threshold` as the lower bound.
31    pub fn semi_threshold(self) -> Option<f64> {
32        match self {
33            Self::SemiContinuous { threshold } | Self::SemiInteger { threshold } => Some(threshold),
34            _ => None,
35        }
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::Domain;
42
43    #[test]
44    fn semi_threshold_only_for_semi_domains() {
45        assert_eq!(Domain::Real.semi_threshold(), None);
46        assert_eq!(Domain::Integer.semi_threshold(), None);
47        assert_eq!(Domain::Binary.semi_threshold(), None);
48        assert_eq!(Domain::SemiContinuous { threshold: 2.0 }.semi_threshold(), Some(2.0));
49        assert_eq!(Domain::SemiInteger { threshold: 1.0 }.semi_threshold(), Some(1.0));
50    }
51}