alga/general/
lattice.rs

1#[cfg(feature = "decimal")]
2use decimal::d128;
3use std::cmp::{Ordering, PartialOrd};
4
5/// A set where every two elements have an infimum (i.e. greatest lower bound).
6pub trait MeetSemilattice: Sized {
7    /// Returns the meet (aka. infimum) of two values.
8    fn meet(&self, other: &Self) -> Self;
9}
10
11/// A set where every two elements have a supremum (i.e. smallest upper bound).
12pub trait JoinSemilattice: Sized {
13    /// Returns the join (aka. supremum) of two values.
14    fn join(&self, other: &Self) -> Self;
15}
16
17/// Partially orderable sets where every two elements have a supremum and infimum.
18pub trait Lattice: MeetSemilattice + JoinSemilattice + PartialOrd {
19    /// Returns the infimum and the supremum simultaneously.
20    #[inline]
21    fn meet_join(&self, other: &Self) -> (Self, Self) {
22        (self.meet(other), self.join(other))
23    }
24
25    /// Return the minimum of `self` and `other` if they are comparable.
26    #[inline]
27    fn partial_min<'a>(&'a self, other: &'a Self) -> Option<&'a Self> {
28        if let Some(ord) = self.partial_cmp(other) {
29            match ord {
30                Ordering::Greater => Some(other),
31                _ => Some(self),
32            }
33        } else {
34            None
35        }
36    }
37
38    /// Return the maximum of `self` and `other` if they are comparable.
39    #[inline]
40    fn partial_max<'a>(&'a self, other: &'a Self) -> Option<&'a Self> {
41        if let Some(ord) = self.partial_cmp(other) {
42            match ord {
43                Ordering::Less => Some(other),
44                _ => Some(self),
45            }
46        } else {
47            None
48        }
49    }
50
51    /// Sorts two values in increasing order using a partial ordering.
52    #[inline]
53    fn partial_sort2<'a>(&'a self, other: &'a Self) -> Option<(&'a Self, &'a Self)> {
54        if let Some(ord) = self.partial_cmp(other) {
55            match ord {
56                Ordering::Less => Some((self, other)),
57                _ => Some((other, self)),
58            }
59        } else {
60            None
61        }
62    }
63
64    /// Clamp `value` between `min` and `max`. Returns `None` if `value` is not comparable to
65    /// `min` or `max`.
66    #[inline]
67    fn partial_clamp<'a>(&'a self, min: &'a Self, max: &'a Self) -> Option<&'a Self> {
68        if let (Some(cmp_min), Some(cmp_max)) = (self.partial_cmp(min), self.partial_cmp(max)) {
69            if cmp_min == Ordering::Less {
70                Some(min)
71            } else if cmp_max == Ordering::Greater {
72                Some(max)
73            } else {
74                Some(self)
75            }
76        } else {
77            None
78        }
79    }
80}
81
82macro_rules! impl_lattice(
83    ($($T:ident),*) => {$(
84        impl MeetSemilattice for $T {
85            #[inline]
86            fn meet(&self, other: &Self) -> Self {
87                if *self <= *other {
88                    *self
89                }
90                else {
91                    *other
92                }
93            }
94        }
95
96        impl JoinSemilattice for $T {
97            #[inline]
98            fn join(&self, other: &Self) -> Self {
99                if *self >= *other {
100                    *self
101                }
102                else {
103                    *other
104                }
105            }
106        }
107
108        impl Lattice for $T {
109            #[inline]
110            fn meet_join(&self, other: &Self) -> (Self, Self) {
111                if *self >= *other {
112                    (*other, *self)
113                }
114                else {
115                    (*self, *other)
116                }
117            }
118        }
119    )*}
120);
121
122impl_lattice!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64);
123#[cfg(feature = "decimal")]
124impl_lattice!(d128);
125
126impl<N: MeetSemilattice> MeetSemilattice for num_complex::Complex<N> {
127    #[inline]
128    fn meet(&self, other: &Self) -> Self {
129        Self {
130            re: self.re.meet(&other.re),
131            im: self.im.meet(&other.im),
132        }
133    }
134}
135
136impl<N: JoinSemilattice> JoinSemilattice for num_complex::Complex<N> {
137    #[inline]
138    fn join(&self, other: &Self) -> Self {
139        Self {
140            re: self.re.join(&other.re),
141            im: self.im.join(&other.im),
142        }
143    }
144}