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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#![warn(missing_docs)]
#![doc = include_str!("../README.md")]

use std::cmp::Ordering::{self, *};

use sealed::sealed;
pub use {cc_traits, variadics};

/// Module for definiting algebraic structures and properties.
pub mod algebra;
pub mod collections;
mod conflict;
mod dom_pair;
pub mod ght;
pub mod map_union;
pub mod map_union_with_tombstones;
mod ord;
mod pair;
mod point;
pub mod semiring_application;
pub mod set_union;
pub mod set_union_with_tombstones;
pub mod test;
pub mod union_find;
mod unit;
mod vec_union;
mod with_bot;
mod with_top;

pub use conflict::Conflict;
pub use dom_pair::DomPair;
pub use lattices_macro::*;
pub use ord::{Max, Min};
pub use pair::{Pair, PairBimorphism};
pub use point::Point;
pub use vec_union::VecUnion;
pub use with_bot::WithBot;
pub use with_top::WithTop;

/// Alias trait for lattice types.
#[sealed]
pub trait Lattice: Sized + Merge<Self> + LatticeOrd + NaiveLatticeOrd + IsBot + IsTop {}
#[sealed]
impl<T> Lattice for T where T: Sized + Merge<Self> + LatticeOrd + NaiveLatticeOrd + IsBot + IsTop {}

/// Alias trait for semirings.
#[sealed]
pub trait Semiring<T>: Addition<T> + Multiplication<T> + Zero<T> + One<T> {}

/// Trait for Semiring Addition.
pub trait Addition<Other> {
    /// Add-assign `other` into self.
    fn add(&mut self, other: Self);

    /// Add `this` and `delta` together, returning the new value.
    fn add_owned(mut self, other: Self) -> Self
    where
        Self: Sized,
    {
        self.add(other);
        self
    }
}

/// Trait for Semiring Multiplication.
pub trait Multiplication<Other> {
    /// Multiply-assign `other` into self.
    fn mul(&mut self, other: Self);

    /// Multiply `this` and `delta` together, returning the new value.
    fn mul_owned(mut self, other: Self) -> Self
    where
        Self: Sized,
    {
        self.mul(other);
        self
    }
}

/// Trait to check if semiring contains a zero.
pub trait Zero<T> {
    /// Returns the zero element of the semiring. Identify for the Addition operation.
    fn zero(&self) -> T;
}

/// Trait to define a one in a semiring.
pub trait One<T> {
    /// Returns the one element of the semiring. Identity for the multiplication operation.
    fn one(&self) -> T;
}
/// Trait for lattice merge (AKA "join" or "least upper bound").
pub trait Merge<Other> {
    /// Merge `other` into the `self` lattice.
    ///
    /// This operation must be associative, commutative, and idempotent.
    ///
    /// Returns `true` if `self` changed, `false` otherwise.
    /// Returning `true` implies that the new value for `self` is later in the lattice order than
    /// the old value. Returning `false` means that `self` was unchanged and therefore `other` came
    /// before `self` (or the two are equal) in the lattice order.
    fn merge(&mut self, other: Other) -> bool;

    /// Merge `this` and `delta` together, returning the new value.
    fn merge_owned(mut this: Self, delta: Other) -> Self
    where
        Self: Sized,
    {
        Self::merge(&mut this, delta);
        this
    }
}

/// Trait for lattice partial order comparison
/// PartialOrd is implemented for many things, this trait can be used to require the type be a lattice.
pub trait LatticeOrd<Rhs = Self>: PartialOrd<Rhs> {}

/// Naive lattice compare, based on the [`Merge::merge`] function.
#[sealed]
pub trait NaiveLatticeOrd<Rhs = Self>
where
    Self: Clone + Merge<Rhs> + Sized,
    Rhs: Clone + Merge<Self>,
{
    /// Naive compare based on the [`Merge::merge`] method. This method can be very inefficient;
    /// use [`PartialOrd::partial_cmp`] instead.
    ///
    /// This method should not be overridden.
    fn naive_cmp(&self, other: &Rhs) -> Option<Ordering> {
        let mut self_a = self.clone();
        let other_a = other.clone();
        let self_b = self.clone();
        let mut other_b = other.clone();
        match (self_a.merge(other_a), other_b.merge(self_b)) {
            (true, true) => None,
            (true, false) => Some(Less),
            (false, true) => Some(Greater),
            (false, false) => Some(Equal),
        }
    }
}
#[sealed]
impl<This, Other> NaiveLatticeOrd<Other> for This
where
    Self: Clone + Merge<Other>,
    Other: Clone + Merge<Self>,
{
}

