harness_space/set.rs
1//! # Set Module
2//!
3//! This module provides traits for abstracting over collection types and partially
4//! ordered sets (posets).
5//!
6//! The core traits defined are:
7//! - [`Collection`]: For types that represent a collection of items, supporting basic operations
8//! like checking for containment and emptiness.
9//! - [`Poset`]: Extends [`Collection`] for sets that also define a partial order relation among
10//! their items, along with related poset operations like finding upsets, downsets,
11//! minimal/maximal elements, etc.
12//!
13//! Implementations of [`Collection`] are provided for standard library types such as
14//! [`HashSet`], [`BTreeSet`], and [`Vec`].
15
16use std::{
17 collections::{BTreeSet, HashSet},
18 hash::{BuildHasher, Hash},
19};
20
21/// A trait for collections that support basic set operations.
22///
23/// This trait defines fundamental operations applicable to various collection types,
24/// focusing on item containment and checking for emptiness.
25///
26/// # Type Parameters
27///
28/// * `Item`: The type of elements contained within the collection.
29///
30/// # Implementations
31///
32/// Implementations are provided for:
33/// * [`HashSet<T, S>`]: Where `T: Hash + Eq + Clone` and `S: BuildHasher + Default`.
34/// * [`BTreeSet<T>`]: Where `T: Ord + Clone`.
35/// * [`Vec<T>`]: Where `T: PartialEq`.
36pub trait Collection {
37 /// The type of elements stored in the collection.
38 type Item;
39
40 /// Checks if an item is present in the collection.
41 ///
42 /// # Arguments
43 ///
44 /// * `point`: A reference to the item to check for containment.
45 ///
46 /// # Returns
47 ///
48 /// `true` if the item is found in the collection, `false` otherwise.
49 fn contains(&self, point: &Self::Item) -> bool;
50
51 /// Determines if the collection is empty.
52 ///
53 /// # Returns
54 ///
55 /// * `true` if the collection contains no items.
56 /// * `false` if the collection contains one or more items.
57 fn is_empty(&self) -> bool;
58}
59
60/// A trait for sets that support partial order relations, building upon [`Collection`].
61///
62/// This trait extends the basic [`Collection`] operations with methods specific to
63/// partially ordered sets (posets). This includes checking the partial order
64/// relation (`leq`), and computing various poset-specific subsets and elements.
65///
66/// # Type Parameters
67///
68/// * `Item`: The type of elements contained in the set, which are subject to the partial order.
69pub trait Poset: Collection {
70 /// Tests if one item is less than or equal to another according to the partial order.
71 ///
72 /// The `leq` relation (often denoted as $\le$) must satisfy reflexivity, antisymmetry,
73 /// and transitivity.
74 ///
75 /// # Arguments
76 ///
77 /// * `a`: A reference to the first item.
78 /// * `b`: A reference to the second item.
79 ///
80 /// # Returns
81 ///
82 /// * `Some(true)` if `a` is less than or equal to `b` ($a \le b$).
83 /// * `Some(false)` if `a` is not less than or equal to `b` (and both are comparable in the set).
84 /// * `None` if the relation cannot be determined (e.g., if one or both items are not considered
85 /// part of the poset for comparison, or if the specific poset implementation cannot compare
86 /// them).
87 fn leq(&self, a: &Self::Item, b: &Self::Item) -> Option<bool>;
88
89 /// Computes the upset of an item `a`.
90 ///
91 /// The upset of `a`, denoted $\uparrow a$, is the set of all items `x` in the poset
92 /// such that $a \le x$.
93 ///
94 /// # Arguments
95 ///
96 /// * `a`: The item whose upset is to be computed.
97 ///
98 /// # Returns
99 ///
100 /// A `HashSet` containing all items `x` such that `a` is less than or equal to `x`.
101 fn upset(&self, a: Self::Item) -> HashSet<Self::Item>;
102
103 /// Computes the downset of an item `a`.
104 ///
105 /// The downset of `a`, denoted $\downarrow a$, is the set of all items `x` in the poset
106 /// such that $x \le a$.
107 ///
108 /// # Arguments
109 ///
110 /// * `a`: The item whose downset is to be computed.
111 ///
112 /// # Returns
113 ///
114 /// A `HashSet` containing all items `x` such that `x` is less than or equal to `a`.
115 fn downset(&self, a: Self::Item) -> HashSet<Self::Item>;
116
117 /// Finds all minimal elements of the poset.
118 ///
119 /// An item `m` is minimal if there is no other item `x` in the poset such that $x < m$
120 /// (i.e., $x \le m$ and $x \neq m$).
121 ///
122 /// # Returns
123 ///
124 /// A `HashSet` containing all minimal elements of the poset.
125 fn minimal_elements(&self) -> HashSet<Self::Item>;
126
127 /// Finds all maximal elements of the poset.
128 ///
129 /// An item `m` is maximal if there is no other item `x` in the poset such that $m < x$
130 /// (i.e., $m \le x$ and $m \neq x$).
131 ///
132 /// # Returns
133 ///
134 /// A `HashSet` containing all maximal elements of the poset.
135 fn maximal_elements(&self) -> HashSet<Self::Item>;
136
137 /// Computes the join (least upper bound) of two items `a` and `b`, if it exists.
138 ///
139 /// The join $a \lor b$ is an item `j` such that $a \le j$ and $b \le j$, and for any
140 /// other item `k` with $a \le k$ and $b \le k$, it holds that $j \le k$.
141 ///
142 /// # Arguments
143 ///
144 /// * `a`: The first item.
145 /// * `b`: The second item.
146 ///
147 /// # Returns
148 ///
149 /// * `Some(join_element)` if the join of `a` and `b` exists.
150 /// * `None` if the join does not exist or is not unique.
151 fn join(&self, a: Self::Item, b: Self::Item) -> Option<Self::Item>;
152
153 /// Computes the meet (greatest lower bound) of two items `a` and `b`, if it exists.
154 ///
155 /// The meet $a \land b$ is an item `m` such that $m \le a$ and $m \le b$, and for any
156 /// other item `k` with $k \le a$ and $k \le b$, it holds that $k \le m$.
157 ///
158 /// # Arguments
159 ///
160 /// * `a`: The first item.
161 /// * `b`: The second item.
162 ///
163 /// # Returns
164 ///
165 /// * `Some(meet_element)` if the meet of `a` and `b` exists.
166 /// * `None` if the meet does not exist or is not unique.
167 fn meet(&self, a: Self::Item, b: Self::Item) -> Option<Self::Item>;
168
169 /// Finds all direct successors (covers) of an item `a`.
170 ///
171 /// An item `s` is a direct successor of `a` if $a < s$ (i.e., $a \le s$ and $a \neq s$)
172 /// and there is no item `x` such that $a < x < s$.
173 ///
174 /// # Arguments
175 ///
176 /// * `a`: The item whose successors are to be found.
177 ///
178 /// # Returns
179 ///
180 /// A `HashSet` containing all direct successors of `a`.
181 fn successors(&self, a: Self::Item) -> HashSet<Self::Item>;
182
183 /// Finds all direct predecessors of an item `a`.
184 ///
185 /// An item `p` is a direct predecessor of `a` if $p < a$ (i.e., $p \le a$ and $p \neq a$)
186 /// and there is no item `x` such that $p < x < a$.
187 ///
188 /// # Arguments
189 ///
190 /// * `a`: The item whose predecessors are to be found.
191 ///
192 /// # Returns
193 ///
194 /// A `HashSet` containing all direct predecessors of `a`.
195 fn predecessors(&self, a: Self::Item) -> HashSet<Self::Item>;
196}
197
198impl<T: Hash + Eq + Clone, S: BuildHasher + Default> Collection for HashSet<T, S> {
199 type Item = T;
200
201 /// Checks if the `HashSet` contains the specified item.
202 /// This is a direct wrapper around [`HashSet::contains`].
203 fn contains(&self, point: &Self::Item) -> bool { Self::contains(self, point) }
204
205 /// Checks if the `HashSet` is empty.
206 /// This is a direct wrapper around [`HashSet::is_empty`].
207 fn is_empty(&self) -> bool { Self::is_empty(self) }
208}
209
210impl<T: Ord + Clone> Collection for BTreeSet<T> {
211 type Item = T;
212
213 /// Checks if the `BTreeSet` contains the specified item.
214 /// This is a direct wrapper around [`BTreeSet::contains`].
215 fn contains(&self, point: &Self::Item) -> bool { Self::contains(self, point) }
216
217 /// Checks if the `BTreeSet` is empty.
218 /// This is a direct wrapper around [`BTreeSet::is_empty`].
219 fn is_empty(&self) -> bool { Self::is_empty(self) }
220}
221
222impl<T: PartialEq> Collection for Vec<T> {
223 type Item = T;
224
225 /// Checks if the `Vec` contains the specified item by iterating through its elements.
226 fn contains(&self, point: &Self::Item) -> bool { self.iter().any(|p| p == point) }
227
228 /// Checks if the `Vec` is empty.
229 /// This is a direct wrapper around [`Vec::is_empty`].
230 fn is_empty(&self) -> bool { self.is_empty() }
231}