Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for a join Semilattice #14

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions examples/set_join_semilattice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use noether::{AssociativeJoin, CommutativeJoin, IdempotentJoin, Join, JoinSemiLattice};
use std::collections::HashSet;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SetJoinSemilattice<T: Eq + std::hash::Hash + Clone> {
set: HashSet<T>,
}
impl<T: Eq + std::hash::Hash + Clone> SetJoinSemilattice<T> {
pub const fn new(set: HashSet<T>) -> Self {
Self { set }
}
}
impl<T: Eq + std::hash::Hash + Clone> CommutativeJoin for SetJoinSemilattice<T> {}
impl<T: Eq + std::hash::Hash + Clone> AssociativeJoin for SetJoinSemilattice<T> {}

impl<T: Eq + std::hash::Hash + Clone> IdempotentJoin for SetJoinSemilattice<T> {}

impl<T: Eq + std::hash::Hash + Clone> Join for SetJoinSemilattice<T> {
fn join(self, other: &Self) -> Self {
let union: HashSet<T> = self.set.union(&other.set).cloned().collect();
Self { set: union }
}

/// The identity element: an empty set.
/// Satisfies: a ⋁ {} == a
fn identity(&self) -> Self {
Self {
set: HashSet::new(),
}
}
}

// // impl Join for {};

impl<T: Eq + std::hash::Hash + Clone> JoinSemiLattice for SetJoinSemilattice<T> {}

fn main() {
// Test 1: check join of different sets
let set_a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
let set_b: HashSet<_> = vec![3, 4, 5].into_iter().collect();

let semilattice_a = SetJoinSemilattice { set: set_a };
let semilattice_b = SetJoinSemilattice { set: set_b };

// Perform the join operation (union)
let result: SetJoinSemilattice<i32> = semilattice_a.join(&semilattice_b);
println!("Resulting Set: {:?}", result.set);

// Test 2: check join of same element

let set_c: HashSet<_> = vec![1, 2, 3].into_iter().collect();
let set_d: HashSet<_> = vec![1, 2, 3].into_iter().collect();

let semilattice_c = SetJoinSemilattice { set: set_c };
let semilattice_d = SetJoinSemilattice { set: set_d };

let result_same_set: SetJoinSemilattice<i32> = semilattice_c.join(&semilattice_d);
println!("Resulting Same Set: {:?}", result_same_set.set);

// Test 3: check join with identity element should return the same set

let set_e: HashSet<_> = vec![1, 2, 4].into_iter().collect();

let semilattice_e = SetJoinSemilattice { set: set_e };
let identity = semilattice_e.identity();

let result_identity: SetJoinSemilattice<i32> = semilattice_e.join(&identity);
println!(
"Resulting of join with identity should return same set {:?}",
result_identity.set
);
}
29 changes: 29 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,35 @@ impl<T: EuclideanDomain + MultiplicativeAbelianGroup> Field for T {}
// OrderedField
impl<T: Field + PartialOrd> OrderedField for T {}

// properties of Join in a semilattice
/// Ensures that the join operation satisfies associativity:
/// - For all a, b, c in the semilattice:
/// (a ⋁ b) ⋁ c == a ⋁ (b ⋁ c)
/// This property guarantees that grouping does not affect the result of joins.
pub trait IdempotentJoin {}
/// Ensures that the join operation satisfies commutativity:
/// - For all a, b in the semilattice:
/// a ⋁ b == b ⋁ a
/// This property allows the order of operands to be swapped without affecting the result.

/// Ensures that the join operation satisfies idempotency:
/// - For all a in the semilattice:
/// a ⋁ a == a
/// This property means that joining an element with itself does not change the element.

pub trait AssociativeJoin {}

pub trait CommutativeJoin {}

pub trait Join: AssociativeJoin + CommutativeJoin + IdempotentJoin {
fn join(self, other: &Self) -> Self;
/// Returns the identity element of the semilattice.
/// The identity must satisfy: a ⋁ e == a, where e is the identity element.
fn identity(&self) -> Self;
}

pub trait JoinSemiLattice: Join {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might look at a blanket implementation here when the traits are satisfied.

Copy link
Author

@SimonVervisch SimonVervisch Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

impl<T: Join> JoinSemiLattice for T {}
Like this? (For all types T)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah


// RealField
// Note: This cannot be implemented as a blanket impl because it requires knowledge about completeness

Expand Down