Skip to main content

constraint_crdt/
merge.rs

1//! # CRDT Merge Trait
2//!
3//! The fundamental algebraic structure underlying both CRDTs and constraint lattices:
4//! a **semilattice**. Every CRDT merge must be:
5//! - **Commutative**: a.merge(b) == b.merge(a)
6//! - **Associative**: a.merge(b).merge(c) == a.merge(b.merge(c))
7//! - **Idempotent**: a.merge(a) == a
8//!
9//! These are EXACTLY the properties needed for distributed constraint satisfaction.
10
11use std::fmt::Debug;
12
13/// The fundamental merge operation — a bounded semilattice join.
14///
15/// This trait unifies CRDT merges, constraint lattice joins,
16/// and PLATO tile reconciliation under one algebraic structure.
17pub trait Merge: Clone + Debug {
18    /// Merge another state into this one (in-place).
19    ///
20    /// Postconditions:
21    /// - `a.merge(b)` ≡ `b.merge(a)` (commutative)
22    /// - `a.merge(b).merge(c)` ≡ `a.merge(b.merge(c))` (associative)
23    /// - `a.merge(a)` ≡ `a` (idempotent)
24    fn merge(&mut self, other: &Self);
25
26    /// Create a merged copy without modifying self.
27    fn merged(&self, other: &Self) -> Self
28    where
29        Self: Sized,
30    {
31        let mut copy = self.clone();
32        copy.merge(other);
33        copy
34    }
35
36    /// Check if this state subsumes (is greater than or equal to) another.
37    /// In lattice terms: self ≥ other.
38    fn subsumes(&self, other: &Self) -> bool
39    where
40        Self: PartialEq,
41    {
42        self.merged(other) == *self
43    }
44}
45
46#[cfg(test)]
47pub mod laws {
48    use super::*;
49
50    /// Verify commutativity: a ∘ b == b ∘ a
51    pub fn check_commutative<T: Merge + PartialEq>(a: &T, b: &T) -> bool {
52        a.merged(b) == b.merged(a)
53    }
54
55    /// Verify associativity: (a ∘ b) ∘ c == a ∘ (b ∘ c)
56    pub fn check_associative<T: Merge + PartialEq>(a: &T, b: &T, c: &T) -> bool {
57        a.merged(b).merged(c) == a.merged(&b.merged(c))
58    }
59
60    /// Verify idempotence: a ∘ a == a
61    pub fn check_idempotent<T: Merge + PartialEq>(a: &T) -> bool {
62        a.merged(a) == *a
63    }
64}