Skip to main content

oxilean_std/order/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4use super::functions::*;
5
6/// Representation of a Galois connection between two posets.
7///
8/// A Galois connection is a pair of monotone maps `(l : A → B, u : B → A)`
9/// satisfying: `l(a) ≤ b ↔ a ≤ u(b)`.
10#[allow(dead_code)]
11pub struct GaloisConnection<A, B> {
12    /// Left adjoint (lower adjoint).
13    pub lower: Box<dyn Fn(A) -> B>,
14    /// Right adjoint (upper adjoint).
15    pub upper: Box<dyn Fn(B) -> A>,
16}
17#[allow(dead_code)]
18impl<A: Clone, B: Clone> GaloisConnection<A, B> {
19    /// Create a new Galois connection from the adjoint pair.
20    pub fn new(lower: impl Fn(A) -> B + 'static, upper: impl Fn(B) -> A + 'static) -> Self {
21        Self {
22            lower: Box::new(lower),
23            upper: Box::new(upper),
24        }
25    }
26    /// Apply the lower adjoint.
27    pub fn apply_lower(&self, a: A) -> B {
28        (self.lower)(a)
29    }
30    /// Apply the upper adjoint.
31    pub fn apply_upper(&self, b: B) -> A {
32        (self.upper)(b)
33    }
34    /// Verify the Galois connection condition on concrete elements given
35    /// order predicates for both sides.
36    pub fn verify(
37        &self,
38        a: A,
39        b: B,
40        le_a: impl Fn(&A, &A) -> bool,
41        le_b: impl Fn(&B, &B) -> bool,
42    ) -> bool {
43        let la = (self.lower)(a.clone());
44        let ub = (self.upper)(b.clone());
45        le_b(&la, &b) == le_a(&a, &ub)
46    }
47}
48/// Representation of the Knaster-Tarski fixed-point construction on a
49/// complete lattice encoded via a supremum function.
50#[allow(dead_code)]
51pub struct KnasterTarskiFixpoint<T> {
52    /// The monotone endofunction `f`.
53    pub func: Box<dyn Fn(T) -> T>,
54    /// Supremum over an arbitrary predicate (models `sSup`).
55    pub ssup: Box<dyn Fn(Box<dyn Fn(&T) -> bool>) -> T>,
56}
57#[allow(dead_code)]
58impl<T: Clone + PartialEq> KnasterTarskiFixpoint<T> {
59    /// Construct a new Knaster-Tarski calculator.
60    pub fn new(
61        func: impl Fn(T) -> T + 'static,
62        ssup: impl Fn(Box<dyn Fn(&T) -> bool>) -> T + 'static,
63    ) -> Self {
64        Self {
65            func: Box::new(func),
66            ssup: Box::new(ssup),
67        }
68    }
69    /// Compute the least fixed point by iterating from `bot`.
70    pub fn lfp_iterate(&self, bot: T, max_iter: usize) -> Option<T> {
71        let mut x = bot;
72        for _ in 0..max_iter {
73            let fx = (self.func)(x.clone());
74            if fx == x {
75                return Some(x);
76            }
77            x = fx;
78        }
79        None
80    }
81    /// Check whether a given element is a fixed point of `f`.
82    pub fn is_fixed_point(&self, x: T) -> bool {
83        let fx = (self.func)(x.clone());
84        fx == x
85    }
86    /// Apply `f` n times starting from `x`.
87    pub fn iterate_n(&self, x: T, n: usize) -> T {
88        let mut current = x;
89        for _ in 0..n {
90            current = (self.func)(current);
91        }
92        current
93    }
94}
95/// Checker for partial-order properties on a finite set encoded as a
96/// comparison closure.
97#[allow(dead_code)]
98pub struct PartialOrderChecker<T> {
99    /// Elements of the poset.
100    pub elements: Vec<T>,
101    /// The underlying partial order relation: returns `true` iff `a ≤ b`.
102    pub le: Box<dyn Fn(&T, &T) -> bool>,
103}
104#[allow(dead_code)]
105impl<T: Clone + PartialEq> PartialOrderChecker<T> {
106    /// Create a new checker.
107    pub fn new(elements: Vec<T>, le: impl Fn(&T, &T) -> bool + 'static) -> Self {
108        Self {
109            elements,
110            le: Box::new(le),
111        }
112    }
113    /// Verify reflexivity: `∀ a, a ≤ a`.
114    pub fn check_reflexive(&self) -> bool {
115        self.elements.iter().all(|a| (self.le)(a, a))
116    }
117    /// Verify transitivity: `∀ a b c, a ≤ b ∧ b ≤ c → a ≤ c`.
118    pub fn check_transitive(&self) -> bool {
119        for a in &self.elements {
120            for b in &self.elements {
121                for c in &self.elements {
122                    if (self.le)(a, b) && (self.le)(b, c) && !(self.le)(a, c) {
123                        return false;
124                    }
125                }
126            }
127        }
128        true
129    }
130    /// Verify antisymmetry: `∀ a b, a ≤ b ∧ b ≤ a → a = b`.
131    pub fn check_antisymmetric(&self) -> bool {
132        for a in &self.elements {
133            for b in &self.elements {
134                if (self.le)(a, b) && (self.le)(b, a) && a != b {
135                    return false;
136                }
137            }
138        }
139        true
140    }
141    /// Check all three partial-order axioms at once.
142    pub fn is_partial_order(&self) -> bool {
143        self.check_reflexive() && self.check_transitive() && self.check_antisymmetric()
144    }
145    /// Find all maximal elements (no strictly larger element exists).
146    pub fn maximal_elements(&self) -> Vec<T> {
147        self.elements
148            .iter()
149            .filter(|a| {
150                !self
151                    .elements
152                    .iter()
153                    .any(|b| (self.le)(a, b) && !(self.le)(b, a))
154            })
155            .cloned()
156            .collect()
157    }
158    /// Find all minimal elements.
159    pub fn minimal_elements(&self) -> Vec<T> {
160        self.elements
161            .iter()
162            .filter(|a| {
163                !self
164                    .elements
165                    .iter()
166                    .any(|b| (self.le)(b, a) && !(self.le)(a, b))
167            })
168            .cloned()
169            .collect()
170    }
171}
172/// Binary lattice operations on elements that implement `Clone + PartialEq`.
173#[allow(dead_code)]
174pub struct LatticeOps<T> {
175    /// Join (supremum) of two elements.
176    pub join: Box<dyn Fn(T, T) -> T>,
177    /// Meet (infimum) of two elements.
178    pub meet: Box<dyn Fn(T, T) -> T>,
179}
180#[allow(dead_code)]
181impl<T: Clone + PartialEq> LatticeOps<T> {
182    /// Create from explicit join/meet functions.
183    pub fn new(join: impl Fn(T, T) -> T + 'static, meet: impl Fn(T, T) -> T + 'static) -> Self {
184        Self {
185            join: Box::new(join),
186            meet: Box::new(meet),
187        }
188    }
189    /// Compute the join of a non-empty slice.
190    pub fn fold_join(&self, elems: &[T]) -> Option<T> {
191        let mut iter = elems.iter().cloned();
192        let first = iter.next()?;
193        Some(iter.fold(first, |acc, x| (self.join)(acc, x)))
194    }
195    /// Compute the meet of a non-empty slice.
196    pub fn fold_meet(&self, elems: &[T]) -> Option<T> {
197        let mut iter = elems.iter().cloned();
198        let first = iter.next()?;
199        Some(iter.fold(first, |acc, x| (self.meet)(acc, x)))
200    }
201    /// Check absorption: `join a (meet a b) = a`.
202    pub fn check_absorption_join_meet(&self, a: T, b: T) -> bool {
203        let lhs = (self.join)(a.clone(), (self.meet)(a.clone(), b));
204        lhs == a
205    }
206    /// Check absorption: `meet a (join a b) = a`.
207    pub fn check_absorption_meet_join(&self, a: T, b: T) -> bool {
208        let lhs = (self.meet)(a.clone(), (self.join)(a.clone(), b));
209        lhs == a
210    }
211}
212/// A closure operator on a poset: an extensive, monotone, idempotent
213/// endofunction.
214#[allow(dead_code)]
215pub struct ClosureOperator<T> {
216    /// The closure map.
217    pub close: Box<dyn Fn(T) -> T>,
218    /// The underlying order used to verify properties.
219    pub le: Box<dyn Fn(&T, &T) -> bool>,
220}
221#[allow(dead_code)]
222impl<T: Clone + PartialEq> ClosureOperator<T> {
223    /// Construct a closure operator.
224    pub fn new(close: impl Fn(T) -> T + 'static, le: impl Fn(&T, &T) -> bool + 'static) -> Self {
225        Self {
226            close: Box::new(close),
227            le: Box::new(le),
228        }
229    }
230    /// Verify extensiveness: `a ≤ close(a)`.
231    pub fn check_extensive(&self, a: T) -> bool {
232        let ca = (self.close)(a.clone());
233        (self.le)(&a, &ca)
234    }
235    /// Verify monotonicity: `a ≤ b → close(a) ≤ close(b)`.
236    pub fn check_monotone(&self, a: T, b: T) -> bool {
237        if (self.le)(&a, &b) {
238            let ca = (self.close)(a);
239            let cb = (self.close)(b);
240            (self.le)(&ca, &cb)
241        } else {
242            true
243        }
244    }
245    /// Verify idempotency: `close(close(a)) = close(a)`.
246    pub fn check_idempotent(&self, a: T) -> bool {
247        let ca = (self.close)(a);
248        let cca = (self.close)(ca.clone());
249        ca == cca
250    }
251    /// Apply closure until a fixed point is reached.
252    /// Returns `None` after `max_iter` iterations without stabilisation.
253    pub fn iterate_to_fixed_point(&self, a: T, max_iter: usize) -> Option<T> {
254        let mut current = a;
255        for _ in 0..max_iter {
256            let next = (self.close)(current.clone());
257            if next == current {
258                return Some(current);
259            }
260            current = next;
261        }
262        None
263    }
264}