Skip to main content

relmath/core/
binary.rs

1//! Deterministic exact binary relation foundations.
2
3use std::collections::BTreeSet;
4
5use crate::{FiniteCarrier, UnaryRelation, traits::FiniteRelation};
6
7/// A finite binary relation.
8///
9/// The starter implementation stores pairs in a `BTreeSet` so iteration order
10/// is deterministic.
11///
12/// Composition direction is:
13///
14/// `r.compose(&s)` = `{ (a, c) | exists b. (a, b) in r and (b, c) in s }`
15///
16/// # Examples
17///
18/// ```rust
19/// use relmath::{BinaryRelation, UnaryRelation};
20///
21/// let user_role = BinaryRelation::from_pairs([
22///     ("ann", "admin"),
23///     ("bob", "reviewer"),
24/// ]);
25///
26/// let extra_role = BinaryRelation::from_pairs([
27///     ("bob", "reviewer"),
28///     ("cara", "guest"),
29/// ]);
30///
31/// let role_permission = BinaryRelation::from_pairs([
32///     ("admin", "read"),
33///     ("reviewer", "approve"),
34///     ("guest", "view"),
35/// ]);
36///
37/// assert_eq!(
38///     user_role.union(&extra_role).to_vec(),
39///     vec![("ann", "admin"), ("bob", "reviewer"), ("cara", "guest")]
40/// );
41/// assert_eq!(
42///     user_role.intersection(&extra_role).to_vec(),
43///     vec![("bob", "reviewer")]
44/// );
45/// assert_eq!(user_role.difference(&extra_role).to_vec(), vec![("ann", "admin")]);
46/// assert_eq!(
47///     user_role.converse().to_vec(),
48///     vec![("admin", "ann"), ("reviewer", "bob")]
49/// );
50///
51/// let effective_permission = user_role.union(&extra_role).compose(&role_permission);
52/// assert!(effective_permission.contains(&"ann", &"read"));
53/// assert_eq!(
54///     effective_permission.iter().copied().collect::<Vec<_>>(),
55///     vec![("ann", "read"), ("bob", "approve"), ("cara", "view")]
56/// );
57/// assert_eq!(
58///     effective_permission.domain().to_vec(),
59///     vec!["ann", "bob", "cara"]
60/// );
61/// assert_eq!(
62///     effective_permission.range().to_vec(),
63///     vec!["approve", "read", "view"]
64/// );
65/// assert_eq!(
66///     effective_permission
67///         .restrict_domain(&UnaryRelation::from_values(["ann", "cara"]))
68///         .to_vec(),
69///     vec![("ann", "read"), ("cara", "view")]
70/// );
71/// assert_eq!(
72///     effective_permission
73///         .restrict_range(&UnaryRelation::from_values(["read", "view"]))
74///         .to_vec(),
75///     vec![("ann", "read"), ("cara", "view")]
76/// );
77/// assert_eq!(
78///     effective_permission.image(&UnaryRelation::singleton("bob")).to_vec(),
79///     vec!["approve"]
80/// );
81/// assert_eq!(
82///     effective_permission
83///         .preimage(&UnaryRelation::from_values(["read", "view"]))
84///         .to_vec(),
85///     vec!["ann", "cara"]
86/// );
87/// ```
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct BinaryRelation<A: Ord, B: Ord> {
90    pairs: BTreeSet<(A, B)>,
91}
92
93impl<A: Ord, B: Ord> BinaryRelation<A, B> {
94    /// Creates an empty binary relation.
95    #[must_use]
96    pub fn new() -> Self {
97        Self {
98            pairs: BTreeSet::new(),
99        }
100    }
101
102    /// Creates a binary relation from the provided pairs.
103    #[must_use]
104    pub fn from_pairs<I>(pairs: I) -> Self
105    where
106        I: IntoIterator<Item = (A, B)>,
107    {
108        pairs.into_iter().collect()
109    }
110
111    /// Inserts a pair into the relation.
112    ///
113    /// Returns `true` when the pair was not already present.
114    pub fn insert(&mut self, left: A, right: B) -> bool {
115        self.pairs.insert((left, right))
116    }
117
118    /// Returns `true` when the relation contains the given pair.
119    #[must_use]
120    pub fn contains(&self, left: &A, right: &B) -> bool {
121        self.pairs.iter().any(|(candidate_left, candidate_right)| {
122            candidate_left == left && candidate_right == right
123        })
124    }
125
126    /// Returns an iterator over the stored pairs in deterministic order.
127    pub fn iter(&self) -> impl Iterator<Item = &(A, B)> {
128        self.pairs.iter()
129    }
130
131    /// Returns the domain of the relation.
132    #[must_use]
133    pub fn domain(&self) -> UnaryRelation<A>
134    where
135        A: Clone,
136    {
137        self.pairs.iter().map(|(left, _)| left.clone()).collect()
138    }
139
140    /// Returns the range of the relation.
141    #[must_use]
142    pub fn range(&self) -> UnaryRelation<B>
143    where
144        B: Clone,
145    {
146        self.pairs.iter().map(|(_, right)| right.clone()).collect()
147    }
148
149    /// Returns the converse relation.
150    #[must_use]
151    pub fn converse(&self) -> BinaryRelation<B, A>
152    where
153        A: Clone,
154        B: Clone,
155    {
156        self.pairs
157            .iter()
158            .map(|(left, right)| (right.clone(), left.clone()))
159            .collect()
160    }
161
162    /// Returns the union of `self` and `other`.
163    #[must_use]
164    pub fn union(&self, other: &Self) -> Self
165    where
166        A: Clone,
167        B: Clone,
168    {
169        self.pairs.union(&other.pairs).cloned().collect()
170    }
171
172    /// Returns the intersection of `self` and `other`.
173    #[must_use]
174    pub fn intersection(&self, other: &Self) -> Self
175    where
176        A: Clone,
177        B: Clone,
178    {
179        self.pairs.intersection(&other.pairs).cloned().collect()
180    }
181
182    /// Returns the set difference `self \ other`.
183    #[must_use]
184    pub fn difference(&self, other: &Self) -> Self
185    where
186        A: Clone,
187        B: Clone,
188    {
189        self.pairs.difference(&other.pairs).cloned().collect()
190    }
191
192    /// Restricts the domain of the relation to `allowed`.
193    #[must_use]
194    pub fn restrict_domain(&self, allowed: &UnaryRelation<A>) -> Self
195    where
196        A: Clone,
197        B: Clone,
198    {
199        self.pairs
200            .iter()
201            .filter(|(left, _)| allowed.contains(left))
202            .cloned()
203            .collect()
204    }
205
206    /// Restricts the range of the relation to `allowed`.
207    #[must_use]
208    pub fn restrict_range(&self, allowed: &UnaryRelation<B>) -> Self
209    where
210        A: Clone,
211        B: Clone,
212    {
213        self.pairs
214            .iter()
215            .filter(|(_, right)| allowed.contains(right))
216            .cloned()
217            .collect()
218    }
219
220    /// Computes the image of `sources` through the relation.
221    ///
222    /// Returns `{ b | exists a in sources. (a, b) in self }`.
223    #[must_use]
224    pub fn image(&self, sources: &UnaryRelation<A>) -> UnaryRelation<B>
225    where
226        B: Clone,
227    {
228        self.pairs
229            .iter()
230            .filter(|(left, _)| sources.contains(left))
231            .map(|(_, right)| right.clone())
232            .collect()
233    }
234
235    /// Computes the preimage of `targets` through the relation.
236    ///
237    /// Returns `{ a | exists b in targets. (a, b) in self }`.
238    #[must_use]
239    pub fn preimage(&self, targets: &UnaryRelation<B>) -> UnaryRelation<A>
240    where
241        A: Clone,
242    {
243        self.pairs
244            .iter()
245            .filter(|(_, right)| targets.contains(right))
246            .map(|(left, _)| left.clone())
247            .collect()
248    }
249
250    /// Composes `self` with `rhs`.
251    ///
252    /// The result contains `(a, c)` whenever there exists `b` such that
253    /// `(a, b)` is in `self` and `(b, c)` is in `rhs`.
254    ///
255    /// # Examples
256    ///
257    /// ```rust
258    /// use relmath::BinaryRelation;
259    ///
260    /// let user_role = BinaryRelation::from_pairs([
261    ///     ("ann", "admin"),
262    ///     ("bob", "reviewer"),
263    /// ]);
264    /// let role_permission = BinaryRelation::from_pairs([
265    ///     ("admin", "read"),
266    ///     ("reviewer", "approve"),
267    /// ]);
268    ///
269    /// let effective_permission = user_role.compose(&role_permission);
270    ///
271    /// assert_eq!(
272    ///     effective_permission.to_vec(),
273    ///     vec![("ann", "read"), ("bob", "approve")]
274    /// );
275    /// ```
276    #[must_use]
277    pub fn compose<C>(&self, rhs: &BinaryRelation<B, C>) -> BinaryRelation<A, C>
278    where
279        A: Clone,
280        B: Clone,
281        C: Clone + Ord,
282    {
283        let mut result = BTreeSet::new();
284
285        for (left, middle_left) in &self.pairs {
286            for (middle_right, right) in &rhs.pairs {
287                if middle_left == middle_right {
288                    result.insert((left.clone(), right.clone()));
289                }
290            }
291        }
292
293        BinaryRelation { pairs: result }
294    }
295
296    /// Converts the relation into a sorted vector of pairs.
297    #[must_use]
298    pub fn to_vec(&self) -> Vec<(A, B)>
299    where
300        A: Clone,
301        B: Clone,
302    {
303        self.pairs.iter().cloned().collect()
304    }
305}
306
307impl<A: Ord, B: Ord> Default for BinaryRelation<A, B> {
308    fn default() -> Self {
309        Self::new()
310    }
311}
312
313impl<T: Ord> BinaryRelation<T, T> {
314    fn identity_from_iter<'a, I>(carrier: I) -> Self
315    where
316        T: Clone + 'a,
317        I: IntoIterator<Item = &'a T>,
318    {
319        carrier
320            .into_iter()
321            .map(|value| (value.clone(), value.clone()))
322            .collect()
323    }
324
325    fn is_reflexive_over<'a, I>(&self, carrier: I) -> bool
326    where
327        T: 'a,
328        I: IntoIterator<Item = &'a T>,
329    {
330        carrier.into_iter().all(|value| self.contains(value, value))
331    }
332
333    fn is_irreflexive_over<'a, I>(&self, carrier: I) -> bool
334    where
335        T: 'a,
336        I: IntoIterator<Item = &'a T>,
337    {
338        carrier
339            .into_iter()
340            .all(|value| !self.contains(value, value))
341    }
342
343    /// Returns the carrier induced by the relation: domain union range.
344    ///
345    /// This is support-derived carrier information, not an explicit
346    /// [`crate::FiniteCarrier`]. Use [`crate::FiniteCarrier`] when the declared
347    /// domain must remain visible even for disconnected values that do not
348    /// appear in stored pairs.
349    ///
350    /// # Examples
351    ///
352    /// ```rust
353    /// use relmath::{BinaryRelation, FiniteCarrier};
354    ///
355    /// let step = BinaryRelation::from_pairs([("Draft", "Review")]);
356    /// let explicit = FiniteCarrier::from_values(["Draft", "Review", "Archived"]);
357    ///
358    /// assert_eq!(step.carrier().to_vec(), vec!["Draft", "Review"]);
359    /// assert_eq!(explicit.to_vec(), vec!["Archived", "Draft", "Review"]);
360    /// ```
361    #[must_use]
362    pub fn carrier(&self) -> UnaryRelation<T>
363    where
364        T: Clone,
365    {
366        self.domain().union(&self.range())
367    }
368
369    /// Returns the identity relation on `carrier`.
370    ///
371    /// # Examples
372    ///
373    /// ```rust
374    /// use relmath::{BinaryRelation, UnaryRelation};
375    ///
376    /// let carrier = UnaryRelation::from_values(["Draft", "Review"]);
377    ///
378    /// assert_eq!(
379    ///     BinaryRelation::identity(&carrier).to_vec(),
380    ///     vec![("Draft", "Draft"), ("Review", "Review")]
381    /// );
382    ///
383    /// // Use `identity_on` when the carrier should remain explicit.
384    /// let explicit = relmath::FiniteCarrier::from_values(["Draft", "Review"]);
385    /// assert_eq!(BinaryRelation::identity_on(&explicit).to_vec(), BinaryRelation::identity(&carrier).to_vec());
386    /// ```
387    #[must_use]
388    pub fn identity(carrier: &UnaryRelation<T>) -> Self
389    where
390        T: Clone,
391    {
392        Self::identity_from_iter(carrier.iter())
393    }
394
395    /// Returns the identity relation on an explicit finite `carrier`.
396    ///
397    /// This is the G7 carrier-aware companion to [`Self::identity`]. It keeps
398    /// the carrier explicit at the API boundary instead of first converting it
399    /// into a unary relation.
400    ///
401    /// # Examples
402    ///
403    /// ```rust
404    /// use relmath::{BinaryRelation, FiniteCarrier, UnaryRelation};
405    ///
406    /// let carrier = FiniteCarrier::from_values(["Draft", "Review"]);
407    /// let unary = UnaryRelation::from_values(["Draft", "Review"]);
408    ///
409    /// assert_eq!(
410    ///     BinaryRelation::identity_on(&carrier).to_vec(),
411    ///     vec![("Draft", "Draft"), ("Review", "Review")]
412    /// );
413    /// assert_eq!(
414    ///     BinaryRelation::identity_on(&carrier).to_vec(),
415    ///     BinaryRelation::identity(&unary).to_vec()
416    /// );
417    /// ```
418    #[must_use]
419    pub fn identity_on(carrier: &FiniteCarrier<T>) -> Self
420    where
421        T: Clone,
422    {
423        Self::identity_from_iter(carrier.iter())
424    }
425
426    /// Computes the transitive closure of the relation.
427    ///
428    /// # Examples
429    ///
430    /// ```rust
431    /// use relmath::BinaryRelation;
432    ///
433    /// let step = BinaryRelation::from_pairs([
434    ///     ("Draft", "Review"),
435    ///     ("Review", "Approved"),
436    /// ]);
437    ///
438    /// assert_eq!(
439    ///     step.transitive_closure().to_vec(),
440    ///     vec![
441    ///         ("Draft", "Approved"),
442    ///         ("Draft", "Review"),
443    ///         ("Review", "Approved"),
444    ///     ]
445    /// );
446    /// ```
447    #[must_use]
448    pub fn transitive_closure(&self) -> Self
449    where
450        T: Clone,
451    {
452        let mut closure = self.clone();
453        let mut changed = true;
454
455        while changed {
456            changed = false;
457            let snapshot = closure.to_vec();
458
459            for (left, middle_left) in &snapshot {
460                for (middle_right, right) in &snapshot {
461                    if middle_left == middle_right
462                        && closure.pairs.insert((left.clone(), right.clone()))
463                    {
464                        changed = true;
465                    }
466                }
467            }
468        }
469
470        closure
471    }
472
473    /// Computes the reflexive-transitive closure on the given `carrier`.
474    ///
475    /// Values that appear in `carrier` but not in any pair still gain their
476    /// identity edge in the result.
477    ///
478    /// # Examples
479    ///
480    /// ```rust
481    /// use relmath::{BinaryRelation, UnaryRelation};
482    ///
483    /// let step = BinaryRelation::from_pairs([("Draft", "Review")]);
484    /// let states = UnaryRelation::from_values(["Draft", "Review", "Archived"]);
485    /// let reachable = step.reflexive_transitive_closure(&states);
486    ///
487    /// assert!(reachable.contains(&"Archived", &"Archived"));
488    /// assert!(reachable.contains(&"Draft", &"Review"));
489    ///
490    /// let explicit_states = relmath::FiniteCarrier::from_values(["Draft", "Review", "Archived"]);
491    /// assert_eq!(
492    ///     step.reflexive_transitive_closure_on(&explicit_states).to_vec(),
493    ///     reachable.to_vec()
494    /// );
495    /// ```
496    #[must_use]
497    pub fn reflexive_transitive_closure(&self, carrier: &UnaryRelation<T>) -> Self
498    where
499        T: Clone,
500    {
501        self.transitive_closure().union(&Self::identity(carrier))
502    }
503
504    /// Computes the reflexive-transitive closure on an explicit finite
505    /// `carrier`.
506    ///
507    /// Values that appear in `carrier` but not in any pair still gain their
508    /// identity edge in the result.
509    ///
510    /// This is the G7 carrier-aware companion to
511    /// [`Self::reflexive_transitive_closure`].
512    ///
513    /// # Examples
514    ///
515    /// ```rust
516    /// use relmath::{BinaryRelation, FiniteCarrier, UnaryRelation};
517    ///
518    /// let step = BinaryRelation::from_pairs([("Draft", "Review")]);
519    /// let explicit_states = FiniteCarrier::from_values(["Draft", "Review", "Archived"]);
520    /// let unary_states = UnaryRelation::from_values(["Draft", "Review", "Archived"]);
521    /// let reachable = step.reflexive_transitive_closure_on(&explicit_states);
522    ///
523    /// assert!(reachable.contains(&"Archived", &"Archived"));
524    /// assert!(reachable.contains(&"Draft", &"Review"));
525    /// assert_eq!(reachable.to_vec(), step.reflexive_transitive_closure(&unary_states).to_vec());
526    /// ```
527    #[must_use]
528    pub fn reflexive_transitive_closure_on(&self, carrier: &FiniteCarrier<T>) -> Self
529    where
530        T: Clone,
531    {
532        self.transitive_closure().union(&Self::identity_on(carrier))
533    }
534
535    /// Returns `true` when the relation is reflexive on `carrier`.
536    ///
537    /// Use [`Self::is_reflexive_on`] when the carrier should remain explicit
538    /// as a [`crate::FiniteCarrier`].
539    #[must_use]
540    pub fn is_reflexive(&self, carrier: &UnaryRelation<T>) -> bool {
541        self.is_reflexive_over(carrier.iter())
542    }
543
544    /// Returns `true` when the relation is reflexive on an explicit finite
545    /// `carrier`.
546    ///
547    /// # Examples
548    ///
549    /// ```rust
550    /// use relmath::{BinaryRelation, FiniteCarrier};
551    ///
552    /// let aliases = BinaryRelation::from_pairs([
553    ///     ("A. Smith", "A. Smith"),
554    ///     ("A. Smith", "Alice Smith"),
555    ///     ("Alice Smith", "A. Smith"),
556    ///     ("Alice Smith", "Alice Smith"),
557    /// ]);
558    /// let carrier = FiniteCarrier::from_values(["A. Smith", "Alice Smith"]);
559    ///
560    /// assert!(aliases.is_reflexive_on(&carrier));
561    /// ```
562    #[must_use]
563    pub fn is_reflexive_on(&self, carrier: &FiniteCarrier<T>) -> bool {
564        self.is_reflexive_over(carrier.iter())
565    }
566
567    /// Returns `true` when the relation is irreflexive on `carrier`.
568    ///
569    /// Use [`Self::is_irreflexive_on`] when the carrier should remain explicit
570    /// as a [`crate::FiniteCarrier`].
571    #[must_use]
572    pub fn is_irreflexive(&self, carrier: &UnaryRelation<T>) -> bool {
573        self.is_irreflexive_over(carrier.iter())
574    }
575
576    /// Returns `true` when the relation is irreflexive on an explicit finite
577    /// `carrier`.
578    ///
579    /// # Examples
580    ///
581    /// ```rust
582    /// use relmath::{BinaryRelation, FiniteCarrier};
583    ///
584    /// let step = BinaryRelation::from_pairs([("Draft", "Review")]);
585    /// let carrier = FiniteCarrier::from_values(["Draft", "Review", "Archived"]);
586    ///
587    /// assert!(step.is_irreflexive_on(&carrier));
588    /// ```
589    #[must_use]
590    pub fn is_irreflexive_on(&self, carrier: &FiniteCarrier<T>) -> bool {
591        self.is_irreflexive_over(carrier.iter())
592    }
593
594    /// Returns `true` when the relation is symmetric.
595    #[must_use]
596    pub fn is_symmetric(&self) -> bool {
597        self.pairs
598            .iter()
599            .all(|(left, right)| self.contains(right, left))
600    }
601
602    /// Returns `true` when the relation is antisymmetric.
603    #[must_use]
604    pub fn is_antisymmetric(&self) -> bool {
605        self.pairs
606            .iter()
607            .all(|(left, right)| left == right || !self.contains(right, left))
608    }
609
610    /// Returns `true` when the relation is transitive.
611    #[must_use]
612    pub fn is_transitive(&self) -> bool
613    where
614        T: Clone,
615    {
616        let snapshot = self.to_vec();
617
618        snapshot.iter().all(|(left, middle_left)| {
619            snapshot.iter().all(|(middle_right, right)| {
620                middle_left != middle_right || self.contains(left, right)
621            })
622        })
623    }
624
625    /// Returns `true` when the relation is an equivalence relation on `carrier`.
626    ///
627    /// # Examples
628    ///
629    /// ```rust
630    /// use relmath::{BinaryRelation, UnaryRelation};
631    ///
632    /// let aliases = BinaryRelation::from_pairs([
633    ///     ("A. Smith", "A. Smith"),
634    ///     ("A. Smith", "Alice Smith"),
635    ///     ("Alice Smith", "A. Smith"),
636    ///     ("Alice Smith", "Alice Smith"),
637    /// ]);
638    /// let carrier = UnaryRelation::from_values(["A. Smith", "Alice Smith"]);
639    ///
640    /// assert!(aliases.is_equivalence(&carrier));
641    ///
642    /// let explicit = relmath::FiniteCarrier::from_values(["A. Smith", "Alice Smith"]);
643    /// assert!(aliases.is_equivalence_on(&explicit));
644    /// ```
645    #[must_use]
646    pub fn is_equivalence(&self, carrier: &UnaryRelation<T>) -> bool
647    where
648        T: Clone,
649    {
650        self.is_reflexive(carrier) && self.is_symmetric() && self.is_transitive()
651    }
652
653    /// Returns `true` when the relation is an equivalence relation on an
654    /// explicit finite `carrier`.
655    ///
656    /// # Examples
657    ///
658    /// ```rust
659    /// use relmath::{BinaryRelation, FiniteCarrier};
660    ///
661    /// let aliases = BinaryRelation::from_pairs([
662    ///     ("A. Smith", "A. Smith"),
663    ///     ("A. Smith", "Alice Smith"),
664    ///     ("Alice Smith", "A. Smith"),
665    ///     ("Alice Smith", "Alice Smith"),
666    /// ]);
667    /// let carrier = FiniteCarrier::from_values(["A. Smith", "Alice Smith"]);
668    ///
669    /// assert!(aliases.is_equivalence_on(&carrier));
670    /// ```
671    #[must_use]
672    pub fn is_equivalence_on(&self, carrier: &FiniteCarrier<T>) -> bool
673    where
674        T: Clone,
675    {
676        self.is_reflexive_on(carrier) && self.is_symmetric() && self.is_transitive()
677    }
678
679    /// Returns `true` when the relation is a partial order on `carrier`.
680    ///
681    /// # Examples
682    ///
683    /// ```rust
684    /// use relmath::{BinaryRelation, UnaryRelation};
685    ///
686    /// let divides = BinaryRelation::from_pairs([
687    ///     (1_u8, 1_u8),
688    ///     (1, 2),
689    ///     (1, 4),
690    ///     (2, 2),
691    ///     (2, 4),
692    ///     (4, 4),
693    /// ]);
694    /// let carrier = UnaryRelation::from_values([1_u8, 2_u8, 4_u8]);
695    ///
696    /// assert!(divides.is_partial_order(&carrier));
697    ///
698    /// let explicit = relmath::FiniteCarrier::from_values([1_u8, 2_u8, 4_u8]);
699    /// assert!(divides.is_partial_order_on(&explicit));
700    /// ```
701    #[must_use]
702    pub fn is_partial_order(&self, carrier: &UnaryRelation<T>) -> bool
703    where
704        T: Clone,
705    {
706        self.is_reflexive(carrier) && self.is_antisymmetric() && self.is_transitive()
707    }
708
709    /// Returns `true` when the relation is a partial order on an explicit
710    /// finite `carrier`.
711    ///
712    /// # Examples
713    ///
714    /// ```rust
715    /// use relmath::{BinaryRelation, FiniteCarrier};
716    ///
717    /// let divides = BinaryRelation::from_pairs([
718    ///     (1_u8, 1_u8),
719    ///     (1, 2),
720    ///     (1, 4),
721    ///     (2, 2),
722    ///     (2, 4),
723    ///     (4, 4),
724    /// ]);
725    /// let carrier = FiniteCarrier::from_values([1_u8, 2_u8, 4_u8]);
726    ///
727    /// assert!(divides.is_partial_order_on(&carrier));
728    /// ```
729    #[must_use]
730    pub fn is_partial_order_on(&self, carrier: &FiniteCarrier<T>) -> bool
731    where
732        T: Clone,
733    {
734        self.is_reflexive_on(carrier) && self.is_antisymmetric() && self.is_transitive()
735    }
736}
737
738impl<A: Ord, B: Ord> FiniteRelation for BinaryRelation<A, B> {
739    fn len(&self) -> usize {
740        self.pairs.len()
741    }
742}
743
744impl<A: Ord, B: Ord> FromIterator<(A, B)> for BinaryRelation<A, B> {
745    fn from_iter<I: IntoIterator<Item = (A, B)>>(iter: I) -> Self {
746        Self {
747            pairs: iter.into_iter().collect(),
748        }
749    }
750}
751
752impl<A: Ord, B: Ord> Extend<(A, B)> for BinaryRelation<A, B> {
753    fn extend<I: IntoIterator<Item = (A, B)>>(&mut self, iter: I) {
754        self.pairs.extend(iter);
755    }
756}
757
758impl<A: Ord, B: Ord> IntoIterator for BinaryRelation<A, B> {
759    type Item = (A, B);
760    type IntoIter = std::collections::btree_set::IntoIter<(A, B)>;
761
762    fn into_iter(self) -> Self::IntoIter {
763        self.pairs.into_iter()
764    }
765}
766
767impl<'a, A: Ord, B: Ord> IntoIterator for &'a BinaryRelation<A, B> {
768    type Item = &'a (A, B);
769    type IntoIter = std::collections::btree_set::Iter<'a, (A, B)>;
770
771    fn into_iter(self) -> Self::IntoIter {
772        self.pairs.iter()
773    }
774}