use log::trace;
use std::borrow::Borrow;
use std::cmp;
use std::rc::Rc;
mod flakiness_tracker;
use flakiness_tracker::*;
mod range_map;
use range_map::*;
mod dag;
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
pub struct CompressedDAGNodeRef {
pub segment: usize,
pub index: usize,
}
#[derive(Clone, Debug)]
pub struct CompressedDAGSegment {
len: usize,
}
impl CompressedDAGSegment {
pub fn new(len: usize) -> Self {
CompressedDAGSegment { len }
}
pub fn len(&self) -> usize {
self.len
}
}
pub type CompressedDAG = dag::DAG<CompressedDAGSegment>;
mod compressed_dag_flakiness_tracker;
use compressed_dag_flakiness_tracker::*;
fn confidence_percentile_nearest(range_map: &RangeMap<f64>, percentile: f64) -> (usize, f64) {
let mut sum = 0.0;
let mut index = 0;
let mut best_index = 0;
let mut best_percentile = f64::NEG_INFINITY;
for w in range_map.ranges() {
let delta = w.len() as f64 * w.value();
trace!(
"percentile = {}, sum = {}, w.value = {}",
percentile,
sum,
w.value()
);
trace!(
"(percentile - sum) / w.value() - 0.5 = {}",
(percentile - sum) / w.value() - 0.5
);
let ix = index
+ cmp::min(
w.len() - 1,
((percentile - sum) / w.value() - 0.5).max(0.0) as usize,
);
let ix_percentile = sum + (ix - index + 1) as f64 * w.value();
trace!("ix = {} ix_percentile = {}", ix, ix_percentile);
if (ix_percentile - percentile).abs() < (best_percentile - percentile).abs() {
best_index = ix;
best_percentile = ix_percentile;
}
sum += delta;
index += w.len();
}
assert!(best_percentile > f64::NEG_INFINITY);
trace!(
"confidence_percentile_nearest returning {:?}",
(best_index, best_percentile)
);
(best_index, best_percentile)
}
fn confidence_percentile_ceil(range_map: &RangeMap<f64>, percentile: f64) -> (usize, f64) {
let mut sum = 0.0;
let mut index = 0;
for w in range_map.ranges() {
let delta = w.len() as f64 * w.value();
if sum + delta >= percentile {
let ix = index + ((percentile - sum) / w.value() - 1e-9) as usize;
let ret = (ix, sum + (ix - index + 1) as f64 * w.value());
trace!("confidence_percentile_ceil returning {:?}", ret);
return ret;
}
sum += delta;
index += w.len();
}
(range_map.len() - 1, sum)
}
fn report_range(weights: &mut RangeMap<f64>, index: usize, heads: bool, stiffness: f64) {
if heads {
for w in weights.split(index).0 {
*w.value_mut() *= 1.0 + stiffness;
}
let (left, _right) = weights.split(index + 1);
*left.rev().next().unwrap().value_mut() *= 1.0 + stiffness;
} else {
weights.split(index);
let (_left, right) = weights.split(index + 1);
for w in right {
*w.value_mut() *= 1.0 + stiffness;
}
}
}
#[derive(Clone, Debug)]
pub struct Searcher {
weights: RangeMap<f64>,
len: usize,
}
impl Searcher {
pub fn new(len: usize) -> Self {
Searcher {
weights: RangeMap::new(len + 1, 1.0 / (len as f64 + 1.0)),
len,
}
}
#[doc(hidden)]
pub fn report_with_stiffness(&mut self, index: usize, heads: bool, stiffness: f64) {
assert!(index < self.len);
report_range(&mut self.weights, index, heads, stiffness);
let weight_sum: f64 = self
.weights
.ranges()
.map(|w| w.value() * w.len() as f64)
.sum();
for w in self.weights.ranges_mut() {
*w.value_mut() /= weight_sum;
}
}
pub fn report(&mut self, index: usize, heads: bool, flakiness: f64) {
self.report_with_stiffness(index, heads, optimal_stiffness(flakiness));
}
pub fn next_index(&self) -> usize {
cmp::min(
confidence_percentile_nearest(&self.weights, 0.5).0,
self.len - 1,
)
}
pub fn best_index(&self) -> usize {
confidence_percentile_ceil(&self.weights, 0.5).0
}
#[doc(hidden)]
pub fn confidence_percentile_ceil(&self, percentile: f64) -> usize {
confidence_percentile_ceil(&self.weights, percentile).0
}
pub fn likelihood(&self, index: usize) -> f64 {
*self.weights.range_for_index(index).value()
}
}
fn optimal_stiffness(flakiness: f64) -> f64 {
(2.6 / flakiness.powf(0.37))
.min(0.58 / flakiness.powf(0.97))
.min(0.19 / flakiness.powf(2.4))
}
#[derive(Clone, Debug)]
pub struct AutoSearcher {
searcher: Searcher,
flakiness_tracker: FlakinessTracker,
}
impl AutoSearcher {
pub fn new(len: usize) -> Self {
AutoSearcher {
searcher: Searcher::new(len),
flakiness_tracker: FlakinessTracker::default(),
}
}
pub fn report(&mut self, index: usize, heads: bool) {
self.flakiness_tracker.report(index, heads);
self.searcher
.report(index, heads, self.flakiness_tracker.flakiness());
}
pub fn next_index(&self) -> usize {
self.searcher.next_index()
}
pub fn best_index(&self) -> usize {
self.searcher.best_index()
}
pub fn likelihood(&self, index: usize) -> f64 {
self.searcher.likelihood(index)
}
}
#[derive(Clone, Debug)]
pub struct CompressedDAGSearcher {
graph: Rc<CompressedDAG>,
segment_range_maps: Vec<RangeMap<f64>>,
}
impl CompressedDAGSearcher {
pub fn new(graph: Rc<CompressedDAG>) -> Self {
let n = graph
.nodes()
.iter()
.map(|node| node.value().len())
.fold(0, |x, y| x + y);
let segment_range_maps = graph
.nodes()
.iter()
.map(|node| RangeMap::new(node.value().len(), 1.0 / n as f64))
.collect();
CompressedDAGSearcher {
graph,
segment_range_maps,
}
}
fn segment_percentile_ranges(&self) -> Vec<(f64, f64)> {
let mut segment_ranges = Vec::<(f64, f64)>::new();
let mut segment_sums = Vec::<f64>::new();
let graph: &CompressedDAG = self.graph.borrow();
for (i, range_map) in self.segment_range_maps.iter().enumerate() {
let inputs = graph.node(i).inputs();
let start = if inputs.is_empty() {
0.0
} else {
let mut start = segment_ranges[inputs[0]].1;
for ancestor in graph.node(i).remainder_ancestors() {
start += segment_sums[*ancestor];
}
start
};
let mut segment_sum = 0.0;
for range in range_map.ranges() {
segment_sum += range.value() * range.len() as f64;
}
segment_sums.push(segment_sum);
let end = start + segment_sum;
assert!(
start >= 0.0 && start <= 1.0 + 1e-11 && end >= 0.0 && end <= 1.0 + 1e-11,
"i = {} of {}, start = {}, end = {}",
i,
self.segment_range_maps.len(),
start,
end
);
segment_ranges.push((start, end));
}
segment_ranges
}
fn confidence_percentile_nearest(&self, percentile: f64) -> CompressedDAGNodeRef {
let segment_ranges = self.segment_percentile_ranges();
trace!("segment_ranges = {:?}", segment_ranges);
let mut best_node = CompressedDAGNodeRef {
segment: 0,
index: 0,
};
let mut best_value = f64::NEG_INFINITY;
for (i, range) in segment_ranges.iter().enumerate() {
let (ix, mut value) =
confidence_percentile_nearest(&self.segment_range_maps[i], percentile - range.0);
value += range.0;
if (percentile - value).abs() < (percentile - best_value).abs() {
best_node = CompressedDAGNodeRef {
segment: i,
index: ix,
};
best_value = value;
}
}
assert!(best_value > f64::NEG_INFINITY);
best_node
}
pub fn confidence_percentile_ceil(&self, percentile: f64) -> CompressedDAGNodeRef {
let segment_ranges = self.segment_percentile_ranges();
let mut min_end = 0;
let mut min_end_segment = 0;
let mut min_end_value = f64::INFINITY;
for (i, range) in segment_ranges.iter().enumerate() {
let (ix, mut value) =
confidence_percentile_ceil(&self.segment_range_maps[i], percentile - range.0);
value += range.0;
trace!(
"i = {}, ix = {}, value = {}, min_end_value = {}",
i,
ix,
value,
min_end_value
);
if value < min_end_value && value >= percentile {
min_end = ix;
min_end_segment = i;
min_end_value = value;
}
}
let ret = CompressedDAGNodeRef {
segment: min_end_segment,
index: min_end,
};
trace!(
"CompressedDAGSearcher::confidence_percentile_ceil returning {:?}",
ret
);
ret
}
pub fn best_node(&self) -> CompressedDAGNodeRef {
self.confidence_percentile_ceil(0.5)
}
pub fn next_node(&self) -> CompressedDAGNodeRef {
self.confidence_percentile_nearest(0.5)
}
pub fn report(&mut self, node: CompressedDAGNodeRef, heads: bool, flakiness: f64) {
let stiffness = optimal_stiffness(flakiness);
let graph: &CompressedDAG = self.graph.borrow();
if heads {
for segment in graph.node(node.segment).ancestors() {
for w in self.segment_range_maps[*segment].ranges_mut() {
*w.value_mut() *= 1.0 + stiffness;
}
}
} else {
let ancestor_segments = graph.node(node.segment).ancestors();
for segment in 0..graph.nodes().len() {
if ancestor_segments.contains(&segment) || segment == node.segment {
continue;
}
for w in self.segment_range_maps[segment].ranges_mut() {
*w.value_mut() *= 1.0 + stiffness;
}
}
}
report_range(
&mut self.segment_range_maps[node.segment],
node.index,
heads,
stiffness,
);
let weight_sum: f64 = self
.segment_range_maps
.iter()
.map(|range_map| {
range_map
.ranges()
.map(|w| w.value() * w.len() as f64)
.sum::<f64>()
})
.sum();
for range_map in &mut self.segment_range_maps {
for w in range_map.ranges_mut() {
*w.value_mut() /= weight_sum;
}
}
}
pub fn likelihood(&self, node: CompressedDAGNodeRef) -> f64 {
*self.segment_range_maps[node.segment]
.range_for_index(node.index)
.value()
}
}
#[derive(Clone, Debug)]
pub struct AutoCompressedDAGSearcher {
searcher: CompressedDAGSearcher,
flakiness_tracker: CompressedDAGFlakinessTracker,
}
impl AutoCompressedDAGSearcher {
pub fn new(graph: Rc<CompressedDAG>) -> Self {
Self {
searcher: CompressedDAGSearcher::new(graph.clone()),
flakiness_tracker: CompressedDAGFlakinessTracker::new(graph),
}
}
pub fn report(&mut self, node: CompressedDAGNodeRef, heads: bool) {
self.flakiness_tracker.report(node, heads);
self.searcher
.report(node, heads, self.flakiness_tracker.flakiness());
}
pub fn next_node(&self) -> CompressedDAGNodeRef {
self.searcher.next_node()
}
pub fn best_node(&self) -> CompressedDAGNodeRef {
self.searcher.best_node()
}
pub fn likelihood(&self, index: CompressedDAGNodeRef) -> f64 {
self.searcher.likelihood(index)
}
pub fn flakiness(&self) -> f64 {
self.flakiness_tracker.flakiness()
}
}
#[cfg(test)]
mod tests {
use super::*;
const DEFAULT_FLAKINESS: f64 = 0.01;
macro_rules! assert_index {
($searcher:expr, $next:expr, $best:expr, $heads:expr, $flakiness:expr) => {
assert_eq!($searcher.next_index(), $next, "next_index");
assert_eq!($searcher.best_index(), $best, "best_index");
$searcher.report($next, $heads, $flakiness);
};
}
#[test]
fn one_element_zero() {
let mut s = Searcher::new(1);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
}
#[test]
fn one_element_one() {
let mut s = Searcher::new(1);
assert_index!(s, 0, 0, false, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
}
#[test]
fn two_elements_zero() {
let mut s = Searcher::new(2);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
}
#[test]
fn two_elements_one() {
let mut s = Searcher::new(2);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
}
#[test]
fn two_elements_two() {
let mut s = Searcher::new(2);
assert_index!(s, 1, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
}
#[test]
fn three_elements_zero() {
let mut s = Searcher::new(3);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
}
#[test]
fn three_elements_one() {
let mut s = Searcher::new(3);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, false, DEFAULT_FLAKINESS);
}
#[test]
fn three_elements_two() {
let mut s = Searcher::new(3);
assert_index!(s, 1, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 2, 2, true, DEFAULT_FLAKINESS);
assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
assert_index!(s, 2, 2, true, DEFAULT_FLAKINESS);
assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
assert_index!(s, 2, 2, true, DEFAULT_FLAKINESS);
assert_index!(s, 1, 2, false, DEFAULT_FLAKINESS);
}
#[test]
fn three_elements_three() {
let mut s = Searcher::new(3);
assert_index!(s, 1, 1, false, DEFAULT_FLAKINESS);
assert_index!(s, 2, 2, false, DEFAULT_FLAKINESS);
assert_index!(s, 2, 3, false, DEFAULT_FLAKINESS);
assert_index!(s, 2, 3, false, DEFAULT_FLAKINESS);
assert_index!(s, 2, 3, false, DEFAULT_FLAKINESS);
}
#[test]
fn many_elements_first() {
let mut s = Searcher::new(1024);
assert_index!(s, 512, 512, true, DEFAULT_FLAKINESS);
assert_index!(s, 272, 273, true, DEFAULT_FLAKINESS);
assert_index!(s, 144, 145, true, DEFAULT_FLAKINESS);
assert_index!(s, 76, 77, true, DEFAULT_FLAKINESS);
assert_index!(s, 40, 41, true, DEFAULT_FLAKINESS);
assert_index!(s, 21, 21, true, DEFAULT_FLAKINESS);
assert_index!(s, 11, 11, true, DEFAULT_FLAKINESS);
assert_index!(s, 5, 6, true, DEFAULT_FLAKINESS);
assert_index!(s, 2, 3, true, DEFAULT_FLAKINESS);
assert_index!(s, 1, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 1, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
assert_index!(s, 0, 0, true, DEFAULT_FLAKINESS);
}
#[test]
fn many_elements_last() {
let mut s = Searcher::new(1024);
assert_index!(s, 512, 512, false, DEFAULT_FLAKINESS);
assert_index!(s, 751, 752, false, DEFAULT_FLAKINESS);
assert_index!(s, 879, 879, false, DEFAULT_FLAKINESS);
assert_index!(s, 947, 947, false, DEFAULT_FLAKINESS);
assert_index!(s, 983, 983, false, DEFAULT_FLAKINESS);
assert_index!(s, 1002, 1003, false, DEFAULT_FLAKINESS);
assert_index!(s, 1012, 1013, false, DEFAULT_FLAKINESS);
assert_index!(s, 1018, 1018, false, DEFAULT_FLAKINESS);
assert_index!(s, 1021, 1021, false, DEFAULT_FLAKINESS);
assert_index!(s, 1022, 1023, false, DEFAULT_FLAKINESS);
assert_index!(s, 1023, 1023, false, DEFAULT_FLAKINESS);
assert_index!(s, 1023, 1024, false, DEFAULT_FLAKINESS);
assert_index!(s, 1023, 1024, false, DEFAULT_FLAKINESS);
assert_index!(s, 1023, 1024, false, DEFAULT_FLAKINESS);
}
#[test]
fn graph_confidence_percentile_nearest_singleton() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(1), vec![]);
let searcher = CompressedDAGSearcher::new(Rc::new(graph));
assert_eq!(
searcher.confidence_percentile_nearest(0.5),
CompressedDAGNodeRef {
segment: 0,
index: 0
}
);
}
#[test]
fn graph_confidence_percentile_nearest_single_segment() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(10), vec![]);
let searcher = CompressedDAGSearcher::new(Rc::new(graph));
assert_eq!(
searcher.confidence_percentile_nearest(0.5),
CompressedDAGNodeRef {
segment: 0,
index: 4
}
);
}
#[test]
fn graph_confidence_percentile_nearest_parallel_segments() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(10), vec![]);
graph.add_node(CompressedDAGSegment::new(10), vec![]);
let searcher = CompressedDAGSearcher::new(Rc::new(graph));
assert_eq!(
searcher.confidence_percentile_nearest(0.5),
CompressedDAGNodeRef {
segment: 0,
index: 9
}
);
}
#[test]
fn graph_confidence_percentile_nearest_parallel_unequal_segments() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(100), vec![]);
graph.add_node(CompressedDAGSegment::new(10), vec![]);
let searcher = CompressedDAGSearcher::new(Rc::new(graph));
assert_eq!(
searcher.confidence_percentile_nearest(0.5),
CompressedDAGNodeRef {
segment: 0,
index: 54
}
);
}
#[test]
fn graph_confidence_percentile_nearest_parallel_unequal_segments2() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(10), vec![]);
graph.add_node(CompressedDAGSegment::new(100), vec![]);
let searcher = CompressedDAGSearcher::new(Rc::new(graph));
assert_eq!(
searcher.confidence_percentile_nearest(0.5),
CompressedDAGNodeRef {
segment: 1,
index: 54
}
);
}
#[test]
fn graph_confidence_percentile_nearest_sequential_segments() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(10), vec![]);
graph.add_node(CompressedDAGSegment::new(10), vec![0]);
graph.add_node(CompressedDAGSegment::new(10), vec![1]);
let searcher = CompressedDAGSearcher::new(Rc::new(graph));
assert_eq!(
searcher.confidence_percentile_nearest(0.5),
CompressedDAGNodeRef {
segment: 1,
index: 4
}
);
}
#[test]
fn graph_confidence_percentile_nearest_fork() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(10), vec![]);
graph.add_node(CompressedDAGSegment::new(10), vec![0]);
graph.add_node(CompressedDAGSegment::new(10), vec![0]);
let searcher = CompressedDAGSearcher::new(Rc::new(graph));
assert_eq!(
searcher.confidence_percentile_nearest(0.5),
CompressedDAGNodeRef {
segment: 1,
index: 4
}
);
}
#[test]
fn graph_confidence_percentile_nearest_merge() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(10), vec![]);
graph.add_node(CompressedDAGSegment::new(10), vec![]);
graph.add_node(CompressedDAGSegment::new(10), vec![0, 1]);
let searcher = CompressedDAGSearcher::new(Rc::new(graph));
assert_eq!(
searcher.confidence_percentile_nearest(0.5),
CompressedDAGNodeRef {
segment: 0,
index: 9
}
);
}
macro_rules! assert_graph_index {
($searcher:expr, $next:expr, $best:expr, $heads:expr, $flakiness:expr) => {
assert_eq!(
$searcher.next_node(),
CompressedDAGNodeRef {
segment: $next.0,
index: $next.1
},
"next_index"
);
assert_eq!(
$searcher.best_node(),
CompressedDAGNodeRef {
segment: $best.0,
index: $best.1
},
"best_index"
);
$searcher.report(
CompressedDAGNodeRef {
segment: $next.0,
index: $next.1,
},
$heads,
$flakiness,
);
};
}
#[test]
fn graph_two_elements_zero() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(2), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 0), (0, 0), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 0), (0, 0), true, DEFAULT_FLAKINESS);
}
#[test]
fn graph_two_elements_one() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(2), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 0), (0, 0), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 0), (0, 1), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 0), (0, 1), false, DEFAULT_FLAKINESS);
}
#[test]
fn graph_many_elements_last() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(1024), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 511), (0, 511), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 750), (0, 751), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 878), (0, 878), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 946), (0, 946), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 982), (0, 982), false, DEFAULT_FLAKINESS);
}
#[test]
fn graph_parallel_first_first() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(100), vec![]);
graph.add_node(CompressedDAGSegment::new(100), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 99), (0, 99), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 52), (0, 53), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 27), (0, 28), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 14), (0, 14), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 7), (0, 7), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 3), (0, 4), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 1), (0, 2), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 0), (0, 1), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 0), (0, 0), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 0), (0, 0), true, DEFAULT_FLAKINESS);
}
#[test]
fn graph_parallel_first_last() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(100), vec![]);
graph.add_node(CompressedDAGSegment::new(100), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 99), (0, 99), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 52), (0, 53), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 77), (0, 78), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 90), (0, 91), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 97), (0, 98), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 68), (1, 69), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 99), (0, 99), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 98), (0, 98), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 99), (0, 99), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 98), (0, 99), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 99), (0, 99), false, DEFAULT_FLAKINESS);
}
#[test]
fn graph_parallel_last_first() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(100), vec![]);
graph.add_node(CompressedDAGSegment::new(100), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 99), (0, 99), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 52), (1, 53), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 27), (1, 28), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 14), (1, 14), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 7), (1, 7), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 3), (1, 4), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 1), (1, 2), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 0), (1, 1), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 0), (1, 0), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 0), (1, 0), true, DEFAULT_FLAKINESS);
}
#[test]
fn graph_parallel_last_last() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(100), vec![]);
graph.add_node(CompressedDAGSegment::new(100), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 99), (0, 99), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 52), (1, 53), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 77), (1, 78), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 90), (1, 91), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 97), (1, 98), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 68), (0, 69), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 99), (1, 99), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 98), (1, 98), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 99), (1, 99), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 98), (1, 99), false, DEFAULT_FLAKINESS);
}
#[test]
fn graph_parallel_first_half() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(100), vec![]);
graph.add_node(CompressedDAGSegment::new(100), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 99), (0, 99), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 52), (0, 53), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 27), (0, 28), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 40), (0, 41), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 47), (0, 48), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 51), (0, 51), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 49), (0, 49), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 50), (0, 51), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 49), (0, 50), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (0, 50), (0, 50), true, DEFAULT_FLAKINESS);
}
#[test]
fn graph_parallel_second_half() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(100), vec![]);
graph.add_node(CompressedDAGSegment::new(100), vec![]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (0, 99), (0, 99), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 52), (1, 53), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 27), (1, 28), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 40), (1, 41), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 47), (1, 48), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 51), (1, 51), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 49), (1, 49), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 50), (1, 51), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 49), (1, 50), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (1, 50), (1, 50), true, DEFAULT_FLAKINESS);
}
#[test]
fn graph_fork_join() {
let mut graph = CompressedDAG::new();
graph.add_node(CompressedDAGSegment::new(100), vec![]);
graph.add_node(CompressedDAGSegment::new(100), vec![0]);
graph.add_node(CompressedDAGSegment::new(100), vec![0]);
graph.add_node(CompressedDAGSegment::new(100), vec![1, 2]);
let mut s = CompressedDAGSearcher::new(Rc::new(graph));
assert_graph_index!(s, (1, 99), (1, 99), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 99), (2, 99), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 49), (2, 50), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 76), (2, 76), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 62), (2, 62), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 54), (2, 55), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 50), (2, 50), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 31), (2, 31), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 49), (2, 49), false, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 50), (2, 50), true, DEFAULT_FLAKINESS);
assert_graph_index!(s, (2, 49), (2, 50), false, DEFAULT_FLAKINESS);
}
}