| 1 |
1 use super::aggregator::*; |
| |
2 use super::bt::*; |
| |
3 use super::support::*; |
| |
4 use crate::nanleast::NaNLeast; |
| |
5 use crate::parallelism::TaskBudget; |
| |
6 use crate::parallelism::{thread_pool, thread_pool_size}; |
| |
7 use crate::sets::Cube; |
| |
8 use crate::types::*; |
| |
9 use std::cmp::{max, Ord, Ordering, Ordering::*, PartialOrd}; |
| 2 use std::collections::BinaryHeap; |
10 use std::collections::BinaryHeap; |
| 3 use std::cmp::{PartialOrd, Ord, Ordering, Ordering::*, max}; |
|
| 4 use std::marker::PhantomData; |
11 use std::marker::PhantomData; |
| 5 use std::sync::{Arc, Mutex, MutexGuard, Condvar}; |
12 use std::sync::{Arc, Condvar, Mutex, MutexGuard}; |
| 6 use crate::types::*; |
|
| 7 use crate::nanleast::NaNLeast; |
|
| 8 use crate::sets::Cube; |
|
| 9 use crate::parallelism::{thread_pool_size, thread_pool}; |
|
| 10 use super::support::*; |
|
| 11 use super::bt::*; |
|
| 12 use super::aggregator::*; |
|
| 13 use crate::parallelism::TaskBudget; |
|
| 14 |
13 |
| 15 /// Trait for sorting [`Aggregator`]s for [`BT`] refinement. |
14 /// Trait for sorting [`Aggregator`]s for [`BT`] refinement. |
| 16 /// |
15 /// |
| 17 /// The sorting involves two sorting keys, the “upper” and the “lower” key. Any [`BT`] nodes |
16 /// The sorting involves two sorting keys, the “upper” and the “lower” key. Any [`BT`] nodes |
| 18 /// with upper key less the lower key of another are discarded from the refinement process. |
17 /// with upper key less the lower key of another are discarded from the refinement process. |
| 19 /// Nodes with the highest upper sorting key are picked for refinement. |
18 /// Nodes with the highest upper sorting key are picked for refinement. |
| 20 pub trait AggregatorSorting : Sync + Send + 'static { |
19 pub trait AggregatorSorting: Sync + Send + 'static { |
| 21 // Priority |
20 // Priority |
| 22 type Agg : Aggregator; |
21 type Agg: Aggregator; |
| 23 type Sort : Ord + Copy + std::fmt::Debug + Sync + Send; |
22 type Sort: Ord + Copy + std::fmt::Debug + Sync + Send; |
| 24 |
23 |
| 25 /// Returns lower sorting key |
24 /// Returns lower sorting key |
| 26 fn sort_lower(aggregator : &Self::Agg) -> Self::Sort; |
25 fn sort_lower(aggregator: &Self::Agg) -> Self::Sort; |
| 27 |
26 |
| 28 /// Returns upper sorting key |
27 /// Returns upper sorting key |
| 29 fn sort_upper(aggregator : &Self::Agg) -> Self::Sort; |
28 fn sort_upper(aggregator: &Self::Agg) -> Self::Sort; |
| 30 |
29 |
| 31 /// Returns a sorting key that is less than any other sorting key. |
30 /// Returns a sorting key that is less than any other sorting key. |
| 32 fn bottom() -> Self::Sort; |
31 fn bottom() -> Self::Sort; |
| 33 } |
32 } |
| 34 |
33 |
| 35 /// An [`AggregatorSorting`] for [`Bounds`], using the upper/lower bound as the upper/lower key. |
34 /// An [`AggregatorSorting`] for [`Bounds`], using the upper/lower bound as the upper/lower key. |
| 36 /// |
35 /// |
| 37 /// See [`LowerBoundSorting`] for the opposite ordering. |
36 /// See [`LowerBoundSorting`] for the opposite ordering. |
| 38 pub struct UpperBoundSorting<F : Float>(PhantomData<F>); |
37 pub struct UpperBoundSorting<F: Float>(PhantomData<F>); |
| 39 |
38 |
| 40 /// An [`AggregatorSorting`] for [`Bounds`], using the upper/lower bound as the lower/upper key. |
39 /// An [`AggregatorSorting`] for [`Bounds`], using the upper/lower bound as the lower/upper key. |
| 41 /// |
40 /// |
| 42 /// See [`UpperBoundSorting`] for the opposite ordering. |
41 /// See [`UpperBoundSorting`] for the opposite ordering. |
| 43 pub struct LowerBoundSorting<F : Float>(PhantomData<F>); |
42 pub struct LowerBoundSorting<F: Float>(PhantomData<F>); |
| 44 |
43 |
| 45 impl<F : Float> AggregatorSorting for UpperBoundSorting<F> { |
44 impl<F: Float> AggregatorSorting for UpperBoundSorting<F> { |
| 46 type Agg = Bounds<F>; |
45 type Agg = Bounds<F>; |
| 47 type Sort = NaNLeast<F>; |
46 type Sort = NaNLeast<F>; |
| 48 |
47 |
| 49 #[inline] |
48 #[inline] |
| 50 fn sort_lower(aggregator : &Bounds<F>) -> Self::Sort { NaNLeast(aggregator.lower()) } |
49 fn sort_lower(aggregator: &Bounds<F>) -> Self::Sort { |
| 51 |
50 NaNLeast(aggregator.lower()) |
| 52 #[inline] |
51 } |
| 53 fn sort_upper(aggregator : &Bounds<F>) -> Self::Sort { NaNLeast(aggregator.upper()) } |
52 |
| 54 |
53 #[inline] |
| 55 #[inline] |
54 fn sort_upper(aggregator: &Bounds<F>) -> Self::Sort { |
| 56 fn bottom() -> Self::Sort { NaNLeast(F::NEG_INFINITY) } |
55 NaNLeast(aggregator.upper()) |
| 57 } |
56 } |
| 58 |
57 |
| 59 |
58 #[inline] |
| 60 impl<F : Float> AggregatorSorting for LowerBoundSorting<F> { |
59 fn bottom() -> Self::Sort { |
| |
60 NaNLeast(F::NEG_INFINITY) |
| |
61 } |
| |
62 } |
| |
63 |
| |
64 impl<F: Float> AggregatorSorting for LowerBoundSorting<F> { |
| 61 type Agg = Bounds<F>; |
65 type Agg = Bounds<F>; |
| 62 type Sort = NaNLeast<F>; |
66 type Sort = NaNLeast<F>; |
| 63 |
67 |
| 64 #[inline] |
68 #[inline] |
| 65 fn sort_upper(aggregator : &Bounds<F>) -> Self::Sort { NaNLeast(-aggregator.lower()) } |
69 fn sort_upper(aggregator: &Bounds<F>) -> Self::Sort { |
| 66 |
70 NaNLeast(-aggregator.lower()) |
| 67 #[inline] |
71 } |
| 68 fn sort_lower(aggregator : &Bounds<F>) -> Self::Sort { NaNLeast(-aggregator.upper()) } |
72 |
| 69 |
73 #[inline] |
| 70 #[inline] |
74 fn sort_lower(aggregator: &Bounds<F>) -> Self::Sort { |
| 71 fn bottom() -> Self::Sort { NaNLeast(F::NEG_INFINITY) } |
75 NaNLeast(-aggregator.upper()) |
| |
76 } |
| |
77 |
| |
78 #[inline] |
| |
79 fn bottom() -> Self::Sort { |
| |
80 NaNLeast(F::NEG_INFINITY) |
| |
81 } |
| 72 } |
82 } |
| 73 |
83 |
| 74 /// Return type of [`Refiner::refine`]. |
84 /// Return type of [`Refiner::refine`]. |
| 75 /// |
85 /// |
| 76 /// The parameter `R` is the result type of the refiner acting on an [`Aggregator`] of type `A`. |
86 /// The parameter `R` is the result type of the refiner acting on an [`Aggregator`] of type `A`. |
| 77 pub enum RefinerResult<A : Aggregator, R> { |
87 pub enum RefinerResult<A: Aggregator, R> { |
| 78 /// Indicates an insufficiently refined state: the [`BT`] needs to be further refined. |
88 /// Indicates an insufficiently refined state: the [`BT`] needs to be further refined. |
| 79 NeedRefinement, |
89 NeedRefinement, |
| 80 /// Indicates a certain result `R`, stop refinement immediately. |
90 /// Indicates a certain result `R`, stop refinement immediately. |
| 81 Certain(R), |
91 Certain(R), |
| 82 /// Indicates an uncertain result: continue refinement until candidates have been exhausted |
92 /// Indicates an uncertain result: continue refinement until candidates have been exhausted |
| 83 /// or a certain result found. |
93 /// or a certain result found. |
| 84 Uncertain(A, R) |
94 Uncertain(A, R), |
| 85 } |
95 } |
| 86 |
96 |
| 87 use RefinerResult::*; |
97 use RefinerResult::*; |
| 88 |
98 |
| 89 /// A `Refiner` is used to search a [`BT`], refining the subdivision when necessary. |
99 /// A `Refiner` is used to search a [`BT`], refining the subdivision when necessary. |
| 90 /// |
100 /// |
| 91 /// The search is performed by [`BTSearch::search_and_refine`]. |
101 /// The search is performed by [`BTSearch::search_and_refine`]. |
| 92 /// The `Refiner` is used to determine whether an [`Aggregator`] `A` stored in the [`BT`] is |
102 /// The `Refiner` is used to determine whether an [`Aggregator`] `A` stored in the [`BT`] is |
| 93 /// sufficiently refined within a [`Cube`], and in such a case, produce a desired result (e.g. |
103 /// sufficiently refined within a [`Cube`], and in such a case, produce a desired result (e.g. |
| 94 /// a maximum value of a function). |
104 /// a maximum value of a function). |
| 95 pub trait Refiner<F : Float, A, G, const N : usize> : Sync + Send + 'static |
105 pub trait Refiner<F: Float, A, G, const N: usize>: Sync + Send + 'static |
| 96 where F : Num, |
106 where |
| 97 A : Aggregator, |
107 F: Num, |
| 98 G : SupportGenerator<F, N> { |
108 A: Aggregator, |
| 99 |
109 G: SupportGenerator<N, F>, |
| |
110 { |
| 100 /// The result type of the refiner |
111 /// The result type of the refiner |
| 101 type Result : std::fmt::Debug + Sync + Send + 'static; |
112 type Result: std::fmt::Debug + Sync + Send + 'static; |
| 102 /// The sorting to be employed by [`BTSearch::search_and_refine`] on node aggregators |
113 /// The sorting to be employed by [`BTSearch::search_and_refine`] on node aggregators |
| 103 /// to detemrine node priority. |
114 /// to detemrine node priority. |
| 104 type Sorting : AggregatorSorting<Agg = A>; |
115 type Sorting: AggregatorSorting<Agg = A>; |
| 105 |
116 |
| 106 /// Determines whether `aggregator` is sufficiently refined within `domain`. |
117 /// Determines whether `aggregator` is sufficiently refined within `domain`. |
| 107 /// |
118 /// |
| 108 /// If the aggregator is sufficiently refined that the desired `Self::Result` can be produced, |
119 /// If the aggregator is sufficiently refined that the desired `Self::Result` can be produced, |
| 109 /// a [`RefinerResult`]`::Certain` or `Uncertain` should be returned, depending on |
120 /// a [`RefinerResult`]`::Certain` or `Uncertain` should be returned, depending on |
| 122 /// The `generator` can be used to convert `data` into [`Support`]s. The parameter `step` |
133 /// The `generator` can be used to convert `data` into [`Support`]s. The parameter `step` |
| 123 /// counts the calls to `refine`, and can be used to stop the refinement when a maximum |
134 /// counts the calls to `refine`, and can be used to stop the refinement when a maximum |
| 124 /// number of steps is reached. |
135 /// number of steps is reached. |
| 125 fn refine( |
136 fn refine( |
| 126 &self, |
137 &self, |
| 127 aggregator : &A, |
138 aggregator: &A, |
| 128 domain : &Cube<F, N>, |
139 domain: &Cube<N, F>, |
| 129 data : &[G::Id], |
140 data: &[G::Id], |
| 130 generator : &G, |
141 generator: &G, |
| 131 step : usize, |
142 step: usize, |
| 132 ) -> RefinerResult<A, Self::Result>; |
143 ) -> RefinerResult<A, Self::Result>; |
| 133 |
144 |
| 134 /// Fuse two [`Self::Result`]s (needed in threaded refinement). |
145 /// Fuse two [`Self::Result`]s (needed in threaded refinement). |
| 135 fn fuse_results(r1 : &mut Self::Result, r2 : Self::Result); |
146 fn fuse_results(r1: &mut Self::Result, r2: Self::Result); |
| 136 } |
147 } |
| 137 |
148 |
| 138 /// Structure for tracking the refinement process in a [`BinaryHeap`]. |
149 /// Structure for tracking the refinement process in a [`BinaryHeap`]. |
| 139 struct RefinementInfo<'a, F, D, A, S, RResult, const N : usize, const P : usize> |
150 struct RefinementInfo<'a, F, D, A, S, RResult, const N: usize, const P: usize> |
| 140 where F : Float, |
151 where |
| 141 D : 'static, |
152 F: Float, |
| 142 A : Aggregator, |
153 D: 'static, |
| 143 S : AggregatorSorting<Agg = A> { |
154 A: Aggregator, |
| |
155 S: AggregatorSorting<Agg = A>, |
| |
156 { |
| 144 /// Domain of `node` |
157 /// Domain of `node` |
| 145 cube : Cube<F, N>, |
158 cube: Cube<N, F>, |
| 146 /// Node to be refined |
159 /// Node to be refined |
| 147 node : &'a mut Node<F, D, A, N, P>, |
160 node: &'a mut Node<F, D, A, N, P>, |
| 148 /// Result and improve aggregator for the [`Refiner`] |
161 /// Result and improve aggregator for the [`Refiner`] |
| 149 refiner_info : Option<(A, RResult)>, |
162 refiner_info: Option<(A, RResult)>, |
| 150 /// For [`AggregatorSorting`] being used for the type system |
163 /// For [`AggregatorSorting`] being used for the type system |
| 151 sorting : PhantomData<S>, |
164 sorting: PhantomData<S>, |
| 152 } |
165 } |
| 153 |
166 |
| 154 impl<'a, F, D, A, S, RResult, const N : usize, const P : usize> |
167 impl<'a, F, D, A, S, RResult, const N: usize, const P: usize> |
| 155 RefinementInfo<'a, F, D, A, S, RResult, N, P> |
168 RefinementInfo<'a, F, D, A, S, RResult, N, P> |
| 156 where F : Float, |
169 where |
| 157 D : 'static, |
170 F: Float, |
| 158 A : Aggregator, |
171 D: 'static, |
| 159 S : AggregatorSorting<Agg = A> { |
172 A: Aggregator, |
| 160 |
173 S: AggregatorSorting<Agg = A>, |
| 161 #[inline] |
174 { |
| 162 fn with_aggregator<U>(&self, f : impl FnOnce(&A) -> U) -> U { |
175 #[inline] |
| |
176 fn with_aggregator<U>(&self, f: impl FnOnce(&A) -> U) -> U { |
| 163 match self.refiner_info { |
177 match self.refiner_info { |
| 164 Some((ref agg, _)) => f(agg), |
178 Some((ref agg, _)) => f(agg), |
| 165 None => f(&self.node.aggregator), |
179 None => f(&self.node.aggregator), |
| 166 } |
180 } |
| 167 } |
181 } |
| 175 fn sort_upper(&self) -> S::Sort { |
189 fn sort_upper(&self) -> S::Sort { |
| 176 self.with_aggregator(S::sort_upper) |
190 self.with_aggregator(S::sort_upper) |
| 177 } |
191 } |
| 178 } |
192 } |
| 179 |
193 |
| 180 impl<'a, F, D, A, S, RResult, const N : usize, const P : usize> PartialEq |
194 impl<'a, F, D, A, S, RResult, const N: usize, const P: usize> PartialEq |
| 181 for RefinementInfo<'a, F, D, A, S, RResult, N, P> |
195 for RefinementInfo<'a, F, D, A, S, RResult, N, P> |
| 182 where F : Float, |
196 where |
| 183 D : 'static, |
197 F: Float, |
| 184 A : Aggregator, |
198 D: 'static, |
| 185 S : AggregatorSorting<Agg = A> { |
199 A: Aggregator, |
| 186 |
200 S: AggregatorSorting<Agg = A>, |
| 187 #[inline] |
201 { |
| 188 fn eq(&self, other : &Self) -> bool { self.cmp(other) == Equal } |
202 #[inline] |
| 189 } |
203 fn eq(&self, other: &Self) -> bool { |
| 190 |
204 self.cmp(other) == Equal |
| 191 impl<'a, F, D, A, S, RResult, const N : usize, const P : usize> PartialOrd |
205 } |
| 192 for RefinementInfo<'a, F, D, A, S, RResult, N, P> |
206 } |
| 193 where F : Float, |
207 |
| 194 D : 'static, |
208 impl<'a, F, D, A, S, RResult, const N: usize, const P: usize> PartialOrd |
| 195 A : Aggregator, |
209 for RefinementInfo<'a, F, D, A, S, RResult, N, P> |
| 196 S : AggregatorSorting<Agg = A> { |
210 where |
| 197 |
211 F: Float, |
| 198 #[inline] |
212 D: 'static, |
| 199 fn partial_cmp(&self, other : &Self) -> Option<Ordering> { Some(self.cmp(other)) } |
213 A: Aggregator, |
| 200 } |
214 S: AggregatorSorting<Agg = A>, |
| 201 |
215 { |
| 202 impl<'a, F, D, A, S, RResult, const N : usize, const P : usize> Eq |
216 #[inline] |
| 203 for RefinementInfo<'a, F, D, A, S, RResult, N, P> |
217 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
| 204 where F : Float, |
218 Some(self.cmp(other)) |
| 205 D : 'static, |
219 } |
| 206 A : Aggregator, |
220 } |
| 207 S : AggregatorSorting<Agg = A> { |
221 |
| 208 } |
222 impl<'a, F, D, A, S, RResult, const N: usize, const P: usize> Eq |
| 209 |
223 for RefinementInfo<'a, F, D, A, S, RResult, N, P> |
| 210 impl<'a, F, D, A, S, RResult, const N : usize, const P : usize> Ord |
224 where |
| 211 for RefinementInfo<'a, F, D, A, S, RResult, N, P> |
225 F: Float, |
| 212 where F : Float, |
226 D: 'static, |
| 213 D : 'static, |
227 A: Aggregator, |
| 214 A : Aggregator, |
228 S: AggregatorSorting<Agg = A>, |
| 215 S : AggregatorSorting<Agg = A> { |
229 { |
| 216 |
230 } |
| 217 #[inline] |
231 |
| 218 fn cmp(&self, other : &Self) -> Ordering { |
232 impl<'a, F, D, A, S, RResult, const N: usize, const P: usize> Ord |
| 219 self.with_aggregator(|agg1| other.with_aggregator(|agg2| { |
233 for RefinementInfo<'a, F, D, A, S, RResult, N, P> |
| 220 match S::sort_upper(agg1).cmp(&S::sort_upper(agg2)) { |
234 where |
| |
235 F: Float, |
| |
236 D: 'static, |
| |
237 A: Aggregator, |
| |
238 S: AggregatorSorting<Agg = A>, |
| |
239 { |
| |
240 #[inline] |
| |
241 fn cmp(&self, other: &Self) -> Ordering { |
| |
242 self.with_aggregator(|agg1| { |
| |
243 other.with_aggregator(|agg2| match S::sort_upper(agg1).cmp(&S::sort_upper(agg2)) { |
| 221 Equal => S::sort_lower(agg1).cmp(&S::sort_lower(agg2)), |
244 Equal => S::sort_lower(agg1).cmp(&S::sort_lower(agg2)), |
| 222 order => order, |
245 order => order, |
| 223 } |
246 }) |
| 224 })) |
247 }) |
| 225 } |
248 } |
| 226 } |
249 } |
| 227 |
250 |
| 228 /// This is a container for a [`BinaryHeap`] of [`RefinementInfo`]s together with tracking of |
251 /// This is a container for a [`BinaryHeap`] of [`RefinementInfo`]s together with tracking of |
| 229 /// the greatest lower bound of the [`Aggregator`]s of the [`Node`]s therein accroding to |
252 /// the greatest lower bound of the [`Aggregator`]s of the [`Node`]s therein accroding to |
| 230 /// chosen [`AggregatorSorting`]. |
253 /// chosen [`AggregatorSorting`]. |
| 231 struct HeapContainer<'a, F, D, A, S, RResult, const N : usize, const P : usize> |
254 struct HeapContainer<'a, F, D, A, S, RResult, const N: usize, const P: usize> |
| 232 where F : Float, |
255 where |
| 233 D : 'static + Copy, |
256 F: Float, |
| 234 Const<P> : BranchCount<N>, |
257 D: 'static + Copy, |
| 235 A : Aggregator, |
258 Const<P>: BranchCount<N>, |
| 236 S : AggregatorSorting<Agg = A> { |
259 A: Aggregator, |
| |
260 S: AggregatorSorting<Agg = A>, |
| |
261 { |
| 237 /// Priority queue of nodes to be refined |
262 /// Priority queue of nodes to be refined |
| 238 heap : BinaryHeap<RefinementInfo<'a, F, D, A, S, RResult, N, P>>, |
263 heap: BinaryHeap<RefinementInfo<'a, F, D, A, S, RResult, N, P>>, |
| 239 /// Maximum of node sorting lower bounds seen in the heap |
264 /// Maximum of node sorting lower bounds seen in the heap |
| 240 glb : S::Sort, |
265 glb: S::Sort, |
| 241 /// Number of insertions in the heap since previous prune |
266 /// Number of insertions in the heap since previous prune |
| 242 insert_counter : usize, |
267 insert_counter: usize, |
| 243 /// If a result has been found by some refinment threat, it is stored here |
268 /// If a result has been found by some refinment threat, it is stored here |
| 244 result : Option<RResult>, |
269 result: Option<RResult>, |
| 245 /// Refinement step counter |
270 /// Refinement step counter |
| 246 step : usize, |
271 step: usize, |
| 247 /// Number of threads currently processing (not sleeping) |
272 /// Number of threads currently processing (not sleeping) |
| 248 n_processing : usize, |
273 n_processing: usize, |
| 249 /// Threshold for heap pruning |
274 /// Threshold for heap pruning |
| 250 heap_prune_threshold : usize, |
275 heap_prune_threshold: usize, |
| 251 } |
276 } |
| 252 |
277 |
| 253 impl<'a, F, D, A, S, RResult, const N : usize, const P : usize> |
278 impl<'a, F, D, A, S, RResult, const N: usize, const P: usize> |
| 254 HeapContainer<'a, F, D, A, S, RResult, N, P> |
279 HeapContainer<'a, F, D, A, S, RResult, N, P> |
| 255 where F : Float, |
280 where |
| 256 D : 'static + Copy, |
281 F: Float, |
| 257 Const<P> : BranchCount<N>, |
282 D: 'static + Copy, |
| 258 A : Aggregator, |
283 Const<P>: BranchCount<N>, |
| 259 S : AggregatorSorting<Agg = A> { |
284 A: Aggregator, |
| 260 |
285 S: AggregatorSorting<Agg = A>, |
| |
286 { |
| 261 /// Push `ri` into the [`BinaryHeap`]. Do greatest lower bound maintenance. |
287 /// Push `ri` into the [`BinaryHeap`]. Do greatest lower bound maintenance. |
| 262 /// |
288 /// |
| 263 /// Returns a boolean indicating whether the push was actually performed due to glb |
289 /// Returns a boolean indicating whether the push was actually performed due to glb |
| 264 /// filtering or not. |
290 /// filtering or not. |
| 265 #[inline] |
291 #[inline] |
| 266 fn push(&mut self, ri : RefinementInfo<'a, F, D, A, S, RResult, N, P>) -> bool { |
292 fn push(&mut self, ri: RefinementInfo<'a, F, D, A, S, RResult, N, P>) -> bool { |
| 267 if ri.sort_upper() >= self.glb { |
293 if ri.sort_upper() >= self.glb { |
| 268 let l = ri.sort_lower(); |
294 let l = ri.sort_lower(); |
| 269 self.heap.push(ri); |
295 self.heap.push(ri); |
| 270 self.glb = self.glb.max(l); |
296 self.glb = self.glb.max(l); |
| 271 self.insert_counter += 1; |
297 self.insert_counter += 1; |
| 274 false |
300 false |
| 275 } |
301 } |
| 276 } |
302 } |
| 277 } |
303 } |
| 278 |
304 |
| 279 impl<F : Float, D, A, const N : usize, const P : usize> |
305 impl<F: Float, D, A, const N: usize, const P: usize> Branches<F, D, A, N, P> |
| 280 Branches<F,D,A,N,P> |
306 where |
| 281 where Const<P> : BranchCount<N>, |
307 Const<P>: BranchCount<N>, |
| 282 A : Aggregator, |
308 A: Aggregator, |
| 283 D : 'static + Copy + Send + Sync { |
309 D: 'static + Copy + Send + Sync, |
| 284 |
310 { |
| 285 /// Stage all subnodes of `self` into the refinement queue `container`. |
311 /// Stage all subnodes of `self` into the refinement queue `container`. |
| 286 fn stage_refine<'a, S, RResult>( |
312 fn stage_refine<'a, S, RResult>( |
| 287 &'a mut self, |
313 &'a mut self, |
| 288 domain : Cube<F,N>, |
314 domain: Cube<N, F>, |
| 289 container : &mut HeapContainer<'a, F, D, A, S, RResult, N, P>, |
315 container: &mut HeapContainer<'a, F, D, A, S, RResult, N, P>, |
| 290 ) where S : AggregatorSorting<Agg = A> { |
316 ) where |
| |
317 S: AggregatorSorting<Agg = A>, |
| |
318 { |
| 291 // Insert all subnodes into the refinement heap. |
319 // Insert all subnodes into the refinement heap. |
| 292 for (node, cube) in self.nodes_and_cubes_mut(&domain) { |
320 for (node, cube) in self.nodes_and_cubes_mut(&domain) { |
| 293 container.push(RefinementInfo { |
321 container.push(RefinementInfo { |
| 294 cube, |
322 cube, |
| 295 node, |
323 node, |
| 296 refiner_info : None, |
324 refiner_info: None, |
| 297 sorting : PhantomData, |
325 sorting: PhantomData, |
| 298 }); |
326 }); |
| 299 } |
327 } |
| 300 } |
328 } |
| 301 } |
329 } |
| 302 |
330 |
| 303 |
331 impl<F: Float, D, A, const N: usize, const P: usize> Node<F, D, A, N, P> |
| 304 impl<F : Float, D, A, const N : usize, const P : usize> |
332 where |
| 305 Node<F,D,A,N,P> |
333 Const<P>: BranchCount<N>, |
| 306 where Const<P> : BranchCount<N>, |
334 A: Aggregator, |
| 307 A : Aggregator, |
335 D: 'static + Copy + Send + Sync, |
| 308 D : 'static + Copy + Send + Sync { |
336 { |
| 309 |
|
| 310 /// If `self` is a leaf node, uses the `refiner` to determine whether further subdivision |
337 /// If `self` is a leaf node, uses the `refiner` to determine whether further subdivision |
| 311 /// is required to get a sufficiently refined solution for the problem the refiner is used |
338 /// is required to get a sufficiently refined solution for the problem the refiner is used |
| 312 /// to solve. If the refiner returns [`RefinerResult::Certain`] result, it is returned. |
339 /// to solve. If the refiner returns [`RefinerResult::Certain`] result, it is returned. |
| 313 /// If [`RefinerResult::Uncertain`] is returned, the leaf is inserted back into the refinement |
340 /// If [`RefinerResult::Uncertain`] is returned, the leaf is inserted back into the refinement |
| 314 /// queue `container`. If `self` is a branch, its subnodes are staged into `container` using |
341 /// queue `container`. If `self` is a branch, its subnodes are staged into `container` using |
| 315 /// [`Branches::stage_refine`]. |
342 /// [`Branches::stage_refine`]. |
| 316 /// |
343 /// |
| 317 /// `domain`, as usual, indicates the spatial area corresponding to `self`. |
344 /// `domain`, as usual, indicates the spatial area corresponding to `self`. |
| 318 fn search_and_refine<'a, 'b, 'c, R, G>( |
345 fn search_and_refine<'a, 'b, 'c, R, G>( |
| 319 self : &'a mut Self, |
346 self: &'a mut Self, |
| 320 domain : Cube<F,N>, |
347 domain: Cube<N, F>, |
| 321 refiner : &R, |
348 refiner: &R, |
| 322 generator : &G, |
349 generator: &G, |
| 323 container_arc : &'c Arc<Mutex<HeapContainer<'a, F, D, A, R::Sorting, R::Result, N, P>>>, |
350 container_arc: &'c Arc<Mutex<HeapContainer<'a, F, D, A, R::Sorting, R::Result, N, P>>>, |
| 324 step : usize |
351 step: usize, |
| 325 ) -> Result<R::Result, MutexGuard<'c, HeapContainer<'a, F, D, A, R::Sorting, R::Result, N, P>>> |
352 ) -> Result<R::Result, MutexGuard<'c, HeapContainer<'a, F, D, A, R::Sorting, R::Result, N, P>>> |
| 326 where R : Refiner<F, A, G, N>, |
353 where |
| 327 G : SupportGenerator<F, N, Id=D>, |
354 R: Refiner<F, A, G, N>, |
| 328 G::SupportType : LocalAnalysis<F, A, N> { |
355 G: SupportGenerator<N, F, Id = D>, |
| 329 |
356 G::SupportType: LocalAnalysis<F, A, N>, |
| |
357 { |
| 330 //drop(container); |
358 //drop(container); |
| 331 |
359 |
| 332 // Refine a leaf. |
360 // Refine a leaf. |
| 333 let res = match self.data { |
361 let res = match self.data { |
| 334 NodeOption::Leaf(ref mut v) => { |
362 NodeOption::Leaf(ref mut v) => { |
| 435 /// [`RefinerResult::Uncertain`] result is found again at the top of the priority queue. |
465 /// [`RefinerResult::Uncertain`] result is found again at the top of the priority queue. |
| 436 /// |
466 /// |
| 437 /// The `generator` converts [`BTImpl::Data`] stored in the bisection tree into a [`Support`]. |
467 /// The `generator` converts [`BTImpl::Data`] stored in the bisection tree into a [`Support`]. |
| 438 fn search_and_refine<'b, R, G>( |
468 fn search_and_refine<'b, R, G>( |
| 439 &'b mut self, |
469 &'b mut self, |
| 440 refiner : R, |
470 refiner: R, |
| 441 generator : &Arc<G>, |
471 generator: &Arc<G>, |
| 442 ) -> Option<R::Result> |
472 ) -> Option<R::Result> |
| 443 where R : Refiner<F, Self::Agg, G, N> + Sync + Send + 'static, |
473 where |
| 444 G : SupportGenerator<F, N, Id=Self::Data> + Sync + Send + 'static, |
474 R: Refiner<F, Self::Agg, G, N> + Sync + Send + 'static, |
| 445 G::SupportType : LocalAnalysis<F, Self::Agg, N>; |
475 G: SupportGenerator<N, F, Id = Self::Data> + Sync + Send + 'static, |
| 446 } |
476 G::SupportType: LocalAnalysis<F, Self::Agg, N>; |
| 447 |
477 } |
| 448 fn refinement_loop<F : Float, D, A, R, G, const N : usize, const P : usize> ( |
478 |
| 449 wakeup : Option<Arc<Condvar>>, |
479 fn refinement_loop<F: Float, D, A, R, G, const N: usize, const P: usize>( |
| 450 refiner : &R, |
480 wakeup: Option<Arc<Condvar>>, |
| 451 generator_arc : &Arc<G>, |
481 refiner: &R, |
| 452 container_arc : &Arc<Mutex<HeapContainer<F, D, A, R::Sorting, R::Result, N, P>>>, |
482 generator_arc: &Arc<G>, |
| 453 ) where A : Aggregator, |
483 container_arc: &Arc<Mutex<HeapContainer<F, D, A, R::Sorting, R::Result, N, P>>>, |
| 454 R : Refiner<F, A, G, N>, |
484 ) where |
| 455 G : SupportGenerator<F, N, Id=D>, |
485 A: Aggregator, |
| 456 G::SupportType : LocalAnalysis<F, A, N>, |
486 R: Refiner<F, A, G, N>, |
| 457 Const<P> : BranchCount<N>, |
487 G: SupportGenerator<N, F, Id = D>, |
| 458 D : 'static + Copy + Sync + Send + std::fmt::Debug { |
488 G::SupportType: LocalAnalysis<F, A, N>, |
| 459 |
489 Const<P>: BranchCount<N>, |
| |
490 D: 'static + Copy + Sync + Send + std::fmt::Debug, |
| |
491 { |
| 460 let mut did_park = true; |
492 let mut did_park = true; |
| 461 let mut container = container_arc.lock().unwrap(); |
493 let mut container = container_arc.lock().unwrap(); |
| 462 |
494 |
| 463 'main: loop { |
495 'main: loop { |
| 464 // Find a node to process |
496 // Find a node to process |
| 500 |
532 |
| 501 if let Some((_, result)) = ri.refiner_info { |
533 if let Some((_, result)) = ri.refiner_info { |
| 502 // Terminate based on a “best possible” result. |
534 // Terminate based on a “best possible” result. |
| 503 container.result = Some(result); |
535 container.result = Some(result); |
| 504 container.n_processing -= 1; |
536 container.n_processing -= 1; |
| 505 break 'main |
537 break 'main; |
| 506 } |
538 } |
| 507 |
539 |
| 508 // Do priority queue maintenance |
540 // Do priority queue maintenance |
| 509 if container.insert_counter > container.heap_prune_threshold { |
541 if container.insert_counter > container.heap_prune_threshold { |
| 510 // Make sure glb is good. |
542 // Make sure glb is good. |
| 511 match container.heap.iter().map(|ri| ri.sort_lower()).reduce(max) { |
543 match container.heap.iter().map(|ri| ri.sort_lower()).reduce(max) { |
| 512 Some(glb) => { |
544 Some(glb) => { |
| 513 container.glb = glb; |
545 container.glb = glb; |
| 514 // Prune |
546 // Prune |
| 515 container.heap.retain(|ri| ri.sort_upper() >= glb); |
547 container.heap.retain(|ri| ri.sort_upper() >= glb); |
| 516 }, |
|
| 517 None => { |
|
| 518 container.glb = R::Sorting::bottom() |
|
| 519 } |
548 } |
| |
549 None => container.glb = R::Sorting::bottom(), |
| 520 } |
550 } |
| 521 container.insert_counter = 0; |
551 container.insert_counter = 0; |
| 522 } |
552 } |
| 523 |
553 |
| 524 // Unlock the mutex… |
554 // Unlock the mutex… |
| 525 drop(container); |
555 drop(container); |
| 526 |
556 |
| 527 // … and process the node. We may get returned an already unlocked mutex. |
557 // … and process the node. We may get returned an already unlocked mutex. |
| 528 match Node::search_and_refine(ri.node, ri.cube, refiner, &**generator_arc, |
558 match Node::search_and_refine( |
| 529 &container_arc, step) { |
559 ri.node, |
| |
560 ri.cube, |
| |
561 refiner, |
| |
562 &**generator_arc, |
| |
563 &container_arc, |
| |
564 step, |
| |
565 ) { |
| 530 Ok(r) => { |
566 Ok(r) => { |
| 531 let mut container = container_arc.lock().unwrap(); |
567 let mut container = container_arc.lock().unwrap(); |
| 532 // Terminate based on a certain result from the refiner |
568 // Terminate based on a certain result from the refiner |
| 533 match container.result { |
569 match container.result { |
| 534 Some(ref mut r_prev) => R::fuse_results(r_prev, r), |
570 Some(ref mut r_prev) => R::fuse_results(r_prev, r), |
| 535 None => container.result = Some(r), |
571 None => container.result = Some(r), |
| 536 } |
572 } |
| 537 break 'main |
573 break 'main; |
| 538 }, |
574 } |
| 539 Err(cnt) => { |
575 Err(cnt) => { |
| 540 container = cnt; |
576 container = cnt; |
| 541 // Wake up another thread if one is sleeping; there should be now work in the |
577 // Wake up another thread if one is sleeping; there should be now work in the |
| 542 // queue. |
578 // queue. |
| 543 if let Some(ref c) = wakeup { |
579 if let Some(ref c) = wakeup { |
| 544 c.notify_one(); |
580 c.notify_one(); |
| 545 } |
581 } |
| 546 } |
582 } |
| 547 } |
583 } |
| 548 |
|
| 549 } |
584 } |
| 550 |
585 |
| 551 // Make sure no task is sleeping |
586 // Make sure no task is sleeping |
| 552 if let Some(ref c) = wakeup { |
587 if let Some(ref c) = wakeup { |
| 553 c.notify_all(); |
588 c.notify_all(); |
| 556 |
591 |
| 557 // Needed to get access to a Node without a trait interface. |
592 // Needed to get access to a Node without a trait interface. |
| 558 macro_rules! impl_btsearch { |
593 macro_rules! impl_btsearch { |
| 559 ($($n:literal)*) => { $( |
594 ($($n:literal)*) => { $( |
| 560 impl<'a, M, F, D, A> |
595 impl<'a, M, F, D, A> |
| 561 BTSearch<F, $n> |
596 BTSearch<$n, F> |
| 562 for BT<M,F,D,A,$n> |
597 for BT<M,F,D,A,$n> |
| 563 where //Self : BTImpl<F,$n,Data=D,Agg=A, Depth=M>, // <== automatically deduced |
598 where //Self : BTImpl<$n, F, Data=D,Agg=A, Depth=M>, // <== automatically deduced |
| 564 M : Depth, |
599 M : Depth, |
| 565 F : Float + Send, |
600 F : Float + Send, |
| 566 A : Aggregator, |
601 A : Aggregator, |
| 567 D : 'static + Copy + Sync + Send + std::fmt::Debug { |
602 D : 'static + Copy + Sync + Send + std::fmt::Debug { |
| 568 fn search_and_refine<'b, R, G>( |
603 fn search_and_refine<'b, R, G>( |
| 569 &'b mut self, |
604 &'b mut self, |
| 570 refiner : R, |
605 refiner : R, |
| 571 generator : &Arc<G>, |
606 generator : &Arc<G>, |
| 572 ) -> Option<R::Result> |
607 ) -> Option<R::Result> |
| 573 where R : Refiner<F, A, G, $n>, |
608 where R : Refiner<F, A, G, $n>, |
| 574 G : SupportGenerator<F, $n, Id=D>, |
609 G : SupportGenerator< $n, F, Id=D>, |
| 575 G::SupportType : LocalAnalysis<F, A, $n> { |
610 G::SupportType : LocalAnalysis<F, A, $n> { |
| 576 let mut init_container = HeapContainer { |
611 let mut init_container = HeapContainer { |
| 577 heap : BinaryHeap::new(), |
612 heap : BinaryHeap::new(), |
| 578 glb : R::Sorting::bottom(), |
613 glb : R::Sorting::bottom(), |
| 579 insert_counter : 0, |
614 insert_counter : 0, |