/// Same as `From` but for lattices.
///
/// This should only be implemented between different representations of the same lattice type.
/// This should recursively convert nested lattice types, but not non-lattice ("scalar") types.
pub trait LatticeFrom<Other> {
    /// Convert from the `Other` lattice into `Self`.
    fn lattice_from(other: Other) -> Self;
}

/// Trait to check if a lattice instance is bottom (⊥).
pub trait IsBot {
    /// Returns if `self` is lattice bottom (⊥).
    ///
    /// Must be consistent with equality, any element equal to bottom is also considered to be bottom.
    fn is_bot(&self) -> bool;
}

/// Trait to check if a lattice instance is top (⊤) and therefore cannot change any futher.
pub trait IsTop {
    /// Returns if `self` is lattice top (⊤).
    ///
    /// Must be consistent with equality, any element equal to top is also considered to be top.
    fn is_top(&self) -> bool;
}

/// Trait to atomize a lattice into individual elements. For example, a [`set_union::SetUnion`]
/// will be broken up into individual singleton elements.
///
/// Formally, breaks up `Self` into an set of lattice points forming a (strong) [antichain](https://en.wikipedia.org/wiki/Antichain).
/// "Strong" in the sense that any pair of lattice points in the antichain should have a greatest
/// lower bound (GLB or "meet") of bottom.
pub trait Atomize: Merge<Self::Atom> {
    /// The type of atoms for this lattice.
    type Atom: 'static + IsBot;

    /// The iter type iterating the antichain atoms.
    type AtomIter: 'static + Iterator<Item = Self::Atom>;

    /// Atomize self: convert into an iter of atoms.
    ///
    /// The returned iterator should be empty if and only if `self.is_bot()` is true.
    /// All atoms in the returned iterator should have `self.is_bot()` be false.
    ///
    /// Returned values must merge to reform a value equal to the original `self`.
    fn atomize(self) -> Self::AtomIter;
}

/// Trait for recursively revealing the underlying types within lattice types.
pub trait DeepReveal {
    /// The underlying type when revealed.
    type Revealed;

    /// Reveals the underlying lattice types recursively.
    fn deep_reveal(self) -> Self::Revealed;
}

/// Semilattice morphism. Lattice merge must distribute over this unary function.
///
/// Use [`crate::test::check_lattice_morphism`] to spot-test an implementation.
///
/// See the [lattice math doc's lattice morphism section](https://hydro.run/docs/hydroflow/lattices_crate/lattice_math/#lattice-morphism).
pub trait LatticeMorphism<LatIn> {
    /// The output lattice type.
    type Output;
    /// Executes the function.
    fn call(&mut self, lat_in: LatIn) -> Self::Output;
}

/// Semilattice bimorphism. Lattice merge must distribute over this binary function, in both arguments.
///
/// Use [`crate::test::check_lattice_bimorphism`] to spot-test an implementation.
///
/// See the [lattice math doc's lattice bimorphism section](https://hydro.run/docs/hydroflow/lattices_crate/lattice_math/#lattice-bimorphism).
pub trait LatticeBimorphism<LatA, LatB> {
    /// The output lattice type.
    type Output;
    /// Executes the function.
    fn call(&mut self, lat_a: LatA, lat_b: LatB) -> Self::Output;
}

/// Converts a closure to a morphism. Does not check for correctness.
pub fn closure_to_morphism<LatIn, LatOut, F>(
    func: F,
) -> impl LatticeMorphism<LatIn, Output = LatOut>
where
    F: FnMut(LatIn) -> LatOut,
{
    struct FnMorphism<F>(F);
    impl<F, LatIn, LatOut> LatticeMorphism<LatIn> for FnMorphism<F>
    where
        F: FnMut(LatIn) -> LatOut,
    {
        type Output = LatOut;

        fn call(&mut self, lat_in: LatIn) -> Self::Output {
            (self.0)(lat_in)
        }
    }
    FnMorphism(func)
}

/// Converts a closure to a bimorphism. Does not check for correctness.
pub fn closure_to_bimorphism<LatA, LatB, LatOut, F>(
    func: F,
) -> impl LatticeBimorphism<LatA, LatB, Output = LatOut>
where
    F: FnMut(LatA, LatB) -> LatOut,
{
    struct FnBimorphism<F>(F);
    impl<F, LatA, LatB, LatOut> LatticeBimorphism<LatA, LatB> for FnBimorphism<F>
    where
        F: FnMut(LatA, LatB) -> LatOut,
    {
        type Output = LatOut;

        fn call(&mut self, lat_a: LatA, lat_b: LatB) -> Self::Output {
            (self.0)(lat_a, lat_b)
        }
    }
    FnBimorphism(func)
}