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}