1use crate::error::{Error, Result};
14use hashbrown::{HashMap, HashSet};
15use itertools::Itertools;
16use std::fmt::{self, Debug, Display};
17use std::hash::Hash;
18use std::ops::{Add, Mul};
19use std::time::Duration;
20
21pub trait Element:
24 Ord + Clone + Hash + Debug + Display + Send + Sync + 'static
25{
26}
27
28impl<T> Element for T where
29 T: Ord + Clone + Hash + Debug + Display + Send + Sync + 'static
30{
31}
32
33#[derive(Debug, Clone)]
39pub struct Node<T: Element> {
40 x: T,
41 read_capacity: f64,
42 write_capacity: f64,
43 latency: Duration,
44}
45
46impl<T: Element> PartialEq for Node<T> {
47 fn eq(&self, other: &Self) -> bool {
48 self.x == other.x
49 }
50}
51
52impl<T: Element> Eq for Node<T> {}
53
54impl<T: Element> Hash for Node<T> {
55 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
56 self.x.hash(state);
57 }
58}
59
60impl<T: Element> PartialOrd for Node<T> {
61 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
62 Some(self.cmp(other))
63 }
64}
65
66impl<T: Element> Ord for Node<T> {
67 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
68 self.x.cmp(&other.x)
69 }
70}
71
72impl<T: Element> Display for Node<T> {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 write!(f, "{}", self.x)
75 }
76}
77
78fn check_capacity(name: &str, c: f64) -> Result<f64> {
79 if c.is_finite() && c > 0.0 {
80 Ok(c)
81 } else {
82 Err(Error::InvalidExpression(format!(
83 "{name} must be finite and > 0, got {c}"
84 )))
85 }
86}
87
88impl<T: Element> Node<T> {
89 #[must_use]
91 pub fn new(x: T) -> Self {
92 Self {
93 x,
94 read_capacity: 1.0,
95 write_capacity: 1.0,
96 latency: Duration::from_secs(1),
97 }
98 }
99
100 pub fn with_capacity(self, capacity: f64) -> Result<Self> {
106 self.with_read_write_capacity(capacity, capacity)
107 }
108
109 pub fn with_read_write_capacity(
115 mut self,
116 read: f64,
117 write: f64,
118 ) -> Result<Self> {
119 self.read_capacity = check_capacity("read capacity", read)?;
120 self.write_capacity = check_capacity("write capacity", write)?;
121 Ok(self)
122 }
123
124 #[must_use]
126 pub fn with_latency(mut self, latency: Duration) -> Self {
127 self.latency = latency;
128 self
129 }
130
131 #[must_use]
133 pub fn x(&self) -> &T {
134 &self.x
135 }
136
137 #[must_use]
139 pub fn read_capacity(&self) -> f64 {
140 self.read_capacity
141 }
142
143 #[must_use]
145 pub fn write_capacity(&self) -> f64 {
146 self.write_capacity
147 }
148
149 #[must_use]
151 pub fn latency(&self) -> Duration {
152 self.latency
153 }
154}
155
156#[derive(Debug, Clone, PartialEq)]
158pub enum Expr<T: Element> {
159 Node(Node<T>),
161 Or(Or<T>),
163 And(And<T>),
165 Choose(Choose<T>),
167}
168
169#[derive(Debug, Clone, PartialEq)]
171pub struct Or<T: Element> {
172 children: Vec<Expr<T>>,
173}
174
175#[derive(Debug, Clone, PartialEq)]
177pub struct And<T: Element> {
178 children: Vec<Expr<T>>,
179}
180
181#[derive(Debug, Clone, PartialEq)]
183pub struct Choose<T: Element> {
184 k: usize,
185 children: Vec<Expr<T>>,
186}
187
188fn non_empty<T: Element>(
189 what: &str,
190 children: Vec<Expr<T>>,
191) -> Result<Vec<Expr<T>>> {
192 if children.is_empty() {
193 Err(Error::InvalidExpression(format!(
194 "{what} cannot be constructed with an empty list"
195 )))
196 } else {
197 Ok(children)
198 }
199}
200
201fn check_k(k: usize, n: usize) -> Result<()> {
202 if k == 0 || k > n {
203 Err(Error::InvalidExpression(format!(
204 "k must be in the range [1, {n}], got {k}"
205 )))
206 } else {
207 Ok(())
208 }
209}
210
211impl<T: Element> Or<T> {
212 pub fn new(children: Vec<Expr<T>>) -> Result<Self> {
217 Ok(Self { children: non_empty("Or", children)? })
218 }
219
220 #[must_use]
222 pub fn children(&self) -> &[Expr<T>] {
223 &self.children
224 }
225}
226
227impl<T: Element> And<T> {
228 pub fn new(children: Vec<Expr<T>>) -> Result<Self> {
233 Ok(Self { children: non_empty("And", children)? })
234 }
235
236 #[must_use]
238 pub fn children(&self) -> &[Expr<T>] {
239 &self.children
240 }
241}
242
243impl<T: Element> Choose<T> {
244 pub fn new(k: usize, children: Vec<Expr<T>>) -> Result<Self> {
250 check_k(k, children.len())?;
251 Ok(Self { k, children })
252 }
253
254 #[must_use]
256 pub fn k(&self) -> usize {
257 self.k
258 }
259
260 #[must_use]
262 pub fn children(&self) -> &[Expr<T>] {
263 &self.children
264 }
265}
266
267fn write_joined<T: Element>(
270 f: &mut fmt::Formatter<'_>,
271 children: &[Expr<T>],
272 sep: &str,
273) -> fmt::Result {
274 for (i, child) in children.iter().enumerate() {
275 if i > 0 {
276 f.write_str(sep)?;
277 }
278 write!(f, "{child}")?;
279 }
280 Ok(())
281}
282
283impl<T: Element> Display for Expr<T> {
284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285 match self {
286 Expr::Node(n) => write!(f, "{n}"),
287 Expr::Or(o) => write!(f, "{o}"),
288 Expr::And(a) => write!(f, "{a}"),
289 Expr::Choose(c) => write!(f, "{c}"),
290 }
291 }
292}
293
294impl<T: Element> Display for Or<T> {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 f.write_str("(")?;
297 write_joined(f, &self.children, " + ")?;
298 f.write_str(")")
299 }
300}
301
302impl<T: Element> Display for And<T> {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 f.write_str("(")?;
305 write_joined(f, &self.children, " * ")?;
306 f.write_str(")")
307 }
308}
309
310impl<T: Element> Display for Choose<T> {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 write!(f, "choose{}(", self.k)?;
313 write_joined(f, &self.children, ", ")?;
314 f.write_str(")")
315 }
316}
317
318impl<T: Element> Expr<T> {
321 pub fn quorums(&self) -> Box<dyn Iterator<Item = HashSet<T>> + '_> {
327 match self {
328 Expr::Node(node) => {
329 let mut s = HashSet::with_capacity(1);
330 s.insert(node.x.clone());
331 Box::new(std::iter::once(s))
332 }
333 Expr::Or(or) => {
334 Box::new(or.children.iter().flat_map(Expr::quorums))
335 }
336 Expr::And(and) => Box::new(and_quorums(&and.children)),
337 Expr::Choose(ch) => Box::new(choose_quorums(ch.k, &ch.children)),
338 }
339 }
340
341 #[must_use]
343 pub fn is_quorum(&self, xs: &HashSet<T>) -> bool {
344 match self {
345 Expr::Node(node) => xs.contains(&node.x),
346 Expr::Or(or) => or.children.iter().any(|e| e.is_quorum(xs)),
347 Expr::And(and) => and.children.iter().all(|e| e.is_quorum(xs)),
348 Expr::Choose(ch) => {
349 ch.children.iter().filter(|e| e.is_quorum(xs)).count() >= ch.k
350 }
351 }
352 }
353
354 #[must_use]
356 pub fn elements(&self) -> HashSet<T> {
357 self.nodes().into_iter().map(|n| n.x).collect()
358 }
359
360 #[must_use]
366 pub fn nodes(&self) -> HashSet<Node<T>> {
367 let mut out = HashSet::new();
368 self.collect_nodes(&mut out);
369 out
370 }
371
372 fn collect_nodes(&self, out: &mut HashSet<Node<T>>) {
373 match self {
374 Expr::Node(node) => {
375 if !out.contains(node) {
376 out.insert(node.clone());
377 }
378 }
379 Expr::Or(Or { children })
380 | Expr::And(And { children })
381 | Expr::Choose(Choose { children, .. }) => {
382 for c in children {
383 c.collect_nodes(out);
384 }
385 }
386 }
387 }
388
389 #[must_use]
394 pub fn dual(&self) -> Self {
395 match self {
396 Expr::Node(_) => self.clone(),
397 Expr::Or(or) => Expr::And(And {
398 children: or.children.iter().map(Expr::dual).collect(),
399 }),
400 Expr::And(and) => Expr::Or(Or {
401 children: and.children.iter().map(Expr::dual).collect(),
402 }),
403 Expr::Choose(ch) => Expr::Choose(Choose {
404 k: ch.children.len() - ch.k + 1,
405 children: ch.children.iter().map(Expr::dual).collect(),
406 }),
407 }
408 }
409
410 #[must_use]
412 pub fn dup_free(&self) -> bool {
413 self.elements().len() == self.num_leaves()
414 }
415
416 #[must_use]
423 pub fn resilience(&self) -> usize {
424 let min_failures = if self.dup_free() {
425 self.dup_free_min_failures()
426 } else {
427 min_hitting_set(self)
428 };
429 min_failures.saturating_sub(1)
430 }
431
432 fn num_leaves(&self) -> usize {
433 match self {
434 Expr::Node(_) => 1,
435 Expr::Or(Or { children })
436 | Expr::And(And { children })
437 | Expr::Choose(Choose { children, .. }) => {
438 children.iter().map(Expr::num_leaves).sum()
439 }
440 }
441 }
442
443 fn dup_free_min_failures(&self) -> usize {
446 match self {
447 Expr::Node(_) => 1,
448 Expr::Or(or) => {
449 or.children.iter().map(Expr::dup_free_min_failures).sum()
450 }
451 Expr::And(and) => and
452 .children
453 .iter()
454 .map(Expr::dup_free_min_failures)
455 .min()
456 .unwrap_or(0),
457 Expr::Choose(ch) => {
458 let mut subfailures: Vec<usize> = ch
459 .children
460 .iter()
461 .map(Expr::dup_free_min_failures)
462 .collect();
463 subfailures.sort_unstable();
464 subfailures.iter().take(ch.children.len() - ch.k + 1).sum()
465 }
466 }
467 }
468}
469
470fn and_quorums<T: Element>(
472 children: &[Expr<T>],
473) -> impl Iterator<Item = HashSet<T>> + '_ {
474 let child_quorums: Vec<Vec<HashSet<T>>> =
475 children.iter().map(|e| e.quorums().collect()).collect();
476 union_product(child_quorums)
477}
478
479fn choose_quorums<T: Element>(
481 k: usize,
482 children: &[Expr<T>],
483) -> impl Iterator<Item = HashSet<T>> + '_ {
484 let child_quorums: Vec<Vec<HashSet<T>>> =
485 children.iter().map(|e| e.quorums().collect()).collect();
486 (0..children.len()).combinations(k).flat_map(move |combo| {
487 union_product(combo.iter().map(|&i| child_quorums[i].clone()).collect())
488 })
489}
490
491fn union_product<T: Element>(
492 parts: Vec<Vec<HashSet<T>>>,
493) -> impl Iterator<Item = HashSet<T>> {
494 parts.into_iter().multi_cartesian_product().map(|subquorums| {
495 subquorums.into_iter().fold(HashSet::new(), |mut acc, q| {
496 acc.extend(q);
497 acc
498 })
499 })
500}
501
502pub(crate) fn minimize<T: Element>(
505 mut sets: Vec<HashSet<T>>,
506) -> Vec<HashSet<T>> {
507 sets.sort_by_key(HashSet::len);
508 let mut minimal: Vec<HashSet<T>> = Vec::new();
509 for s in sets {
510 if !minimal.iter().any(|m| s.is_superset(m)) {
511 minimal.push(s);
512 }
513 }
514 minimal
515}
516
517fn min_hitting_set<T: Element>(e: &Expr<T>) -> usize {
519 min_hitting_set_of(minimize(e.quorums().collect()))
520}
521
522fn min_hitting_set_of<T: Element>(sets: Vec<HashSet<T>>) -> usize {
530 let mut index: HashMap<T, usize> = HashMap::new();
531 let sets: Vec<Vec<usize>> = sets
532 .into_iter()
533 .map(|q| {
534 q.into_iter()
535 .map(|x| {
536 let n = index.len();
537 *index.entry(x).or_insert(n)
538 })
539 .collect()
540 })
541 .collect();
542 let mut best = index.len();
543 let mut chosen = vec![false; index.len()];
544 hitting_set_search(&sets, &mut chosen, 0, &mut best);
545 best
546}
547
548fn hitting_set_search(
549 sets: &[Vec<usize>],
550 chosen: &mut [bool],
551 size: usize,
552 best: &mut usize,
553) {
554 if size >= *best {
555 return;
556 }
557 let Some(unhit) = sets.iter().find(|s| !s.iter().any(|&i| chosen[i]))
558 else {
559 *best = size;
560 return;
561 };
562 for &i in unhit {
563 chosen[i] = true;
564 hitting_set_search(sets, chosen, size + 1, best);
565 chosen[i] = false;
566 }
567}
568
569impl<T: Element> Add for Expr<T> {
574 type Output = Expr<T>;
575
576 fn add(self, rhs: Self) -> Self::Output {
577 let mut children = Vec::new();
578 for e in [self, rhs] {
579 match e {
580 Expr::Or(or) => children.extend(or.children),
581 other => children.push(other),
582 }
583 }
584 Expr::Or(Or { children })
585 }
586}
587
588impl<T: Element> Mul for Expr<T> {
591 type Output = Expr<T>;
592
593 fn mul(self, rhs: Self) -> Self::Output {
594 let mut children = Vec::new();
595 for e in [self, rhs] {
596 match e {
597 Expr::And(and) => children.extend(and.children),
598 other => children.push(other),
599 }
600 }
601 Expr::And(And { children })
602 }
603}
604
605impl<T: Element> From<Node<T>> for Expr<T> {
606 fn from(node: Node<T>) -> Self {
607 Expr::Node(node)
608 }
609}
610
611impl<T: Element> From<Or<T>> for Expr<T> {
612 fn from(e: Or<T>) -> Self {
613 Expr::Or(e)
614 }
615}
616
617impl<T: Element> From<And<T>> for Expr<T> {
618 fn from(e: And<T>) -> Self {
619 Expr::And(e)
620 }
621}
622
623impl<T: Element> From<Choose<T>> for Expr<T> {
624 fn from(e: Choose<T>) -> Self {
625 Expr::Choose(e)
626 }
627}
628
629pub fn choose<T: Element>(k: usize, exprs: Vec<Expr<T>>) -> Result<Expr<T>> {
638 let exprs = non_empty("choose", exprs)?;
639 check_k(k, exprs.len())?;
640 Ok(if k == 1 {
641 Expr::Or(Or { children: exprs })
642 } else if k == exprs.len() {
643 Expr::And(And { children: exprs })
644 } else {
645 Expr::Choose(Choose { k, children: exprs })
646 })
647}
648
649pub fn majority<T: Element>(exprs: Vec<Expr<T>>) -> Result<Expr<T>> {
655 let k = exprs.len() / 2 + 1;
656 choose(k, exprs)
657}
658
659#[cfg(test)]
660#[expect(clippy::unwrap_used)]
661mod tests {
662 use super::*;
663 use hashbrown::HashSet;
664
665 fn n(x: &str) -> Expr<String> {
666 Expr::Node(Node::new(x.to_string()))
667 }
668
669 fn set(items: &[&str]) -> HashSet<String> {
670 items.iter().map(|s| (*s).to_string()).collect()
671 }
672
673 fn quorum_set(e: &Expr<String>) -> HashSet<Vec<String>> {
674 e.quorums()
675 .map(|q| {
676 let mut v: Vec<String> = q.into_iter().collect();
677 v.sort();
678 v
679 })
680 .collect()
681 }
682
683 fn sorted_set(items: &[&str]) -> Vec<String> {
684 let mut v: Vec<String> =
685 items.iter().map(|s| (*s).to_string()).collect();
686 v.sort();
687 v.dedup();
688 v
689 }
690
691 fn assert_quorums(e: &Expr<String>, expected: &[&[&str]]) {
692 let got = quorum_set(e);
693 let want: HashSet<Vec<String>> =
694 expected.iter().map(|s| sorted_set(s)).collect();
695 assert_eq!(got, want, "quorums mismatch");
696 }
697
698 #[test]
701 fn test_quorums_or() {
702 let e = n("a") + n("b") + n("c");
703 assert_quorums(&e, &[&["a"], &["b"], &["c"]]);
704 }
705
706 #[test]
707 fn test_quorums_and() {
708 let e = n("a") * n("b") * n("c");
709 assert_quorums(&e, &[&["a", "b", "c"]]);
710 }
711
712 #[test]
713 fn test_quorums_mixed() {
714 let e = n("a") + n("b") * n("c");
715 assert_quorums(&e, &[&["a"], &["b", "c"]]);
716 }
717
718 #[test]
719 fn test_quorums_dup_and() {
720 let e = n("a") * n("a") * n("a");
721 assert_quorums(&e, &[&["a"]]);
722 }
723
724 #[test]
725 fn test_quorums_dup_or() {
726 let e = n("a") + n("a") + n("a");
727 assert_quorums(&e, &[&["a"]]);
728 }
729
730 #[test]
731 fn test_quorums_node_times_or() {
732 let e = n("a") * (n("a") + n("b"));
733 assert_quorums(&e, &[&["a"], &["a", "b"]]);
734 }
735
736 #[test]
737 fn test_quorums_choose_1() {
738 let e = choose(1, vec![n("a"), n("b"), n("c")]).unwrap();
739 assert_quorums(&e, &[&["a"], &["b"], &["c"]]);
740 }
741
742 #[test]
743 fn test_quorums_choose_2() {
744 let e = choose(2, vec![n("a"), n("b"), n("c")]).unwrap();
745 assert_quorums(&e, &[&["a", "b"], &["a", "c"], &["b", "c"]]);
746 }
747
748 #[test]
749 fn test_quorums_choose_3() {
750 let e = choose(3, vec![n("a"), n("b"), n("c")]).unwrap();
751 assert_quorums(&e, &[&["a", "b", "c"]]);
752 }
753
754 #[test]
755 fn test_quorums_cross_product() {
756 let e = (n("a") + n("b")) * (n("c") + n("d"));
757 assert_quorums(
758 &e,
759 &[&["a", "c"], &["a", "d"], &["b", "c"], &["b", "d"]],
760 );
761 }
762
763 #[test]
764 fn test_quorums_cross_product_dup() {
765 let e = (n("a") + n("b")) * (n("a") + n("c"));
766 assert_quorums(&e, &[&["a"], &["a", "c"], &["a", "b"], &["b", "c"]]);
767 }
768
769 #[test]
770 fn test_quorums_nested_choose() {
771 let e = choose(
772 2,
773 vec![
774 choose(2, vec![n("a"), n("b"), n("c")]).unwrap(),
775 choose(2, vec![n("d"), n("e"), n("f")]).unwrap(),
776 choose(2, vec![n("a"), n("c"), n("e")]).unwrap(),
777 ],
778 )
779 .unwrap();
780
781 let qs = quorum_set(&e);
785 assert!(qs.contains(&sorted_set(&["a", "b", "d", "e"])));
787 assert!(qs.contains(&sorted_set(&["b", "c", "d", "f"])));
788 assert!(qs.contains(&sorted_set(&["a", "c", "e", "f"])));
789 }
790
791 #[test]
794 fn test_is_quorum_or() {
795 let expr = n("a") + n("b") + n("c");
796 assert!(expr.is_quorum(&set(&["a"])));
797 assert!(expr.is_quorum(&set(&["b"])));
798 assert!(expr.is_quorum(&set(&["c"])));
799 assert!(expr.is_quorum(&set(&["a", "b"])));
800 assert!(expr.is_quorum(&set(&["a", "c"])));
801 assert!(expr.is_quorum(&set(&["b", "c"])));
802 assert!(expr.is_quorum(&set(&["a", "b", "c"])));
803 assert!(expr.is_quorum(&set(&["a", "x"])));
804 assert!(!expr.is_quorum(&set(&[])));
805 assert!(!expr.is_quorum(&set(&["x"])));
806 }
807
808 #[test]
809 fn test_is_quorum_and() {
810 let expr = n("a") * n("b") * n("c");
811 assert!(expr.is_quorum(&set(&["a", "b", "c"])));
812 assert!(expr.is_quorum(&set(&["a", "b", "c", "x"])));
813 assert!(!expr.is_quorum(&set(&[])));
814 assert!(!expr.is_quorum(&set(&["a"])));
815 assert!(!expr.is_quorum(&set(&["b"])));
816 assert!(!expr.is_quorum(&set(&["c"])));
817 assert!(!expr.is_quorum(&set(&["a", "b"])));
818 assert!(!expr.is_quorum(&set(&["a", "c"])));
819 assert!(!expr.is_quorum(&set(&["b", "c"])));
820 assert!(!expr.is_quorum(&set(&["x"])));
821 assert!(!expr.is_quorum(&set(&["a", "x"])));
822 }
823
824 #[test]
825 fn test_is_quorum_choose() {
826 let expr = choose(2, vec![n("a"), n("b"), n("c")]).unwrap();
827 assert!(expr.is_quorum(&set(&["a", "b"])));
828 assert!(expr.is_quorum(&set(&["a", "c"])));
829 assert!(expr.is_quorum(&set(&["b", "c"])));
830 assert!(expr.is_quorum(&set(&["a", "b", "c"])));
831 assert!(expr.is_quorum(&set(&["a", "b", "c", "x"])));
832 assert!(!expr.is_quorum(&set(&["a"])));
833 assert!(!expr.is_quorum(&set(&["b"])));
834 assert!(!expr.is_quorum(&set(&["c"])));
835 assert!(!expr.is_quorum(&set(&["x"])));
836 }
837
838 #[test]
839 fn test_is_quorum_cross_product() {
840 let expr = (n("a") + n("b")) * (n("c") + n("d"));
841 assert!(expr.is_quorum(&set(&["a", "c"])));
842 assert!(expr.is_quorum(&set(&["a", "d"])));
843 assert!(expr.is_quorum(&set(&["b", "c"])));
844 assert!(expr.is_quorum(&set(&["b", "d"])));
845 assert!(expr.is_quorum(&set(&["a", "b", "d"])));
846 assert!(expr.is_quorum(&set(&["b", "c", "d"])));
847 assert!(expr.is_quorum(&set(&["a", "c", "d"])));
848 assert!(expr.is_quorum(&set(&["a", "b", "c", "d"])));
849 assert!(!expr.is_quorum(&set(&["a"])));
850 assert!(!expr.is_quorum(&set(&["b"])));
851 assert!(!expr.is_quorum(&set(&["c"])));
852 assert!(!expr.is_quorum(&set(&["d"])));
853 assert!(!expr.is_quorum(&set(&["a", "b"])));
854 assert!(!expr.is_quorum(&set(&["c", "d"])));
855 assert!(!expr.is_quorum(&set(&["a", "b", "x"])));
856 }
857
858 #[test]
861 fn test_resilience_single() {
862 assert_eq!(n("a").resilience(), 0);
863 }
864
865 #[test]
866 fn test_resilience_or() {
867 assert_eq!((n("a") + n("b")).resilience(), 1);
868 assert_eq!((n("a") + n("b") + n("c")).resilience(), 2);
869 assert_eq!((n("a") + n("b") + n("c") + n("d")).resilience(), 3);
870 }
871
872 #[test]
873 fn test_resilience_and() {
874 assert_eq!((n("a") * n("b")).resilience(), 0);
875 assert_eq!((n("a") * n("b") * n("c")).resilience(), 0);
876 assert_eq!((n("a") * n("b") * n("c") * n("d")).resilience(), 0);
877 }
878
879 #[test]
880 fn test_resilience_mixed() {
881 assert_eq!(((n("a") + n("b")) * (n("c") + n("d"))).resilience(), 1);
882 assert_eq!(
883 ((n("a") + n("b") + n("c")) * (n("d") + n("e") + n("f")))
884 .resilience(),
885 2
886 );
887 }
888
889 #[test]
890 fn test_resilience_dup() {
891 assert_eq!(
893 ((n("a") + n("b") + n("c")) * (n("a") + n("e") + n("f")))
894 .resilience(),
895 2
896 );
897 assert_eq!(
898 ((n("a") + n("a") + n("c")) * (n("d") + n("e") + n("f")))
899 .resilience(),
900 1
901 );
902 assert_eq!(
903 ((n("a") + n("a") + n("a")) * (n("d") + n("e") + n("f")))
904 .resilience(),
905 0
906 );
907 assert_eq!(
908 (n("a") * n("b")
909 + n("b") * n("c")
910 + n("a") * n("d")
911 + n("a") * n("d") * n("e"))
912 .resilience(),
913 1
914 );
915 }
916
917 #[test]
918 fn test_resilience_choose() {
919 let ch2_3 = choose(2, vec![n("a"), n("b"), n("c")]).unwrap();
920 assert_eq!(ch2_3.resilience(), 1);
921
922 let ch2_5 =
923 choose(2, vec![n("a"), n("b"), n("c"), n("d"), n("e")]).unwrap();
924 assert_eq!(ch2_5.resilience(), 3);
925
926 let ch3_5 =
927 choose(3, vec![n("a"), n("b"), n("c"), n("d"), n("e")]).unwrap();
928 assert_eq!(ch3_5.resilience(), 2);
929
930 let ch4_5 =
931 choose(4, vec![n("a"), n("b"), n("c"), n("d"), n("e")]).unwrap();
932 assert_eq!(ch4_5.resilience(), 1);
933 }
934
935 #[test]
936 fn test_resilience_choose_compound() {
937 let e1 =
938 choose(2, vec![n("a") + n("b") + n("c"), n("d") + n("e"), n("f")])
939 .unwrap();
940 assert_eq!(e1.resilience(), 2);
941
942 let e2 =
943 choose(2, vec![n("a") * n("b"), n("a") * n("c"), n("d")]).unwrap();
944 assert_eq!(e2.resilience(), 0);
945
946 let e3 =
947 choose(2, vec![n("a") + n("b"), n("a") + n("c"), n("a") + n("d")])
948 .unwrap();
949 assert_eq!(e3.resilience(), 2);
950 }
951
952 fn assert_dual(x: &Expr<String>, y: &Expr<String>) {
955 let x_dual = x.dual();
956 let x_qs = quorum_set(&x_dual);
957 let y_qs = quorum_set(y);
958 assert_eq!(x_qs, y_qs, "dual mismatch");
959 }
960
961 #[test]
962 fn test_dual_node() {
963 assert_dual(&n("a"), &n("a"));
964 }
965
966 #[test]
967 fn test_dual_or_and() {
968 assert_dual(&(n("a") + n("b")), &(n("a") * n("b")));
969 }
970
971 #[test]
972 fn test_dual_dup() {
973 assert_dual(&(n("a") + n("a")), &(n("a") * n("a")));
974 }
975
976 #[test]
977 fn test_dual_compound() {
978 assert_dual(
979 &((n("a") + n("b")) * (n("c") + n("d"))),
980 &((n("a") * n("b")) + (n("c") * n("d"))),
981 );
982 assert_dual(
983 &((n("a") + n("b")) * (n("a") + n("d"))),
984 &((n("a") * n("b")) + (n("a") * n("d"))),
985 );
986 assert_dual(
987 &((n("a") + n("b")) * (n("a") + n("a"))),
988 &((n("a") * n("b")) + (n("a") * n("a"))),
989 );
990 assert_dual(
991 &((n("a") + n("a")) * (n("a") + n("a"))),
992 &((n("a") * n("a")) + (n("a") * n("a"))),
993 );
994 }
995
996 #[test]
997 fn test_dual_nested() {
998 assert_dual(
999 &((n("a") + (n("a") * n("b"))) + ((n("c") * n("d")) + n("a"))),
1000 &((n("a") * (n("a") + n("b"))) * ((n("c") + n("d")) * n("a"))),
1001 );
1002 }
1003
1004 #[test]
1005 fn test_dual_choose() {
1006 let ch2_3 = choose(2, vec![n("a"), n("b"), n("c")]).unwrap();
1007 let ch2_3b = choose(2, vec![n("a"), n("b"), n("c")]).unwrap();
1008 assert_dual(&ch2_3, &ch2_3b);
1009
1010 let ch2_ab_cd_e =
1011 choose(2, vec![n("a") + n("b"), n("c") + n("d"), n("e")]).unwrap();
1012 let ch2_ab_cd_e_dual =
1013 choose(2, vec![n("a") * n("b"), n("c") * n("d"), n("e")]).unwrap();
1014 assert_dual(&ch2_ab_cd_e, &ch2_ab_cd_e_dual);
1015
1016 let ch3_5 =
1017 choose(3, vec![n("a"), n("b"), n("c"), n("d"), n("e")]).unwrap();
1018 let ch3_5b =
1019 choose(3, vec![n("a"), n("b"), n("c"), n("d"), n("e")]).unwrap();
1020 assert_dual(&ch3_5, &ch3_5b);
1021
1022 let ch2_5 =
1023 choose(2, vec![n("a"), n("b"), n("c"), n("d"), n("e")]).unwrap();
1024 let ch4_5 =
1025 choose(4, vec![n("a"), n("b"), n("c"), n("d"), n("e")]).unwrap();
1026 assert_dual(&ch2_5, &ch4_5);
1027 assert_dual(&ch4_5, &ch2_5);
1028 }
1029
1030 #[test]
1033 fn test_dup_free() {
1034 assert!(n("a").dup_free());
1035 assert!((n("a") + n("b")).dup_free());
1036 assert!((n("a") * n("b")).dup_free());
1037 assert!((n("a") * n("b") + n("c")).dup_free());
1038
1039 let ch = choose(2, vec![n("a"), n("b"), n("c")]).unwrap();
1040 assert!(ch.dup_free());
1041
1042 let ch2 =
1043 choose(2, vec![n("a") * n("b"), n("c"), n("d") + n("e") + n("f")])
1044 .unwrap();
1045 assert!(ch2.dup_free());
1046
1047 let ch3 =
1048 choose(3, vec![n("a"), n("b"), n("c"), n("d"), n("e")]).unwrap();
1049 assert!(ch3.dup_free());
1050
1051 assert!(((n("a") + n("b")) * (n("c") + (n("d") * n("e")))).dup_free());
1052 }
1053
1054 #[test]
1055 fn test_not_dup_free() {
1056 assert!(!(n("a") + n("a")).dup_free());
1057 assert!(!(n("a") * n("a")).dup_free());
1058 assert!(!(n("a") * (n("b") + n("a"))).dup_free());
1059
1060 let ch = choose(2, vec![n("a"), n("b"), n("a")]).unwrap();
1061 assert!(!ch.dup_free());
1062
1063 let ch2 =
1064 choose(3, vec![n("a"), n("b"), n("c"), n("d"), n("a")]).unwrap();
1065 assert!(!ch2.dup_free());
1066
1067 assert!(!((n("a") + n("b")) * (n("c") + (n("d") * n("a")))).dup_free());
1068 }
1069
1070 #[test]
1073 fn test_choose_returns_or_for_k1() {
1074 let e = choose(1, vec![n("a"), n("b"), n("c")]).unwrap();
1075 assert!(matches!(e, Expr::Or(_)));
1076 }
1077
1078 #[test]
1079 fn test_choose_returns_and_for_k_eq_n() {
1080 let e = choose(3, vec![n("a"), n("b"), n("c")]).unwrap();
1081 assert!(matches!(e, Expr::And(_)));
1082 }
1083
1084 #[test]
1085 fn test_choose_returns_choose_for_middle_k() {
1086 let e = choose(2, vec![n("a"), n("b"), n("c")]).unwrap();
1087 assert!(matches!(e, Expr::Choose(_)));
1088 }
1089
1090 #[test]
1091 fn test_choose_errors() {
1092 assert!(choose::<String>(0, vec![]).is_err());
1093 assert!(choose(0, vec![n("a")]).is_err());
1094 assert!(choose(2, vec![n("a")]).is_err());
1095 }
1096
1097 #[test]
1098 fn test_majority() {
1099 let e = majority(vec![n("a"), n("b"), n("c")]).unwrap();
1100 assert_quorums(&e, &[&["a", "b"], &["a", "c"], &["b", "c"]]);
1101 }
1102
1103 fn mhs(vecs: &[&[&str]]) -> usize {
1106 min_hitting_set_of(vecs.iter().map(|v| set(v)).collect())
1107 }
1108
1109 #[test]
1110 fn test_min_hitting_set() {
1111 assert_eq!(mhs(&[]), 0);
1112 assert_eq!(mhs(&[&["a"]]), 1);
1113 assert_eq!(mhs(&[&["a"], &["b"]]), 2);
1114 assert_eq!(mhs(&[&["a", "b"], &["b", "c"]]), 1);
1115 assert_eq!(mhs(&[&["a"], &["b"], &["c"]]), 3);
1116 assert_eq!(mhs(&[&["a", "b", "c"]]), 1);
1117 assert_eq!(
1118 mhs(&[&["a", "c"], &["a", "d"], &["b", "c"], &["b", "d"]]),
1119 2
1120 );
1121 assert_eq!(mhs(&[&["a", "b"], &["a", "c"], &["b", "c"]]), 2);
1122 assert_eq!(
1123 mhs(&[&["a", "b"], &["b", "c"], &["a", "d"], &["a", "d", "e"]]),
1124 2
1125 );
1126 let xs = ["a", "b", "c", "d", "e"];
1128 let pairs: Vec<HashSet<String>> =
1129 xs.iter().array_combinations().map(|[p, q]| set(&[p, q])).collect();
1130 assert_eq!(min_hitting_set_of(pairs), 4);
1131 }
1132
1133 #[test]
1136 fn test_node_builders_and_accessors() {
1137 let a = Node::new("a")
1138 .with_capacity(4.0)
1139 .unwrap()
1140 .with_latency(Duration::from_millis(5));
1141 assert_eq!(*a.x(), "a");
1142 assert_eq!(a.read_capacity().to_bits(), 4.0_f64.to_bits());
1143 assert_eq!(a.write_capacity().to_bits(), 4.0_f64.to_bits());
1144 assert_eq!(a.latency(), Duration::from_millis(5));
1145 let b = Node::new("b").with_read_write_capacity(2.0, 3.0).unwrap();
1146 assert!(b.read_capacity() < b.write_capacity());
1147 for bad in [0.0, -1.0, f64::NAN, f64::INFINITY] {
1148 assert!(Node::new("a").with_capacity(bad).is_err());
1149 assert!(Node::new("a").with_read_write_capacity(1.0, bad).is_err());
1150 }
1151 assert_eq!(a, Node::new("a"));
1153 assert!(Node::new("a") < Node::new("b"));
1154 assert_eq!(
1155 Node::new("a").partial_cmp(&Node::new("b")),
1156 Some(std::cmp::Ordering::Less)
1157 );
1158 }
1159
1160 #[test]
1161 fn test_combinator_constructors() {
1162 assert!(Or::<String>::new(vec![]).is_err());
1163 assert!(And::<String>::new(vec![]).is_err());
1164 assert!(Choose::<String>::new(1, vec![]).is_err());
1165 assert!(Choose::new(0, vec![n("a")]).is_err());
1166 assert!(Choose::new(2, vec![n("a")]).is_err());
1167
1168 let or = Or::new(vec![n("a"), n("b")]).unwrap();
1169 assert_eq!(or.children().len(), 2);
1170 let and = And::new(vec![n("a"), n("b")]).unwrap();
1171 assert_eq!(and.children().len(), 2);
1172 let ch = Choose::new(2, vec![n("a"), n("b"), n("c")]).unwrap();
1173 assert_eq!(ch.k(), 2);
1174 assert_eq!(ch.children().len(), 3);
1175
1176 let e: Expr<String> = ch.into();
1177 assert_eq!(e.to_string(), "choose2(a, b, c)");
1178 assert_eq!(Expr::from(or).to_string(), "(a + b)");
1179 assert_eq!(Expr::from(and).to_string(), "(a * b)");
1180 assert_eq!(Expr::from(Node::new("z".to_string())).to_string(), "z");
1181 assert_eq!(e.dual().to_string(), "choose2(a, b, c)");
1182 }
1183
1184 #[test]
1185 fn test_first_node_occurrence_wins() {
1186 let fast = Node::new("a".to_string()).with_latency(Duration::ZERO);
1187 let e = Expr::Node(fast) + n("a");
1188 let nodes = e.nodes();
1189 assert_eq!(nodes.len(), 1);
1190 assert!(nodes.iter().all(|x| x.latency() == Duration::ZERO));
1191 }
1192
1193 #[test]
1194 fn test_majority_errors() {
1195 assert!(majority::<String>(vec![]).is_err());
1196 }
1197}