1use log::trace;
16use std::borrow::Borrow;
17use std::cmp;
18use std::rc::Rc;
19
20mod flakiness_tracker;
21use flakiness_tracker::*;
22mod range_map;
23use range_map::*;
24
25mod dag;
26
27#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
29pub struct CompressedDAGNodeRef {
30 pub segment: usize,
32 pub index: usize,
34}
35
36#[derive(Clone, Debug)]
40pub struct CompressedDAGSegment {
41 len: usize,
42}
43
44impl CompressedDAGSegment {
45 pub fn new(len: usize) -> Self {
47 CompressedDAGSegment { len }
48 }
49
50 pub fn len(&self) -> usize {
52 self.len
53 }
54}
55
56pub type CompressedDAG = dag::DAG<CompressedDAGSegment>;
90
91mod compressed_dag_flakiness_tracker;
92use compressed_dag_flakiness_tracker::*;
93
94fn confidence_percentile_nearest(range_map: &RangeMap<f64>, percentile: f64) -> (usize, f64) {
97 let mut sum = 0.0;
98 let mut index = 0;
99 let mut best_index = 0;
100 let mut best_percentile = f64::NEG_INFINITY;
101 for w in range_map.ranges() {
102 let delta = w.len() as f64 * w.value();
103 trace!(
104 "percentile = {}, sum = {}, w.value = {}",
105 percentile,
106 sum,
107 w.value()
108 );
109 trace!(
110 "(percentile - sum) / w.value() - 0.5 = {}",
111 (percentile - sum) / w.value() - 0.5
112 );
113 let ix = index
114 + cmp::min(
115 w.len() - 1,
116 ((percentile - sum) / w.value() - 0.5).max(0.0) as usize,
117 );
118 let ix_percentile = sum + (ix - index + 1) as f64 * w.value();
119 trace!("ix = {} ix_percentile = {}", ix, ix_percentile);
120 if (ix_percentile - percentile).abs() < (best_percentile - percentile).abs() {
121 best_index = ix;
122 best_percentile = ix_percentile;
123 }
124 sum += delta;
125 index += w.len();
126 }
127 assert!(best_percentile > f64::NEG_INFINITY);
128 trace!(
129 "confidence_percentile_nearest returning {:?}",
130 (best_index, best_percentile)
131 );
132 (best_index, best_percentile)
133}
134
135fn confidence_percentile_ceil(range_map: &RangeMap<f64>, percentile: f64) -> (usize, f64) {
139 let mut sum = 0.0;
140 let mut index = 0;
141 for w in range_map.ranges() {
142 let delta = w.len() as f64 * w.value();
143 if sum + delta >= percentile {
144 let ix = index + ((percentile - sum) / w.value() - 1e-9) as usize;
145 let ret = (ix, sum + (ix - index + 1) as f64 * w.value());
146 trace!("confidence_percentile_ceil returning {:?}", ret);
147 return ret;
148 }
149 sum += delta;
150 index += w.len();
151 }
152 (range_map.len() - 1, sum)
153}
154
155fn report_range(weights: &mut RangeMap<f64>, index: usize, heads: bool, stiffness: f64) {
157 if heads {
158 for w in weights.split(index).0 {
159 *w.value_mut() *= 1.0 + stiffness;
160 }
161 let (left, _right) = weights.split(index + 1);
162 *left.rev().next().unwrap().value_mut() *= 1.0 + stiffness;
163 } else {
164 weights.split(index);
165 let (_left, right) = weights.split(index + 1);
166 for w in right {
167 *w.value_mut() *= 1.0 + stiffness;
168 }
169 }
170}
171
172#[derive(Clone, Debug)]
174pub struct Searcher {
175 weights: RangeMap<f64>,
176 len: usize,
177}
178
179impl Searcher {
180 pub fn new(len: usize) -> Self {
182 Searcher {
183 weights: RangeMap::new(len + 1, 1.0 / (len as f64 + 1.0)),
184 len,
185 }
186 }
187
188 #[doc(hidden)]
195 pub fn report_with_stiffness(&mut self, index: usize, heads: bool, stiffness: f64) {
196 assert!(index < self.len);
197 report_range(&mut self.weights, index, heads, stiffness);
198 let weight_sum: f64 = self
199 .weights
200 .ranges()
201 .map(|w| w.value() * w.len() as f64)
202 .sum();
203 for w in self.weights.ranges_mut() {
204 *w.value_mut() /= weight_sum;
205 }
206 }
207
208 pub fn report(&mut self, index: usize, heads: bool, flakiness: f64) {
215 self.report_with_stiffness(index, heads, optimal_stiffness(flakiness));
216 }
217
218 pub fn next_index(&self) -> usize {
221 cmp::min(
222 confidence_percentile_nearest(&self.weights, 0.5).0,
223 self.len - 1,
224 )
225 }
226
227 pub fn best_index(&self) -> usize {
230 confidence_percentile_ceil(&self.weights, 0.5).0
231 }
232
233 #[doc(hidden)]
235 pub fn confidence_percentile_ceil(&self, percentile: f64) -> usize {
236 confidence_percentile_ceil(&self.weights, percentile).0
237 }
238
239 pub fn likelihood(&self, index: usize) -> f64 {
245 *self.weights.range_for_index(index).value()
246 }
247}
248
249fn optimal_stiffness(flakiness: f64) -> f64 {
251 (2.6 / flakiness.powf(0.37))
253 .min(0.58 / flakiness.powf(0.97))
254 .min(0.19 / flakiness.powf(2.4))
255}
256
257#[derive(Clone, Debug)]
260pub struct AutoSearcher {
261 searcher: Searcher,
262 flakiness_tracker: FlakinessTracker,
263}
264
265impl AutoSearcher {
266 pub fn new(len: usize) -> Self {
268 AutoSearcher {
269 searcher: Searcher::new(len),
270 flakiness_tracker: FlakinessTracker::default(),
271 }
272 }
273
274 pub fn report(&mut self, index: usize, heads: bool) {
281 self.flakiness_tracker.report(index, heads);
282 self.searcher
283 .report(index, heads, self.flakiness_tracker.flakiness());
284 }
285
286 pub fn next_index(&self) -> usize {
289 self.searcher.next_index()
290 }
291
292 pub fn best_index(&self) -> usize {
295 self.searcher.best_index()
296 }
297
298 pub fn likelihood(&self, index: usize) -> f64 {
304 self.searcher.likelihood(index)
305 }
306}
307
308#[derive(Clone, Debug)]
310pub struct CompressedDAGSearcher {
311 graph: Rc<CompressedDAG>,
312 segment_range_maps: Vec<RangeMap<f64>>,
313}
314
315impl CompressedDAGSearcher {
316 pub fn new(graph: Rc<CompressedDAG>) -> Self {
318 let n = graph
319 .nodes()
320 .iter()
321 .map(|node| node.value().len())
322 .fold(0, |x, y| x + y);
323 let segment_range_maps = graph
324 .nodes()
325 .iter()
326 .map(|node| RangeMap::new(node.value().len(), 1.0 / n as f64))
327 .collect();
328 CompressedDAGSearcher {
329 graph,
330 segment_range_maps,
331 }
332 }
333
334 fn segment_percentile_ranges(&self) -> Vec<(f64, f64)> {
339 let mut segment_ranges = Vec::<(f64, f64)>::new();
340 let mut segment_sums = Vec::<f64>::new();
341 let graph: &CompressedDAG = self.graph.borrow();
342 for (i, range_map) in self.segment_range_maps.iter().enumerate() {
343 let inputs = graph.node(i).inputs();
344 let start = if inputs.is_empty() {
345 0.0
346 } else {
347 let mut start = segment_ranges[inputs[0]].1;
348 for ancestor in graph.node(i).remainder_ancestors() {
349 start += segment_sums[*ancestor];
350 }
351 start
352 };
353 let mut segment_sum = 0.0;
354 for range in range_map.ranges() {
355 segment_sum += range.value() * range.len() as f64;
356 }
357 segment_sums.push(segment_sum);
358 let end = start + segment_sum;
359 assert!(
360 start >= 0.0 && start <= 1.0 + 1e-11 && end >= 0.0 && end <= 1.0 + 1e-11,
361 "i = {} of {}, start = {}, end = {}",
362 i,
363 self.segment_range_maps.len(),
364 start,
365 end
366 );
367 segment_ranges.push((start, end));
368 }
369 segment_ranges
370 }
371
372 fn confidence_percentile_nearest(&self, percentile: f64) -> CompressedDAGNodeRef {
375 let segment_ranges = self.segment_percentile_ranges();
376 trace!("segment_ranges = {:?}", segment_ranges);
377 let mut best_node = CompressedDAGNodeRef {
378 segment: 0,
379 index: 0,
380 };
381 let mut best_value = f64::NEG_INFINITY;
382 for (i, range) in segment_ranges.iter().enumerate() {
383 let (ix, mut value) =
384 confidence_percentile_nearest(&self.segment_range_maps[i], percentile - range.0);
385 value += range.0;
386 if (percentile - value).abs() < (percentile - best_value).abs() {
387 best_node = CompressedDAGNodeRef {
388 segment: i,
389 index: ix,
390 };
391 best_value = value;
392 }
393 }
394 assert!(best_value > f64::NEG_INFINITY);
395 best_node
396 }
397
398 pub fn confidence_percentile_ceil(&self, percentile: f64) -> CompressedDAGNodeRef {
401 let segment_ranges = self.segment_percentile_ranges();
402 let mut min_end = 0;
403 let mut min_end_segment = 0;
404 let mut min_end_value = f64::INFINITY;
405 for (i, range) in segment_ranges.iter().enumerate() {
406 let (ix, mut value) =
407 confidence_percentile_ceil(&self.segment_range_maps[i], percentile - range.0);
408 value += range.0;
409 trace!(
410 "i = {}, ix = {}, value = {}, min_end_value = {}",
411 i,
412 ix,
413 value,
414 min_end_value
415 );
416 if value < min_end_value && value >= percentile {
417 min_end = ix;
418 min_end_segment = i;
419 min_end_value = value;
420 }
421 }
422 let ret = CompressedDAGNodeRef {
423 segment: min_end_segment,
424 index: min_end,
425 };
426 trace!(
427 "CompressedDAGSearcher::confidence_percentile_ceil returning {:?}",
428 ret
429 );
430 ret
431 }
432
433 pub fn best_node(&self) -> CompressedDAGNodeRef {
435 self.confidence_percentile_ceil(0.5)
436 }
437
438 pub fn next_node(&self) -> CompressedDAGNodeRef {
440 self.confidence_percentile_nearest(0.5)
441 }
442
443 pub fn report(&mut self, node: CompressedDAGNodeRef, heads: bool, flakiness: f64) {
450 let stiffness = optimal_stiffness(flakiness);
451 let graph: &CompressedDAG = self.graph.borrow();
452 if heads {
453 for segment in graph.node(node.segment).ancestors() {
454 for w in self.segment_range_maps[*segment].ranges_mut() {
455 *w.value_mut() *= 1.0 + stiffness;
456 }
457 }
458 } else {
459 let ancestor_segments = graph.node(node.segment).ancestors();
460 for segment in 0..graph.nodes().len() {
461 if ancestor_segments.contains(&segment) || segment == node.segment {
462 continue;
463 }
464 for w in self.segment_range_maps[segment].ranges_mut() {
465 *w.value_mut() *= 1.0 + stiffness;
466 }
467 }
468 }
469 report_range(
470 &mut self.segment_range_maps[node.segment],
471 node.index,
472 heads,
473 stiffness,
474 );
475 let weight_sum: f64 = self
476 .segment_range_maps
477 .iter()
478 .map(|range_map| {
479 range_map
480 .ranges()
481 .map(|w| w.value() * w.len() as f64)
482 .sum::<f64>()
483 })
484 .sum();
485 for range_map in &mut self.segment_range_maps {
486 for w in range_map.ranges_mut() {
487 *w.value_mut() /= weight_sum;
488 }
489 }
490 }
491
492 pub fn likelihood(&self, node: CompressedDAGNodeRef) -> f64 {
498 *self.segment_range_maps[node.segment]
499 .range_for_index(node.index)
500 .value()
501 }
502}
503
504#[derive(Clone, Debug)]
507pub struct AutoCompressedDAGSearcher {
508 searcher: CompressedDAGSearcher,
509 flakiness_tracker: CompressedDAGFlakinessTracker,
510}
511
512impl AutoCompressedDAGSearcher {
513 pub fn new(graph: Rc<CompressedDAG>) -> Self {
515 Self {
516 searcher: CompressedDAGSearcher::new(graph.clone()),
517 flakiness_tracker: CompressedDAGFlakinessTracker::new(graph),
518 }
519 }
520
521 pub fn report(&mut self, node: CompressedDAGNodeRef, heads: bool) {
528 self.flakiness_tracker.report(node, heads);
529 self.searcher
530 .report(node, heads, self.flakiness_tracker.flakiness());
531 }
532
533 pub fn next_node(&self) -> CompressedDAGNodeRef {
535 self.searcher.next_node()
536 }
537
538 pub fn best_node(&self) -> CompressedDAGNodeRef {
540 self.searcher.best_node()
541 }
542
543 pub fn likelihood(&self, index: CompressedDAGNodeRef) -> f64 {
549 self.searcher.likelihood(index)
550 }
551
552 pub fn flakiness(&self) -> f64 {
554 self.flakiness_tracker.flakiness()
555 }
556}
557
558#[cfg(test)]
559mod tests {
560 use super::*;
561
562 const DEFAULT_FLAKINESS: f64 = 0.01;
563
564 macro_rules! assert_index {
565 ($searcher:expr, $next:expr, $best:expr, $heads:expr, $flakiness:expr) => {
566 assert_eq!($searcher.next_index(), $next, "next_index");
567 assert_eq!($searcher.best_index(), $best, "best_index");
568 $searcher.report($next, $heads, $flakiness);
569 };
570 }
571
572 #[test]
576 fn one_element_zero() {
577 let mut s = Searcher::new(1);
578 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
579 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
580 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
581 }
582
583 #[test]
584 fn one_element_one() {
585 let mut s = Searcher::new(1);
586 assert_index!(s, 0, 0, false, DEFAULT_FLAKINESS);
587 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
588 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
589 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
590 }
591
592 #[test]
593 fn two_elements_zero() {
594 let mut s = Searcher::new(2);
595 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
596 assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
597 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
598 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
599 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
600 }
601
602 #[test]
603 fn two_elements_one() {
604 let mut s = Searcher::new(2);
605 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
606 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
607 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
608 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
609 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
610 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
611 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
612 assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
613 assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
614 assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
615 }
616
617 #[test]
618 fn two_elements_two() {
619 let mut s = Searcher::new(2);
620 assert_index!(s, 1, 1, false, DEFAULT_FLAKINESS);
621 assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
622 assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
623 assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
624 }
625
626 #[test]
627 fn three_elements_zero() {
628 let mut s = Searcher::new(3);
629 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
630 assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
631 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
632 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
633 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
634 }
635
636 #[test]
637 fn three_elements_one() {
638 let mut s = Searcher::new(3);
639 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
640 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
641 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
642 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
643 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
644 assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
645 }
646
647 #[test]
648 fn three_elements_two() {
649 let mut s = Searcher::new(3);
650 assert_index!(s, 1, 1, false, DEFAULT_FLAKINESS);
651 assert_index!(s, 2, 2, true, DEFAULT_FLAKINESS);
652 assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
653 assert_index!(s, 2, 2, true, DEFAULT_FLAKINESS);
654 assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
655 assert_index!(s, 2, 2, true, DEFAULT_FLAKINESS);
656 assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
657 }
658
659 #[test]
660 fn three_elements_three() {
661 let mut s = Searcher::new(3);
662 assert_index!(s, 1, 1, false, DEFAULT_FLAKINESS);
663 assert_index!(s, 2, 2, false, DEFAULT_FLAKINESS);
664 assert_index!(s, 2, 3, false, DEFAULT_FLAKINESS);
665 assert_index!(s, 2, 3, false, DEFAULT_FLAKINESS);
666 assert_index!(s, 2, 3, false, DEFAULT_FLAKINESS);
667 }
668
669 #[test]
670 fn many_elements_first() {
671 let mut s = Searcher::new(1024);
672 assert_index!(s, 512, 512, true, DEFAULT_FLAKINESS);
673 assert_index!(s, 272, 273, true, DEFAULT_FLAKINESS);
674 assert_index!(s, 144, 145, true, DEFAULT_FLAKINESS);
675 assert_index!(s, 76, 77, true, DEFAULT_FLAKINESS);
676 assert_index!(s, 40, 41, true, DEFAULT_FLAKINESS);
677 assert_index!(s, 21, 21, true, DEFAULT_FLAKINESS);
678 assert_index!(s, 11, 11, true, DEFAULT_FLAKINESS);
679 assert_index!(s, 5, 6, true, DEFAULT_FLAKINESS);
680 assert_index!(s, 2, 3, true, DEFAULT_FLAKINESS);
681 assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
682 assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
683 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
684 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
685 assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
686 }
687
688 #[test]
689 fn many_elements_last() {
690 let mut s = Searcher::new(1024);
691 assert_index!(s, 512, 512, false, DEFAULT_FLAKINESS);
692 assert_index!(s, 751, 752, false, DEFAULT_FLAKINESS);
693 assert_index!(s, 879, 879, false, DEFAULT_FLAKINESS);
694 assert_index!(s, 947, 947, false, DEFAULT_FLAKINESS);
695 assert_index!(s, 983, 983, false, DEFAULT_FLAKINESS);
696 assert_index!(s, 1002, 1003, false, DEFAULT_FLAKINESS);
697 assert_index!(s, 1012, 1013, false, DEFAULT_FLAKINESS);
698 assert_index!(s, 1018, 1018, false, DEFAULT_FLAKINESS);
699 assert_index!(s, 1021, 1021, false, DEFAULT_FLAKINESS);
700 assert_index!(s, 1022, 1023, false, DEFAULT_FLAKINESS);
701 assert_index!(s, 1023, 1023, false, DEFAULT_FLAKINESS);
702 assert_index!(s, 1023, 1024, false, DEFAULT_FLAKINESS);
703 assert_index!(s, 1023, 1024, false, DEFAULT_FLAKINESS);
704 assert_index!(s, 1023, 1024, false, DEFAULT_FLAKINESS);
705 }
706
707 #[test]
708 fn graph_confidence_percentile_nearest_singleton() {
709 let mut graph = CompressedDAG::new();
710 graph.add_node(CompressedDAGSegment::new(1), vec![]);
711 let searcher = CompressedDAGSearcher::new(Rc::new(graph));
712 assert_eq!(
713 searcher.confidence_percentile_nearest(0.5),
714 CompressedDAGNodeRef {
715 segment: 0,
716 index: 0
717 }
718 );
719 }
720
721 #[test]
722 fn graph_confidence_percentile_nearest_single_segment() {
723 let mut graph = CompressedDAG::new();
724 graph.add_node(CompressedDAGSegment::new(10), vec![]);
725 let searcher = CompressedDAGSearcher::new(Rc::new(graph));
726 assert_eq!(
727 searcher.confidence_percentile_nearest(0.5),
728 CompressedDAGNodeRef {
729 segment: 0,
730 index: 4
731 }
732 );
733 }
734
735 #[test]
736 fn graph_confidence_percentile_nearest_parallel_segments() {
737 let mut graph = CompressedDAG::new();
738 graph.add_node(CompressedDAGSegment::new(10), vec![]);
739 graph.add_node(CompressedDAGSegment::new(10), vec![]);
740 let searcher = CompressedDAGSearcher::new(Rc::new(graph));
741 assert_eq!(
742 searcher.confidence_percentile_nearest(0.5),
743 CompressedDAGNodeRef {
744 segment: 0,
745 index: 9
746 }
747 );
748 }
749
750 #[test]
751 fn graph_confidence_percentile_nearest_parallel_unequal_segments() {
752 let mut graph = CompressedDAG::new();
753 graph.add_node(CompressedDAGSegment::new(100), vec![]);
754 graph.add_node(CompressedDAGSegment::new(10), vec![]);
755 let searcher = CompressedDAGSearcher::new(Rc::new(graph));
756 assert_eq!(
757 searcher.confidence_percentile_nearest(0.5),
758 CompressedDAGNodeRef {
759 segment: 0,
760 index: 54
761 }
762 );
763 }
764
765 #[test]
766 fn graph_confidence_percentile_nearest_parallel_unequal_segments2() {
767 let mut graph = CompressedDAG::new();
768 graph.add_node(CompressedDAGSegment::new(10), vec![]);
769 graph.add_node(CompressedDAGSegment::new(100), vec![]);
770 let searcher = CompressedDAGSearcher::new(Rc::new(graph));
771 assert_eq!(
772 searcher.confidence_percentile_nearest(0.5),
773 CompressedDAGNodeRef {
774 segment: 1,
775 index: 54
776 }
777 );
778 }
779
780 #[test]
781 fn graph_confidence_percentile_nearest_sequential_segments() {
782 let mut graph = CompressedDAG::new();
783 graph.add_node(CompressedDAGSegment::new(10), vec![]);
784 graph.add_node(CompressedDAGSegment::new(10), vec![0]);
785 graph.add_node(CompressedDAGSegment::new(10), vec![1]);
786 let searcher = CompressedDAGSearcher::new(Rc::new(graph));
787 assert_eq!(
788 searcher.confidence_percentile_nearest(0.5),
789 CompressedDAGNodeRef {
790 segment: 1,
791 index: 4
792 }
793 );
794 }
795
796 #[test]
797 fn graph_confidence_percentile_nearest_fork() {
798 let mut graph = CompressedDAG::new();
799 graph.add_node(CompressedDAGSegment::new(10), vec![]);
800 graph.add_node(CompressedDAGSegment::new(10), vec![0]);
801 graph.add_node(CompressedDAGSegment::new(10), vec![0]);
802 let searcher = CompressedDAGSearcher::new(Rc::new(graph));
803 assert_eq!(
804 searcher.confidence_percentile_nearest(0.5),
805 CompressedDAGNodeRef {
806 segment: 1,
807 index: 4
808 }
809 );
810 }
811
812 #[test]
813 fn graph_confidence_percentile_nearest_merge() {
814 let mut graph = CompressedDAG::new();
815 graph.add_node(CompressedDAGSegment::new(10), vec![]);
816 graph.add_node(CompressedDAGSegment::new(10), vec![]);
817 graph.add_node(CompressedDAGSegment::new(10), vec![0, 1]);
818 let searcher = CompressedDAGSearcher::new(Rc::new(graph));
819 assert_eq!(
820 searcher.confidence_percentile_nearest(0.5),
821 CompressedDAGNodeRef {
822 segment: 0,
823 index: 9
824 }
825 );
826 }
827
828 macro_rules! assert_graph_index {
829 ($searcher:expr, $next:expr, $best:expr, $heads:expr, $flakiness:expr) => {
830 assert_eq!(
831 $searcher.next_node(),
832 CompressedDAGNodeRef {
833 segment: $next.0,
834 index: $next.1
835 },
836 "next_index"
837 );
838 assert_eq!(
839 $searcher.best_node(),
840 CompressedDAGNodeRef {
841 segment: $best.0,
842 index: $best.1
843 },
844 "best_index"
845 );
846 $searcher.report(
847 CompressedDAGNodeRef {
848 segment: $next.0,
849 index: $next.1,
850 },
851 $heads,
852 $flakiness,
853 );
854 };
855 }
856
857 #[test]
858 fn graph_two_elements_zero() {
859 let mut graph = CompressedDAG::new();
860 graph.add_node(CompressedDAGSegment::new(2), vec![]);
861 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
862 assert_graph_index!(s, (0, 0), (0, 0), true, DEFAULT_FLAKINESS);
863 assert_graph_index!(s, (0, 0), (0, 0), true, DEFAULT_FLAKINESS);
864 }
865
866 #[test]
867 fn graph_two_elements_one() {
868 let mut graph = CompressedDAG::new();
869 graph.add_node(CompressedDAGSegment::new(2), vec![]);
870 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
871 assert_graph_index!(s, (0, 0), (0, 0), false, DEFAULT_FLAKINESS);
872 assert_graph_index!(s, (0, 0), (0, 1), false, DEFAULT_FLAKINESS);
873 assert_graph_index!(s, (0, 0), (0, 1), false, DEFAULT_FLAKINESS);
874 }
875
876 #[test]
877 fn graph_many_elements_last() {
878 let mut graph = CompressedDAG::new();
879 graph.add_node(CompressedDAGSegment::new(1024), vec![]);
880 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
881 assert_graph_index!(s, (0, 511), (0, 511), false, DEFAULT_FLAKINESS);
882 assert_graph_index!(s, (0, 750), (0, 751), false, DEFAULT_FLAKINESS);
883 assert_graph_index!(s, (0, 878), (0, 878), false, DEFAULT_FLAKINESS);
884 assert_graph_index!(s, (0, 946), (0, 946), false, DEFAULT_FLAKINESS);
885 assert_graph_index!(s, (0, 982), (0, 982), false, DEFAULT_FLAKINESS);
886 }
887
888 #[test]
889 fn graph_parallel_first_first() {
890 let mut graph = CompressedDAG::new();
891 graph.add_node(CompressedDAGSegment::new(100), vec![]);
892 graph.add_node(CompressedDAGSegment::new(100), vec![]);
893 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
894 assert_graph_index!(s, (0, 99), (0, 99), true, DEFAULT_FLAKINESS);
895 assert_graph_index!(s, (0, 52), (0, 53), true, DEFAULT_FLAKINESS);
896 assert_graph_index!(s, (0, 27), (0, 28), true, DEFAULT_FLAKINESS);
897 assert_graph_index!(s, (0, 14), (0, 14), true, DEFAULT_FLAKINESS);
898 assert_graph_index!(s, (0, 7), (0, 7), true, DEFAULT_FLAKINESS);
899 assert_graph_index!(s, (0, 3), (0, 4), true, DEFAULT_FLAKINESS);
900 assert_graph_index!(s, (0, 1), (0, 2), true, DEFAULT_FLAKINESS);
901 assert_graph_index!(s, (0, 0), (0, 1), true, DEFAULT_FLAKINESS);
902 assert_graph_index!(s, (0, 0), (0, 0), true, DEFAULT_FLAKINESS);
903 assert_graph_index!(s, (0, 0), (0, 0), true, DEFAULT_FLAKINESS);
904 }
905
906 #[test]
907 fn graph_parallel_first_last() {
908 let mut graph = CompressedDAG::new();
909 graph.add_node(CompressedDAGSegment::new(100), vec![]);
910 graph.add_node(CompressedDAGSegment::new(100), vec![]);
911 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
912 assert_graph_index!(s, (0, 99), (0, 99), true, DEFAULT_FLAKINESS);
913 assert_graph_index!(s, (0, 52), (0, 53), false, DEFAULT_FLAKINESS);
914 assert_graph_index!(s, (0, 77), (0, 78), false, DEFAULT_FLAKINESS);
915 assert_graph_index!(s, (0, 90), (0, 91), false, DEFAULT_FLAKINESS);
916 assert_graph_index!(s, (0, 97), (0, 98), false, DEFAULT_FLAKINESS);
917 assert_graph_index!(s, (1, 68), (1, 69), false, DEFAULT_FLAKINESS);
918 assert_graph_index!(s, (1, 99), (0, 99), false, DEFAULT_FLAKINESS);
919 assert_graph_index!(s, (0, 98), (0, 98), false, DEFAULT_FLAKINESS);
920 assert_graph_index!(s, (0, 99), (0, 99), true, DEFAULT_FLAKINESS);
921 assert_graph_index!(s, (0, 98), (0, 99), false, DEFAULT_FLAKINESS);
922 assert_graph_index!(s, (1, 99), (0, 99), false, DEFAULT_FLAKINESS);
923 }
924
925 #[test]
926 fn graph_parallel_last_first() {
927 let mut graph = CompressedDAG::new();
928 graph.add_node(CompressedDAGSegment::new(100), vec![]);
929 graph.add_node(CompressedDAGSegment::new(100), vec![]);
930 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
931 assert_graph_index!(s, (0, 99), (0, 99), false, DEFAULT_FLAKINESS);
932 assert_graph_index!(s, (1, 52), (1, 53), true, DEFAULT_FLAKINESS);
933 assert_graph_index!(s, (1, 27), (1, 28), true, DEFAULT_FLAKINESS);
934 assert_graph_index!(s, (1, 14), (1, 14), true, DEFAULT_FLAKINESS);
935 assert_graph_index!(s, (1, 7), (1, 7), true, DEFAULT_FLAKINESS);
936 assert_graph_index!(s, (1, 3), (1, 4), true, DEFAULT_FLAKINESS);
937 assert_graph_index!(s, (1, 1), (1, 2), true, DEFAULT_FLAKINESS);
938 assert_graph_index!(s, (1, 0), (1, 1), true, DEFAULT_FLAKINESS);
939 assert_graph_index!(s, (1, 0), (1, 0), true, DEFAULT_FLAKINESS);
940 assert_graph_index!(s, (1, 0), (1, 0), true, DEFAULT_FLAKINESS);
941 }
942
943 #[test]
944 fn graph_parallel_last_last() {
945 let mut graph = CompressedDAG::new();
946 graph.add_node(CompressedDAGSegment::new(100), vec![]);
947 graph.add_node(CompressedDAGSegment::new(100), vec![]);
948 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
949 assert_graph_index!(s, (0, 99), (0, 99), false, DEFAULT_FLAKINESS);
950 assert_graph_index!(s, (1, 52), (1, 53), false, DEFAULT_FLAKINESS);
951 assert_graph_index!(s, (1, 77), (1, 78), false, DEFAULT_FLAKINESS);
952 assert_graph_index!(s, (1, 90), (1, 91), false, DEFAULT_FLAKINESS);
953 assert_graph_index!(s, (1, 97), (1, 98), false, DEFAULT_FLAKINESS);
954 assert_graph_index!(s, (0, 68), (0, 69), false, DEFAULT_FLAKINESS);
955 assert_graph_index!(s, (0, 99), (1, 99), false, DEFAULT_FLAKINESS);
956 assert_graph_index!(s, (1, 98), (1, 98), false, DEFAULT_FLAKINESS);
957 assert_graph_index!(s, (0, 99), (1, 99), false, DEFAULT_FLAKINESS);
958 assert_graph_index!(s, (1, 98), (1, 99), false, DEFAULT_FLAKINESS);
959 }
960
961 #[test]
962 fn graph_parallel_first_half() {
963 let mut graph = CompressedDAG::new();
964 graph.add_node(CompressedDAGSegment::new(100), vec![]);
965 graph.add_node(CompressedDAGSegment::new(100), vec![]);
966 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
967 assert_graph_index!(s, (0, 99), (0, 99), true, DEFAULT_FLAKINESS);
968 assert_graph_index!(s, (0, 52), (0, 53), true, DEFAULT_FLAKINESS);
969 assert_graph_index!(s, (0, 27), (0, 28), false, DEFAULT_FLAKINESS);
970 assert_graph_index!(s, (0, 40), (0, 41), false, DEFAULT_FLAKINESS);
971 assert_graph_index!(s, (0, 47), (0, 48), false, DEFAULT_FLAKINESS);
972 assert_graph_index!(s, (0, 51), (0, 51), true, DEFAULT_FLAKINESS);
973 assert_graph_index!(s, (0, 49), (0, 49), false, DEFAULT_FLAKINESS);
974 assert_graph_index!(s, (0, 50), (0, 51), true, DEFAULT_FLAKINESS);
975 assert_graph_index!(s, (0, 49), (0, 50), false, DEFAULT_FLAKINESS);
976 assert_graph_index!(s, (0, 50), (0, 50), true, DEFAULT_FLAKINESS);
977 }
978
979 #[test]
980 fn graph_parallel_second_half() {
981 let mut graph = CompressedDAG::new();
982 graph.add_node(CompressedDAGSegment::new(100), vec![]);
983 graph.add_node(CompressedDAGSegment::new(100), vec![]);
984 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
985 assert_graph_index!(s, (0, 99), (0, 99), false, DEFAULT_FLAKINESS);
986 assert_graph_index!(s, (1, 52), (1, 53), true, DEFAULT_FLAKINESS);
987 assert_graph_index!(s, (1, 27), (1, 28), false, DEFAULT_FLAKINESS);
988 assert_graph_index!(s, (1, 40), (1, 41), false, DEFAULT_FLAKINESS);
989 assert_graph_index!(s, (1, 47), (1, 48), false, DEFAULT_FLAKINESS);
990 assert_graph_index!(s, (1, 51), (1, 51), true, DEFAULT_FLAKINESS);
991 assert_graph_index!(s, (1, 49), (1, 49), false, DEFAULT_FLAKINESS);
992 assert_graph_index!(s, (1, 50), (1, 51), true, DEFAULT_FLAKINESS);
993 assert_graph_index!(s, (1, 49), (1, 50), false, DEFAULT_FLAKINESS);
994 assert_graph_index!(s, (1, 50), (1, 50), true, DEFAULT_FLAKINESS);
995 }
996
997 #[test]
998 fn graph_fork_join() {
999 let mut graph = CompressedDAG::new();
1003 graph.add_node(CompressedDAGSegment::new(100), vec![]);
1004 graph.add_node(CompressedDAGSegment::new(100), vec![0]);
1005 graph.add_node(CompressedDAGSegment::new(100), vec![0]);
1006 graph.add_node(CompressedDAGSegment::new(100), vec![1, 2]);
1007 let mut s = CompressedDAGSearcher::new(Rc::new(graph));
1008 assert_graph_index!(s, (1, 99), (1, 99), false, DEFAULT_FLAKINESS);
1009 assert_graph_index!(s, (2, 99), (2, 99), true, DEFAULT_FLAKINESS);
1010 assert_graph_index!(s, (2, 49), (2, 50), false, DEFAULT_FLAKINESS);
1011 assert_graph_index!(s, (2, 76), (2, 76), true, DEFAULT_FLAKINESS);
1012 assert_graph_index!(s, (2, 62), (2, 62), true, DEFAULT_FLAKINESS);
1013 assert_graph_index!(s, (2, 54), (2, 55), true, DEFAULT_FLAKINESS);
1014 assert_graph_index!(s, (2, 50), (2, 50), true, DEFAULT_FLAKINESS);
1015 assert_graph_index!(s, (2, 31), (2, 31), false, DEFAULT_FLAKINESS);
1016 assert_graph_index!(s, (2, 49), (2, 49), false, DEFAULT_FLAKINESS);
1017 assert_graph_index!(s, (2, 50), (2, 50), true, DEFAULT_FLAKINESS);
1018 assert_graph_index!(s, (2, 49), (2, 50), false, DEFAULT_FLAKINESS);
1019 }
1020}