1use std::collections::VecDeque;
15
16pub enum Split<T> {
18 Done,
21 Restrict(T),
23 Halves(T, T),
25}
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub enum Order {
30 BreadthFirst,
33 DepthFirst,
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39#[must_use]
40pub enum Searched {
41 Complete,
43 Exhausted { pending: usize },
46}
47
48pub fn subdivide<T, E>(
53 roots: impl IntoIterator<Item = T>,
54 order: Order,
55 max_nodes: usize,
56 mut visit: impl FnMut(T, usize) -> Result<Split<T>, E>,
57) -> Result<Searched, E> {
58 let mut pending: VecDeque<T> = VecDeque::new();
59 match order {
60 Order::BreadthFirst => pending.extend(roots),
61 Order::DepthFirst => roots.into_iter().for_each(|r| pending.push_front(r)),
62 }
63 let mut explored = 0usize;
64 while let Some(piece) = pending.pop_front() {
66 if explored >= max_nodes {
67 return Ok(Searched::Exhausted {
68 pending: pending.len() + 1,
69 });
70 }
71 explored += 1;
72 match visit(piece, max_nodes - explored)? {
73 Split::Done => {}
74 Split::Restrict(restricted) => match order {
75 Order::BreadthFirst => pending.push_back(restricted),
76 Order::DepthFirst => pending.push_front(restricted),
77 },
78 Split::Halves(first, second) => match order {
79 Order::BreadthFirst => pending.extend([first, second]),
80 Order::DepthFirst => {
81 pending.push_front(second);
82 pending.push_front(first);
83 }
84 },
85 }
86 }
87 Ok(Searched::Complete)
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 fn search(order: Order, max_nodes: usize) -> (Searched, Vec<(f64, f64)>) {
97 let mut found = Vec::new();
98 let searched = subdivide::<_, ()>([(0.0, 1.0)], order, max_nodes, |(lo, hi), _| {
99 if ![0.3, 0.7].iter().any(|&r| lo <= r && r < hi) {
100 return Ok(Split::Done);
101 }
102 if hi - lo <= 1.0 / 16.0 {
103 found.push((lo, hi));
104 return Ok(Split::Done);
105 }
106 let mid = 0.5 * (lo + hi);
107 Ok(Split::Halves((lo, mid), (mid, hi)))
108 })
109 .unwrap();
110 (searched, found)
111 }
112
113 #[test]
114 fn every_solution_is_found_in_either_order() {
115 let both = [(0.25, 0.3125), (0.6875, 0.75)];
116 for order in [Order::BreadthFirst, Order::DepthFirst] {
117 let (searched, found) = search(order, 1000);
118 assert_eq!(searched, Searched::Complete);
119 assert_eq!(found, both);
120 }
121 }
122
123 #[test]
126 fn the_orders_differ_only_in_order() {
127 let mut seen = [Vec::new(), Vec::new()];
128 for (k, order) in [Order::BreadthFirst, Order::DepthFirst]
129 .into_iter()
130 .enumerate()
131 {
132 let _ = subdivide::<_, ()>([(0u32, 4u32)], order, 100, |(lo, hi), _| {
133 seen[k].push((lo, hi));
134 Ok(if hi - lo == 1 {
135 Split::Done
136 } else {
137 let mid = (lo + hi) / 2;
138 Split::Halves((lo, mid), (mid, hi))
139 })
140 })
141 .unwrap();
142 }
143 assert_eq!(
144 seen[0],
145 [(0, 4), (0, 2), (2, 4), (0, 1), (1, 2), (2, 3), (3, 4)]
146 );
147 assert_eq!(
148 seen[1],
149 [(0, 4), (0, 2), (0, 1), (1, 2), (2, 4), (2, 3), (3, 4)]
150 );
151 }
152
153 #[test]
156 fn running_out_is_reported() {
157 let (searched, _) = search(Order::BreadthFirst, 5);
158 assert_eq!(searched, Searched::Exhausted { pending: 4 });
159 }
160}