use crate::semiring::Semiring;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MinPlus {
Inf,
Fin(i64),
}
impl Semiring for MinPlus {
fn zero() -> Self {
MinPlus::Inf
}
fn one() -> Self {
MinPlus::Fin(0)
}
fn add(&self, other: &Self) -> Self {
match (self, other) {
(MinPlus::Inf, x) | (x, MinPlus::Inf) => *x,
(MinPlus::Fin(a), MinPlus::Fin(b)) => MinPlus::Fin((*a).min(*b)),
}
}
fn mul(&self, other: &Self) -> Self {
match (self, other) {
(MinPlus::Inf, _) | (_, MinPlus::Inf) => MinPlus::Inf,
(MinPlus::Fin(a), MinPlus::Fin(b)) => MinPlus::Fin(a.saturating_add(*b)),
}
}
fn is_zero(&self) -> bool {
matches!(self, MinPlus::Inf)
}
fn star(&self) -> Option<Self> {
match self {
MinPlus::Inf => Some(MinPlus::Fin(0)),
MinPlus::Fin(a) if *a >= 0 => Some(MinPlus::Fin(0)),
MinPlus::Fin(_) => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::semiring::laws::assert_semiring_laws;
#[test]
fn laws_hold() {
assert_semiring_laws(&[
MinPlus::Inf,
MinPlus::Fin(0),
MinPlus::Fin(2),
MinPlus::Fin(5),
]);
}
#[test]
fn star_behaviour() {
assert_eq!(MinPlus::Inf.star(), Some(MinPlus::Fin(0)));
assert_eq!(MinPlus::Fin(0).star(), Some(MinPlus::Fin(0)));
assert_eq!(MinPlus::Fin(7).star(), Some(MinPlus::Fin(0)));
assert_eq!(MinPlus::Fin(-1).star(), None);
}
}