lattices/lib.rs
1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4use std::cmp::Ordering::{self, *};
5
6use sealed::sealed;
7pub use {cc_traits, variadics};
8
9/// Module for definiting algebraic structures and properties.
10pub mod algebra;
11pub mod collections;
12mod conflict;
13mod dom_pair;
14pub mod ght;
15pub mod map_union;
16pub mod map_union_with_tombstones;
17mod ord;
18mod pair;
19mod point;
20pub mod semiring_application;
21pub mod set_union;
22pub mod set_union_with_tombstones;
23pub mod test;
24pub mod union_find;
25mod unit;
26mod vec_union;
27mod with_bot;
28mod with_top;
29
30pub use conflict::Conflict;
31pub use dom_pair::DomPair;
32pub use lattices_macro::*;
33pub use ord::{Max, Min};
34pub use pair::{Pair, PairBimorphism};
35pub use point::Point;
36pub use vec_union::VecUnion;
37pub use with_bot::WithBot;
38pub use with_top::WithTop;
39
40/// Alias trait for lattice types.
41#[sealed]
42pub trait Lattice: Sized + Merge<Self> + LatticeOrd + NaiveLatticeOrd + IsBot + IsTop {}
43#[sealed]
44impl<T> Lattice for T where T: Sized + Merge<Self> + LatticeOrd + NaiveLatticeOrd + IsBot + IsTop {}
45
46/// Alias trait for semirings.
47#[sealed]
48pub trait Semiring<T>: Addition<T> + Multiplication<T> + Zero<T> + One<T> {}
49
50/// Trait for Semiring Addition.
51pub trait Addition<Other> {
52 /// Add-assign `other` into self.
53 fn add(&mut self, other: Self);
54
55 /// Add `this` and `delta` together, returning the new value.
56 fn add_owned(mut self, other: Self) -> Self
57 where
58 Self: Sized,
59 {
60 self.add(other);
61 self
62 }
63}
64
65/// Trait for Semiring Multiplication.
66pub trait Multiplication<Other> {
67 /// Multiply-assign `other` into self.
68 fn mul(&mut self, other: Self);
69
70 /// Multiply `this` and `delta` together, returning the new value.
71 fn mul_owned(mut self, other: Self) -> Self
72 where
73 Self: Sized,
74 {
75 self.mul(other);
76 self
77 }
78}
79
80/// Trait to check if semiring contains a zero.
81pub trait Zero<T> {
82 /// Returns the zero element of the semiring. Identify for the Addition operation.
83 fn zero(&self) -> T;
84}
85
86/// Trait to define a one in a semiring.
87pub trait One<T> {
88 /// Returns the one element of the semiring. Identity for the multiplication operation.
89 fn one(&self) -> T;
90}
91/// Trait for lattice merge (AKA "join" or "least upper bound").
92pub trait Merge<Other> {
93 /// Merge `other` into the `self` lattice.
94 ///
95 /// This operation must be associative, commutative, and idempotent.
96 ///
97 /// Returns `true` if `self` changed, `false` otherwise.
98 /// Returning `true` implies that the new value for `self` is later in the lattice order than
99 /// the old value. Returning `false` means that `self` was unchanged and therefore `other` came
100 /// before `self` (or the two are equal) in the lattice order.
101 fn merge(&mut self, other: Other) -> bool;
102
103 /// Merge `this` and `delta` together, returning the new value.
104 fn merge_owned(mut this: Self, delta: Other) -> Self
105 where
106 Self: Sized,
107 {
108 Self::merge(&mut this, delta);
109 this
110 }
111}
112
113/// Trait for lattice partial order comparison
114/// PartialOrd is implemented for many things, this trait can be used to require the type be a lattice.
115pub trait LatticeOrd<Rhs = Self>: PartialOrd<Rhs> {}
116
117/// Naive lattice compare, based on the [`Merge::merge`] function.
118#[sealed]
119pub trait NaiveLatticeOrd<Rhs = Self>
120where
121 Self: Clone + Merge<Rhs> + Sized,
122 Rhs: Clone + Merge<Self>,
123{
124 /// Naive compare based on the [`Merge::merge`] method. This method can be very inefficient;
125 /// use [`PartialOrd::partial_cmp`] instead.
126 ///
127 /// This method should not be overridden.
128 fn naive_cmp(&self, other: &Rhs) -> Option<Ordering> {
129 let mut self_a = self.clone();
130 let other_a = other.clone();
131 let self_b = self.clone();
132 let mut other_b = other.clone();
133 match (self_a.merge(other_a), other_b.merge(self_b)) {
134 (true, true) => None,
135 (true, false) => Some(Less),
136 (false, true) => Some(Greater),
137 (false, false) => Some(Equal),
138 }
139 }
140}
141#[sealed]
142impl<This, Other> NaiveLatticeOrd<Other> for This
143where
144 Self: Clone + Merge<Other>,
145 Other: Clone + Merge<Self>,
146{
147}
148
149/// Same as `From` but for lattices.
150///
151/// This should only be implemented between different representations of the same lattice type.
152/// This should recursively convert nested lattice types, but not non-lattice ("scalar") types.
153pub trait LatticeFrom<Other> {
154 /// Convert from the `Other` lattice into `Self`.
155 fn lattice_from(other: Other) -> Self;
156}
157
158/// Trait to check if a lattice instance is bottom (⊥).
159pub trait IsBot {
160 /// Returns if `self` is lattice bottom (⊥).
161 ///
162 /// Must be consistent with equality, any element equal to bottom is also considered to be bottom.
163 fn is_bot(&self) -> bool;
164}
165
166/// Trait to check if a lattice instance is top (⊤) and therefore cannot change any futher.
167pub trait IsTop {
168 /// Returns if `self` is lattice top (⊤).
169 ///
170 /// Must be consistent with equality, any element equal to top is also considered to be top.
171 fn is_top(&self) -> bool;
172}
173
174/// Trait to atomize a lattice into individual elements. For example, a [`set_union::SetUnion`]
175/// will be broken up into individual singleton elements.
176///
177/// Formally, breaks up `Self` into an set of lattice points forming a (strong) [antichain](https://en.wikipedia.org/wiki/Antichain).
178/// "Strong" in the sense that any pair of lattice points in the antichain should have a greatest
179/// lower bound (GLB or "meet") of bottom.
180pub trait Atomize: Merge<Self::Atom> {
181 /// The type of atoms for this lattice.
182 type Atom: 'static + IsBot;
183
184 /// The iter type iterating the antichain atoms.
185 type AtomIter: 'static + Iterator<Item = Self::Atom>;
186
187 /// Atomize self: convert into an iter of atoms.
188 ///
189 /// The returned iterator should be empty if and only if `self.is_bot()` is true.
190 /// All atoms in the returned iterator should have `self.is_bot()` be false.
191 ///
192 /// Returned values must merge to reform a value equal to the original `self`.
193 fn atomize(self) -> Self::AtomIter;
194}
195
196/// Trait for recursively revealing the underlying types within lattice types.
197pub trait DeepReveal {
198 /// The underlying type when revealed.
199 type Revealed;
200
201 /// Reveals the underlying lattice types recursively.
202 fn deep_reveal(self) -> Self::Revealed;
203}
204
205/// Semilattice morphism. Lattice merge must distribute over this unary function.
206///
207/// Use [`crate::test::check_lattice_morphism`] to spot-test an implementation.
208///
209/// See the [lattice math doc's lattice morphism section](https://hydro.run/docs/dfir/lattices_crate/lattice_math/#lattice-morphism).
210pub trait LatticeMorphism<LatIn> {
211 /// The output lattice type.
212 type Output;
213 /// Executes the function.
214 fn call(&mut self, lat_in: LatIn) -> Self::Output;
215}
216
217/// Semilattice bimorphism. Lattice merge must distribute over this binary function, in both arguments.
218///
219/// Use [`crate::test::check_lattice_bimorphism`] to spot-test an implementation.
220///
221/// See the [lattice math doc's lattice bimorphism section](https://hydro.run/docs/dfir/lattices_crate/lattice_math/#lattice-bimorphism).
222pub trait LatticeBimorphism<LatA, LatB> {
223 /// The output lattice type.
224 type Output;
225 /// Executes the function.
226 fn call(&mut self, lat_a: LatA, lat_b: LatB) -> Self::Output;
227}
228
229/// Converts a closure to a morphism. Does not check for correctness.
230pub fn closure_to_morphism<LatIn, LatOut, F>(
231 func: F,
232) -> impl LatticeMorphism<LatIn, Output = LatOut>
233where
234 F: FnMut(LatIn) -> LatOut,
235{
236 struct FnMorphism<F>(F);
237 impl<F, LatIn, LatOut> LatticeMorphism<LatIn> for FnMorphism<F>
238 where
239 F: FnMut(LatIn) -> LatOut,
240 {
241 type Output = LatOut;
242
243 fn call(&mut self, lat_in: LatIn) -> Self::Output {
244 (self.0)(lat_in)
245 }
246 }
247 FnMorphism(func)
248}
249
250/// Converts a closure to a bimorphism. Does not check for correctness.
251pub fn closure_to_bimorphism<LatA, LatB, LatOut, F>(
252 func: F,
253) -> impl LatticeBimorphism<LatA, LatB, Output = LatOut>
254where
255 F: FnMut(LatA, LatB) -> LatOut,
256{
257 struct FnBimorphism<F>(F);
258 impl<F, LatA, LatB, LatOut> LatticeBimorphism<LatA, LatB> for FnBimorphism<F>
259 where
260 F: FnMut(LatA, LatB) -> LatOut,
261 {
262 type Output = LatOut;
263
264 fn call(&mut self, lat_a: LatA, lat_b: LatB) -> Self::Output {
265 (self.0)(lat_a, lat_b)
266 }
267 }
268 FnBimorphism(func)
269}