Sun, 19 Jan 2025 22:33:21 +0100
doc updates
0 | 1 | /*! |
5 | 2 | Tools for separating the computational steps of an iterative algorithm from stopping rules |
3 | and reporting. | |
0 | 4 | |
5 | 5 | The computational step is to be implemented as a closure. That closure gets passed a `state` |
6 | parameter that implements an [`if_verbose`][AlgIteratorState::if_verbose] method that is to | |
7 | be called to determine whether function values or other potentially costly things need to be | |
8 | calculated on that iteration. The parameter of [`if_verbose`][AlgIteratorState::if_verbose] is | |
9 | another closure that does the necessary computation. | |
0 | 10 | |
11 | ## Simple example | |
12 | ||
13 | ```rust | |
5 | 14 | # use alg_tools::types::*; |
15 | # use alg_tools::iterate::*; | |
16 | let mut iter = AlgIteratorOptions{ | |
17 | max_iter : 100, | |
18 | verbose_iter : Verbose::Every(10), | |
19 | .. Default::default() | |
20 | }; | |
0 | 21 | let mut x = 1 as float; |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
22 | # let mut iter_clone = iter.clone(); |
0 | 23 | iter.iterate(|state|{ |
24 | // This is our computational step | |
25 | x = x + x.sqrt(); | |
26 | state.if_verbose(||{ | |
27 | // return current value when requested | |
28 | return x | |
29 | }) | |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
30 | }); |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
31 | // or alternatively (avoiding problems with moves) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
32 | # iter = iter_clone; |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
33 | for state in iter.iter() { |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
34 | // This is our computational step |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
35 | x = x + x.sqrt(); |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
36 | state.if_verbose(||{ |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
37 | // return current value when requested |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
38 | return x |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
39 | }) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
40 | } |
0 | 41 | ``` |
42 | There is no colon after `state.if_verbose`, because we need to return its value. If you do something after the step, you need to store the result in a variable and return it from the main computational step afterwards. | |
43 | ||
44 | This will print out | |
45 | ```output | |
46 | 10/100 J=31.051164 | |
47 | 20/100 J=108.493699 | |
48 | 30/100 J=234.690039 | |
49 | 40/100 J=410.056327 | |
50 | 50/100 J=634.799262 | |
51 | 60/100 J=909.042928 | |
52 | 70/100 J=1232.870172 | |
53 | 80/100 J=1606.340254 | |
54 | 90/100 J=2029.497673 | |
55 | 100/100 J=2502.377071 | |
56 | ``` | |
57 | */ | |
58 | ||
5 | 59 | use colored::{Colorize, ColoredString}; |
0 | 60 | use core::fmt::Debug; |
61 | use serde::{Serialize, Deserialize}; | |
62 | use cpu_time::ProcessTime; | |
63 | use std::marker::PhantomData; | |
64 | use std::time::Duration; | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
65 | use std::error::Error; |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
66 | use std::cell::RefCell; |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
67 | use std::rc::Rc; |
0 | 68 | use crate::types::*; |
69 | use crate::logger::*; | |
70 | ||
5 | 71 | /// Create the displayed presentation for log items. |
0 | 72 | pub trait LogRepr : Debug { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
73 | fn logrepr(&self) -> ColoredString { format!("« {self:?} »").as_str().into() } |
0 | 74 | } |
75 | ||
76 | impl LogRepr for str { | |
77 | fn logrepr(&self) -> ColoredString { self.into() } | |
78 | } | |
79 | ||
80 | impl LogRepr for String { | |
81 | fn logrepr(&self) -> ColoredString { self.as_str().into() } | |
82 | } | |
83 | ||
84 | impl<T> LogRepr for T where T : Num { | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
85 | fn logrepr(&self) -> ColoredString { format!("J={self}").as_str().into() } |
0 | 86 | } |
87 | ||
88 | impl<V> LogRepr for Option<V> where V : LogRepr { | |
89 | fn logrepr(&self) -> ColoredString { | |
90 | match self { | |
91 | None => { "===missing value===".red() } | |
92 | Some(v) => { v.logrepr() } | |
93 | } | |
94 | } | |
95 | } | |
96 | ||
5 | 97 | /// Helper struct for returning results annotated with an additional string to |
98 | /// [`if_verbose`][AlgIteratorState::if_verbose]. The [`LogRepr`] implementation will | |
99 | /// display that string when so decided by the specific [`AlgIterator`] in use. | |
0 | 100 | #[derive(Debug,Clone)] |
101 | pub struct Annotated<F>(pub F, pub String); | |
102 | ||
103 | impl<V> LogRepr for Annotated<V> where V : LogRepr { | |
104 | fn logrepr(&self) -> ColoredString { | |
105 | format!("{}\t| {}", self.0.logrepr(), self.1).as_str().into() | |
106 | } | |
107 | } | |
108 | ||
109 | ||
110 | /// Basic log item. | |
111 | #[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)] | |
112 | pub struct LogItem<V> { | |
113 | pub iter : usize, | |
114 | // This causes [`csv`] to crash. | |
115 | //#[serde(flatten)] | |
116 | pub data : V | |
117 | } | |
118 | ||
5 | 119 | impl<V> LogItem<V> { |
120 | /// Creates a new log item | |
121 | fn new(iter : usize, data : V) -> Self { | |
122 | LogItem{ iter, data } | |
123 | } | |
0 | 124 | } |
125 | ||
5 | 126 | /// State of an [`AlgIterator`]. |
127 | /// | |
128 | /// This is the parameter obtained by the closure passed to [`AlgIterator::iterate`] or | |
129 | /// [`AlgIteratorFactory::iterate`]. | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
130 | pub trait AlgIteratorState : Sized { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
131 | /// Call `call_objective` if this is a verbose iteration. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
132 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
133 | /// Verbosity depends on the [`AlgIterator`] that produced this state. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
134 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
135 | /// The closure `calc_objective` should return an arbitrary value of type `V`, to be inserted |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
136 | /// into the log, or whatever is deemed by the [`AlgIterator`]. For usage instructions see the |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
137 | /// [module documentation][self]. |
46 | 138 | fn if_verbose<V, E : Error>(self, calc_objective : impl FnOnce() -> V) -> Step<V, Self, E>; |
0 | 139 | |
5 | 140 | /// Returns the current iteration count. |
0 | 141 | fn iteration(&self) -> usize; |
31
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
142 | |
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
143 | /// Indicates whether the iterator is quiet |
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
144 | fn is_quiet(&self) -> bool; |
0 | 145 | } |
146 | ||
147 | /// Result of a step of an [`AlgIterator`] | |
148 | #[derive(Debug, Serialize)] | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
149 | pub enum Step<V, S, Fail : Error = std::convert::Infallible> { |
0 | 150 | /// Iteration should be terminated |
151 | Terminated, | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
152 | /// Iteration should be terminated due to failure |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
153 | Failure(Fail), |
0 | 154 | /// No result this iteration (due to verbosity settings) |
155 | Quiet, | |
156 | /// Result of this iteration (due to verbosity settings) | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
157 | Result(V, S), |
0 | 158 | } |
159 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
160 | impl<V, S, E : Error> Step<V, S, E> { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
161 | /// Maps the value contained within the `Step`, if any, by the closure `f`. |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
162 | pub fn map<U>(self, mut f : impl FnMut(V) -> U) -> Step<U, S, E> { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
163 | match self { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
164 | Step::Result(v, s) => Step::Result(f(v), s), |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
165 | Step::Failure(e) => Step::Failure(e), |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
166 | Step::Quiet => Step::Quiet, |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
167 | Step::Terminated => Step::Terminated, |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
168 | } |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
169 | } |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
170 | } |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
171 | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
172 | impl<V, S, E : Error> Default for Step<V, S, E> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
173 | fn default() -> Self { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
174 | Step::Quiet |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
175 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
176 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
177 | |
5 | 178 | /// An iterator for algorithms, produced by [`AlgIteratorFactory::prepare`]. |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
179 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
180 | /// Typically not accessed directly, but transparently produced by an [`AlgIteratorFactory`]. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
181 | /// Every [`AlgIteratorFactory`] has to implement a corresponding `AlgIterator`. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
182 | pub trait AlgIterator : Sized { |
5 | 183 | /// The state type |
0 | 184 | type State : AlgIteratorState; |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
185 | /// The output type for [`Self::poststep`] and [`Self::step`]. |
0 | 186 | type Output; |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
187 | /// The input type for [`Self::poststep`]. |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
188 | type Input; |
0 | 189 | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
190 | /// Advance the iterator, performing `step_fn` with the state |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
191 | fn step<F, E>(&mut self, step_fn : &mut F) -> Step<Self::Output, Self::State, E> |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
192 | where F : FnMut(Self::State) -> Step<Self::Input, Self::State, E>, |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
193 | E : Error { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
194 | self.prestep().map_or(Step::Terminated, |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
195 | |state| self.poststep(step_fn(state))) |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
196 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
197 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
198 | /// Initial stage of advancing the iterator, before the actual step |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
199 | fn prestep(&mut self) -> Option<Self::State>; |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
200 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
201 | /// Handle step result |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
202 | fn poststep<E>(&mut self, result : Step<Self::Input, Self::State, E>) |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
203 | -> Step<Self::Output, Self::State, E> |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
204 | where E : Error; |
0 | 205 | |
206 | /// Return current iteration count. | |
207 | fn iteration(&self) -> usize { | |
208 | self.state().iteration() | |
209 | } | |
210 | ||
5 | 211 | /// Return current state. |
0 | 212 | fn state(&self) -> Self::State; |
213 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
214 | /// Iterate the `AlgIterator` until termination, erforming `step_fn` on each step. |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
215 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
216 | /// Returns either `()` or an error if the step closure terminated in [`Step::Failure´]. |
0 | 217 | #[inline] |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
218 | fn iterate<F, E>(&mut self, mut step_fn : F) -> Result<(), E> |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
219 | where F : FnMut(Self::State) -> Step<Self::Input, Self::State, E>, |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
220 | E : Error { |
0 | 221 | loop { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
222 | match self.step(&mut step_fn) { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
223 | Step::Terminated => return Ok(()), |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
224 | Step::Failure(e) => return Err(e), |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
225 | _ => {}, |
0 | 226 | } |
227 | } | |
228 | } | |
229 | } | |
230 | ||
5 | 231 | /// A factory for producing an [`AlgIterator`]. |
0 | 232 | /// |
5 | 233 | /// For usage instructions see the [module documentation][self]. |
0 | 234 | pub trait AlgIteratorFactory<V> : Sized { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
235 | type Iter : AlgIterator<State = Self::State, Input = V, Output = Self::Output>; |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
236 | |
5 | 237 | /// The state type of the corresponding [`AlgIterator`]. |
238 | /// A reference to this is passed to the closures passed to methods such as [`Self::iterate`]. | |
0 | 239 | type State : AlgIteratorState; |
5 | 240 | /// The output type of the corresponding [`AlgIterator`]. |
241 | /// This is the output of the closures passed to methods such as [`Self::iterate`] after | |
242 | /// mappings performed by each [`AlgIterator`] implementation. | |
0 | 243 | type Output; |
244 | ||
245 | /// Prepare an [`AlgIterator`], consuming the factory. | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
246 | fn prepare(self) -> Self::Iter; |
0 | 247 | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
248 | /// Iterate the the closure `step`. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
249 | /// |
5 | 250 | /// The closure should accept a `state` parameter (satisfying the trait [`AlgIteratorState`]). |
251 | /// It should return the output of | |
252 | /// `state.`[`if_verbose`][AlgIteratorState::if_verbose], [`Step::Terminated`] to indicate | |
253 | /// completion for other reason, or [`Step::Failure`] for termination for failure. | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
254 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
255 | /// This method is equivalent to [`Self::prepare`] followed by [`AlgIterator::iterate`]. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
256 | #[inline] |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
257 | fn iterate_fallible<F, E>(self, step : F) -> Result<(), E> |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
258 | where F : FnMut(Self::State) -> Step<V, Self::State, E>, |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
259 | E : Error { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
260 | self.prepare().iterate(step) |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
261 | } |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
262 | |
46 | 263 | /// Iterate the closure `step`. |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
264 | /// |
5 | 265 | /// The closure should accept a `state` parameter (satisfying the trait [`AlgIteratorState`]), |
266 | /// It should return the output of | |
267 | /// `state.`[`if_verbose`][AlgIteratorState::if_verbose]. | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
268 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
269 | /// For usage instructions see the [module documentation][self]. |
0 | 270 | /// |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
271 | /// This method is equivalent to [`Self::prepare`] followed by [`AlgIterator::iterate`] |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
272 | /// with the error type `E=`[`std::convert::Infallible`]. |
0 | 273 | #[inline] |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
274 | fn iterate<F>(self, step : F) |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
275 | where F : FnMut(Self::State) -> Step<V, Self::State> { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
276 | self.iterate_fallible(step).unwrap_or_default() |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
277 | } |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
278 | |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
279 | /// Iterate the closure `step` with data produced by `datasource`. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
280 | /// |
5 | 281 | /// The closure should accept a `state` parameter (satisfying the trait [`AlgIteratorState`]), |
282 | /// and a data parameter taken from `datasource`. It should return the output of | |
283 | /// `state.`[`if_verbose`][AlgIteratorState::if_verbose], [`Step::Terminated`] to indicate | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
284 | /// completion for other reason, or [`Step::Failure`] for termination for failure. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
285 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
286 | /// If the `datasource` runs out of data, the iterator is considered having terminated |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
287 | /// successsfully. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
288 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
289 | /// For usage instructions see the [module documentation][self]. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
290 | #[inline] |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
291 | fn iterate_data_fallible<F, D, I, E>(self, mut datasource : I, mut step : F) |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
292 | -> Result<(), E> |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
293 | where F : FnMut(Self::State, D) -> Step<V, Self::State, E>, |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
294 | I : Iterator<Item = D>, |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
295 | E : Error { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
296 | self.prepare().iterate(move |state| { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
297 | datasource.next().map_or(Step::Terminated, |d| step(state, d)) |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
298 | }) |
0 | 299 | } |
300 | ||
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
301 | /// Iterate the closure `step` with data produced by `datasource`. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
302 | /// |
5 | 303 | /// The closure should accept a `state` parameter (satisfying the trait [`AlgIteratorState`]), |
304 | /// and a data parameter taken from `datasource`. It should return the output of | |
305 | /// `state.`[`if_verbose`][AlgIteratorState::if_verbose]. | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
306 | /// |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
307 | /// If the `datasource` runs out of data, the iterator is considered having terminated |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
308 | /// successsfully. |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
309 | /// |
0 | 310 | /// For usage instructions see the [module documentation][self]. |
311 | #[inline] | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
312 | fn iterate_data<F, D, I>(self, datasource : I, step : F) |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
313 | where F : FnMut(Self::State, D) -> Step<V, Self::State>, |
0 | 314 | I : Iterator<Item = D> { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
315 | self.iterate_data_fallible(datasource, step).unwrap_or_default() |
0 | 316 | } |
317 | ||
318 | // fn make_iterate<'own>(self) | |
319 | // -> Box<dyn (FnMut(dyn FnMut(&Self::State) -> Option<V>) -> ()) + 'own> { | |
320 | // Box::new(move |step| self.iterate(step)) | |
321 | // } | |
322 | ||
323 | // fn make_iterate_data<'own, D, I>(self, datasource : I) | |
324 | // -> Box<dyn (FnMut(dyn FnMut(&Self::State, D) -> Option<V>) -> ()) + 'own> | |
325 | // where I : Iterator<Item = D> + 'own { | |
326 | // Box::new(move |step| self.iterate_data(step, datasource)) | |
327 | // } | |
328 | ||
329 | /// Add logging to the iterator produced by the factory. | |
5 | 330 | /// |
331 | /// Returns a new factory whose corresponding [`AlgIterator`] only inserts that data into the | |
332 | /// log without passing it onwards. | |
333 | /// | |
334 | /// Use as: | |
335 | /// ```rust | |
336 | /// # use alg_tools::iterate::*; | |
337 | /// # use alg_tools::logger::*; | |
338 | /// let iter = AlgIteratorOptions::default(); | |
339 | /// let mut log = Logger::new(); | |
340 | /// iter.into_log(&mut log).iterate(|state|{ | |
341 | /// // perform iterations | |
342 | /// state.if_verbose(||{ | |
343 | /// // calculate and return function value or other displayed data v | |
344 | /// return 0 | |
345 | /// }) | |
346 | /// }) | |
347 | /// ``` | |
0 | 348 | fn into_log<'log>(self, logger : &'log mut Logger<Self::Output>) |
349 | -> LoggingIteratorFactory<'log, Self::Output, Self> | |
350 | where Self : Sized { | |
351 | LoggingIteratorFactory { | |
352 | base_options : self, | |
353 | logger, | |
354 | } | |
355 | } | |
356 | ||
357 | /// Map the output of the iterator produced by the factory. | |
5 | 358 | /// |
359 | /// Returns a new factory. | |
0 | 360 | fn mapped<U, G>(self, map : G) |
361 | -> MappingIteratorFactory<G, Self> | |
362 | where Self : Sized, | |
363 | G : Fn(usize, Self::Output) -> U { | |
364 | MappingIteratorFactory { | |
365 | base_options : self, | |
366 | map | |
367 | } | |
368 | } | |
369 | ||
5 | 370 | /// Adds iteration number to the output. |
371 | /// | |
372 | /// Returns a new factory. | |
373 | /// Typically followed by [`Self::into_log`]. | |
0 | 374 | fn with_iteration_number(self) |
375 | -> MappingIteratorFactory<fn(usize, Self::Output) -> LogItem<Self::Output>, Self> | |
376 | where Self : Sized { | |
5 | 377 | self.mapped(LogItem::new) |
0 | 378 | } |
379 | ||
380 | /// Add timing to the iterator produced by the factory. | |
381 | fn timed(self) -> TimingIteratorFactory<Self> | |
382 | where Self : Sized { | |
383 | TimingIteratorFactory(self) | |
384 | } | |
385 | ||
386 | /// Add value stopping threshold to the iterator produce by the factory | |
387 | fn stop_target(self, target : Self::Output) -> ValueIteratorFactory<Self::Output, Self> | |
388 | where Self : Sized, | |
389 | Self::Output : Num { | |
390 | ValueIteratorFactory { base_options : self, target : target } | |
391 | } | |
392 | ||
393 | /// Add stall stopping to the iterator produce by the factory | |
394 | fn stop_stall(self, stall : Self::Output) -> StallIteratorFactory<Self::Output, Self> | |
395 | where Self : Sized, | |
396 | Self::Output : Num { | |
397 | StallIteratorFactory { base_options : self, stall : stall } | |
398 | } | |
399 | ||
400 | /// Is the iterator quiet, i.e., on-verbose? | |
401 | fn is_quiet(&self) -> bool { false } | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
402 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
403 | /// Returns an an [`std::iter::Iterator`] that can be used in a `for`-loop. |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
404 | fn iter(self) -> AlgIteratorIterator<Self::Iter> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
405 | AlgIteratorIterator { |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
406 | algi : Rc::new(RefCell::new(self.prepare())), |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
407 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
408 | } |
46 | 409 | |
410 | /// Returns an an [`std::iter::Iterator`] that can be used in a `for`-loop, | |
411 | /// also inputting an initial iteration status calculated by `f` if needed. | |
412 | fn iter_init(self, f : impl FnOnce() -> <Self::Iter as AlgIterator>::Input) | |
413 | -> AlgIteratorIterator<Self::Iter> { | |
414 | let mut i = self.prepare(); | |
415 | let st = i.state(); | |
416 | let step : Step<<Self::Iter as AlgIterator>::Input, Self::State> = st.if_verbose(f); | |
417 | i.poststep(step); | |
418 | AlgIteratorIterator { | |
419 | algi : Rc::new(RefCell::new(i)), | |
420 | } | |
421 | } | |
0 | 422 | } |
423 | ||
5 | 424 | /// Options for [`BasicAlgIteratorFactory`]. |
425 | /// | |
426 | /// Use as: | |
0 | 427 | /// ``` |
428 | /// # use alg_tools::iterate::*; | |
429 | /// let iter = AlgIteratorOptions{ max_iter : 10000, .. Default::default() }; | |
430 | /// ``` | |
431 | #[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq)] | |
432 | pub struct AlgIteratorOptions { | |
433 | /// Maximum number of iterations | |
434 | pub max_iter : usize, | |
435 | /// Number of iterations between verbose iterations that display state. | |
436 | pub verbose_iter : Verbose, | |
437 | /// Whether verbose iterations are displayed, or just passed onwards to a containing | |
438 | /// `AlgIterator`. | |
439 | pub quiet : bool, | |
440 | } | |
441 | ||
442 | #[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq)] | |
443 | pub enum Verbose { | |
444 | /// Be verbose every $n$ iterations. | |
445 | Every(usize), | |
446 | /// Be verbose every $n$ iterations and initial $m$ iterations. | |
447 | EveryAndInitial{ every : usize, initial : usize }, | |
448 | /// Be verbose if iteration number $n$ divides by $b^{\text{floor}(\log_b(n))}$, where | |
449 | /// $b$ is indicated logarithmic base. So, with $b=10$, | |
450 | /// * every iteration for first 10 iterations, | |
451 | /// * every 10 iterations from there on until 100 iterations, | |
452 | /// * every 100 iteartinos frmo there on until 1000 iterations, etc. | |
453 | Logarithmic(usize), | |
87
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
454 | /// Same as `Logarithmic`, but $\log_b(n)$ is replaced by $min\{c, \log_b(n)\}$ where $c$ |
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
455 | /// is the given `cap`. For example, with `base=10` and `cap=2`, the first ten iterations |
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
456 | /// will be output, then every tenth iteration, and after 100 iterations, every 100th iteration, |
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
457 | /// without further logarithmic progression. |
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
458 | LogarithmicCap{ base : usize, cap : u32 }, |
0 | 459 | } |
460 | ||
461 | impl Verbose { | |
462 | /// Indicates whether given iteration number is verbose | |
463 | pub fn is_verbose(&self, iter : usize) -> bool { | |
464 | match self { | |
465 | &Verbose::Every(every) => { | |
466 | every != 0 && iter % every == 0 | |
467 | }, | |
468 | &Verbose::EveryAndInitial{ every, initial } => { | |
469 | iter <= initial || (every != 0 && iter % every == 0) | |
470 | }, | |
471 | &Verbose::Logarithmic(base) => { | |
25
d14c877e14b7
Logarithmic logging base correction
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
472 | let every = base.pow((iter as float).log(base as float).floor() as u32); |
0 | 473 | iter % every == 0 |
474 | } | |
87
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
475 | &Verbose::LogarithmicCap{base, cap} => { |
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
476 | let every = base.pow(((iter as float).log(base as float).floor() as u32).min(cap)); |
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
477 | iter % every == 0 |
72968cf30033
LogarithmicCap verbosity option
Tuomo Valkonen <tuomov@iki.fi>
parents:
51
diff
changeset
|
478 | } |
0 | 479 | } |
480 | } | |
481 | } | |
482 | ||
483 | impl Default for AlgIteratorOptions { | |
484 | fn default() -> AlgIteratorOptions { | |
485 | AlgIteratorOptions{ | |
486 | max_iter : 1000, | |
487 | verbose_iter : Verbose::EveryAndInitial { every : 100, initial : 10 }, | |
488 | quiet : false | |
489 | } | |
490 | } | |
491 | } | |
492 | ||
493 | /// State of a `BasicAlgIterator` | |
494 | #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] | |
495 | pub struct BasicState { | |
5 | 496 | /// Current iteration |
0 | 497 | iter : usize, |
5 | 498 | /// Whether the iteration is verbose, i.e., results should be displayed. |
499 | /// Requires `calc` to be `true`. | |
0 | 500 | verbose : bool, |
5 | 501 | /// Whether results should be calculated. |
0 | 502 | calc : bool, |
31
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
503 | /// Indicates whether the iteration is quiet |
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
504 | quiet : bool, |
0 | 505 | } |
506 | ||
507 | /// [`AlgIteratorFactory`] for [`BasicAlgIterator`] | |
508 | #[derive(Clone,Debug)] | |
509 | pub struct BasicAlgIteratorFactory<V> { | |
510 | options : AlgIteratorOptions, | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
511 | _phantoms : PhantomData<V>, |
0 | 512 | } |
513 | ||
5 | 514 | /// The simplest [`AlgIterator`], created by [`BasicAlgIteratorFactory`] |
0 | 515 | #[derive(Clone,Debug)] |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
516 | pub struct BasicAlgIterator<V> { |
0 | 517 | options : AlgIteratorOptions, |
518 | iter : usize, | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
519 | _phantoms : PhantomData<V>, |
0 | 520 | } |
521 | ||
522 | impl AlgIteratorOptions { | |
523 | /// [`AlgIteratorOptions`] is directly a factory for [`BasicAlgIterator`], | |
524 | /// however, due to type inference issues, it may become convenient to instantiate | |
525 | /// it to a specific return type for the inner step function. This method does that. | |
526 | pub fn instantiate<V>(&self) -> BasicAlgIteratorFactory<V> { | |
527 | BasicAlgIteratorFactory { | |
528 | options : self.clone(), | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
529 | _phantoms : PhantomData |
0 | 530 | } |
531 | } | |
532 | } | |
533 | ||
534 | impl<V> AlgIteratorFactory<V> for AlgIteratorOptions | |
535 | where V : LogRepr { | |
536 | type State = BasicState; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
537 | type Iter = BasicAlgIterator<V>; |
0 | 538 | type Output = V; |
539 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
540 | fn prepare(self) -> Self::Iter { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
541 | BasicAlgIterator{ |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
542 | options : self, |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
543 | iter : 0, |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
544 | _phantoms : PhantomData, |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
545 | } |
0 | 546 | } |
547 | ||
548 | #[inline] | |
549 | fn is_quiet(&self) -> bool { | |
550 | self.quiet | |
551 | } | |
552 | } | |
553 | ||
554 | impl<V> AlgIteratorFactory<V> for BasicAlgIteratorFactory<V> | |
555 | where V : LogRepr { | |
556 | type State = BasicState; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
557 | type Iter = BasicAlgIterator<V>; |
0 | 558 | type Output = V; |
559 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
560 | fn prepare(self) -> Self::Iter { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
561 | BasicAlgIterator { |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
562 | options : self.options, |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
563 | iter : 0, |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
564 | _phantoms : PhantomData |
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
565 | } |
0 | 566 | } |
567 | ||
568 | #[inline] | |
569 | fn is_quiet(&self) -> bool { | |
570 | self.options.quiet | |
571 | } | |
572 | } | |
573 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
574 | impl<V> AlgIterator for BasicAlgIterator<V> |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
575 | where V : LogRepr { |
0 | 576 | type State = BasicState; |
577 | type Output = V; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
578 | type Input = V; |
0 | 579 | |
580 | #[inline] | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
581 | fn prestep(&mut self) -> Option<Self::State> { |
0 | 582 | if self.iter >= self.options.max_iter { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
583 | None |
0 | 584 | } else { |
585 | self.iter += 1; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
586 | Some(self.state()) |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
587 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
588 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
589 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
590 | fn poststep<E : Error>(&mut self, res : Step<V, Self::State, E>) -> Step<V, Self::State, E> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
591 | if let Step::Result(ref val, ref state) = res { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
592 | if state.verbose && !self.options.quiet { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
593 | println!("{}{}/{} {}{}", "".dimmed(), |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
594 | state.iter, |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
595 | self.options.max_iter, |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
596 | val.logrepr(), |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
597 | "".clear()); |
0 | 598 | } |
599 | } | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
600 | res |
0 | 601 | } |
602 | ||
603 | #[inline] | |
604 | fn iteration(&self) -> usize { | |
605 | self.iter | |
606 | } | |
607 | ||
608 | #[inline] | |
609 | fn state(&self) -> BasicState { | |
610 | let iter = self.iter; | |
611 | let verbose = self.options.verbose_iter.is_verbose(iter); | |
31
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
612 | BasicState { |
0 | 613 | iter : iter, |
614 | verbose : verbose, | |
615 | calc : verbose, | |
31
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
616 | quiet : self.options.quiet |
0 | 617 | } |
618 | } | |
619 | } | |
620 | ||
621 | impl AlgIteratorState for BasicState { | |
622 | #[inline] | |
46 | 623 | fn if_verbose<V, E : Error>(self, calc_objective : impl FnOnce() -> V) -> Step<V, Self, E> { |
0 | 624 | if self.calc { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
625 | Step::Result(calc_objective(), self) |
0 | 626 | } else { |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
627 | Step::Quiet |
0 | 628 | } |
629 | } | |
630 | ||
631 | #[inline] | |
632 | fn iteration(&self) -> usize { | |
31
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
633 | self.iter |
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
634 | } |
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
635 | |
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
636 | #[inline] |
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
637 | fn is_quiet(&self) -> bool { |
50a77e4efcbb
Add is_quiet to AlgIteratorState as well.
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
638 | self.quiet |
0 | 639 | } |
640 | } | |
641 | ||
642 | // | |
643 | // Stall detecting iteration function. | |
644 | // | |
645 | ||
5 | 646 | /// An [`AlgIteratorFactory`] for an [`AlgIterator`] that detects “stall”. |
647 | /// | |
648 | /// We define stall as $(v_{k+n}-v_k)/v_k ≤ θ$, where $n$ the distance between | |
649 | /// [`Step::Result`] iterations, and $θ$ is the provided `stall` parameter. | |
0 | 650 | #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] |
651 | pub struct StallIteratorFactory<U : Num, BaseFactory> { | |
5 | 652 | /// An [`AlgIteratorFactory`] on which to build on |
0 | 653 | pub base_options : BaseFactory, |
654 | /// Stalling threshold $θ$. | |
655 | pub stall : U, | |
656 | } | |
657 | ||
658 | /// Iterator produced by [`StallIteratorFactory`]. | |
659 | pub struct StallIterator<U : Num, BaseIterator> { | |
660 | base_iterator : BaseIterator, | |
661 | stall : U, | |
662 | previous_value : Option<U>, | |
663 | } | |
664 | ||
665 | impl<V, U, BaseFactory> AlgIteratorFactory<V> | |
666 | for StallIteratorFactory<U, BaseFactory> | |
667 | where BaseFactory : AlgIteratorFactory<V, Output=U>, | |
668 | U : SignedNum + PartialOrd { | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
669 | type Iter = StallIterator<U, BaseFactory::Iter>; |
0 | 670 | type State = BaseFactory::State; |
671 | type Output = BaseFactory::Output; | |
672 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
673 | fn prepare(self) -> Self::Iter { |
0 | 674 | StallIterator { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
675 | base_iterator : self.base_options.prepare(), |
0 | 676 | stall : self.stall, |
677 | previous_value : None, | |
678 | } | |
679 | } | |
680 | ||
681 | fn is_quiet(&self) -> bool { | |
682 | self.base_options.is_quiet() | |
683 | } | |
684 | } | |
685 | ||
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
686 | impl<U, BaseIterator> AlgIterator |
0 | 687 | for StallIterator<U, BaseIterator> |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
688 | where BaseIterator : AlgIterator<Output=U>, |
0 | 689 | U : SignedNum + PartialOrd { |
690 | type State = BaseIterator::State; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
691 | type Output = U; |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
692 | type Input = BaseIterator::Input; |
0 | 693 | |
694 | #[inline] | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
695 | fn prestep(&mut self) -> Option<Self::State> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
696 | self.base_iterator.prestep() |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
697 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
698 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
699 | #[inline] |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
700 | fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<U, Self::State, E> |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
701 | where E : Error { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
702 | match self.base_iterator.poststep(res) { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
703 | Step::Result(nv, state) => { |
0 | 704 | let previous_v = self.previous_value; |
705 | self.previous_value = Some(nv); | |
706 | match previous_v { | |
707 | Some(pv) if (nv - pv).abs() <= self.stall * pv.abs() => Step::Terminated, | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
708 | _ => Step::Result(nv, state), |
0 | 709 | } |
710 | }, | |
711 | val => val, | |
712 | } | |
713 | } | |
714 | ||
715 | #[inline] | |
716 | fn iteration(&self) -> usize { | |
717 | self.base_iterator.iteration() | |
718 | } | |
719 | ||
720 | #[inline] | |
721 | fn state(&self) -> Self::State { | |
722 | self.base_iterator.state() | |
723 | } | |
724 | } | |
725 | ||
726 | /// An [`AlgIteratorFactory`] for an [`AlgIterator`] that detect whether step function | |
727 | /// return value is less than `target`, and terminates if it is. | |
728 | #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] | |
729 | pub struct ValueIteratorFactory<U : Num, BaseFactory> { | |
5 | 730 | /// An [`AlgIteratorFactory`] on which to build on |
0 | 731 | pub base_options : BaseFactory, |
5 | 732 | /// Target value |
0 | 733 | pub target : U, |
734 | } | |
735 | ||
736 | /// Iterator produced by [`ValueIteratorFactory`]. | |
737 | pub struct ValueIterator<U : Num, BaseIterator> { | |
738 | base_iterator : BaseIterator, | |
739 | target : U, | |
740 | } | |
741 | ||
742 | impl<V, U, BaseFactory> AlgIteratorFactory<V> | |
743 | for ValueIteratorFactory<U, BaseFactory> | |
744 | where BaseFactory : AlgIteratorFactory<V, Output=U>, | |
745 | U : SignedNum + PartialOrd { | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
746 | type Iter = ValueIterator<U, BaseFactory::Iter>; |
0 | 747 | type State = BaseFactory::State; |
748 | type Output = BaseFactory::Output; | |
749 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
750 | fn prepare(self) -> Self::Iter { |
0 | 751 | ValueIterator { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
752 | base_iterator : self.base_options.prepare(), |
0 | 753 | target : self.target |
754 | } | |
755 | } | |
756 | ||
757 | fn is_quiet(&self) -> bool { | |
758 | self.base_options.is_quiet() | |
759 | } | |
760 | } | |
761 | ||
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
762 | impl<U, BaseIterator> AlgIterator |
0 | 763 | for ValueIterator<U, BaseIterator> |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
764 | where BaseIterator : AlgIterator<Output=U>, |
0 | 765 | U : SignedNum + PartialOrd { |
766 | type State = BaseIterator::State; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
767 | type Output = U; |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
768 | type Input = BaseIterator::Input; |
0 | 769 | |
770 | #[inline] | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
771 | fn prestep(&mut self) -> Option<Self::State> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
772 | self.base_iterator.prestep() |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
773 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
774 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
775 | #[inline] |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
776 | fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<U, Self::State, E> where E : Error{ |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
777 | match self.base_iterator.poststep(res) { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
778 | Step::Result(v, state) => { |
0 | 779 | if v <= self.target { |
780 | Step::Terminated | |
781 | } else { | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
782 | Step::Result(v, state) |
0 | 783 | } |
784 | }, | |
785 | val => val, | |
786 | } | |
787 | } | |
788 | ||
789 | #[inline] | |
790 | fn iteration(&self) -> usize { | |
791 | self.base_iterator.iteration() | |
792 | } | |
793 | ||
794 | #[inline] | |
795 | fn state(&self) -> Self::State { | |
796 | self.base_iterator.state() | |
797 | } | |
798 | } | |
799 | ||
800 | // | |
801 | // Logging iterator | |
802 | // | |
803 | ||
804 | /// [`AlgIteratorFactory`] for a logging [`AlgIterator`]. | |
5 | 805 | /// |
806 | /// Typically produced with [`AlgIteratorFactory::into_log`]. | |
0 | 807 | /// The `Output` of the corresponding [`LoggingIterator`] is `()`: |
808 | #[derive(Debug)] | |
809 | pub struct LoggingIteratorFactory<'log, U, BaseFactory> { | |
5 | 810 | /// Base [`AlgIteratorFactory`] on which to build |
811 | base_options : BaseFactory, | |
812 | /// The `Logger` to use. | |
813 | logger : &'log mut Logger<U>, | |
0 | 814 | } |
815 | ||
816 | /// Iterator produced by `LoggingIteratorFactory`. | |
817 | pub struct LoggingIterator<'log, U, BaseIterator> { | |
818 | base_iterator : BaseIterator, | |
819 | logger : &'log mut Logger<U>, | |
820 | } | |
821 | ||
822 | ||
823 | impl<'log, V, BaseFactory> AlgIteratorFactory<V> | |
824 | for LoggingIteratorFactory<'log, BaseFactory::Output, BaseFactory> | |
825 | where BaseFactory : AlgIteratorFactory<V>, | |
826 | BaseFactory::Output : 'log { | |
827 | type State = BaseFactory::State; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
828 | type Iter = LoggingIterator<'log, BaseFactory::Output, BaseFactory::Iter>; |
0 | 829 | type Output = (); |
830 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
831 | fn prepare(self) -> Self::Iter { |
0 | 832 | LoggingIterator { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
833 | base_iterator : self.base_options.prepare(), |
0 | 834 | logger : self.logger, |
835 | } | |
836 | } | |
837 | ||
838 | #[inline] | |
839 | fn is_quiet(&self) -> bool { | |
840 | self.base_options.is_quiet() | |
841 | } | |
842 | } | |
843 | ||
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
844 | impl<'log, BaseIterator> AlgIterator |
0 | 845 | for LoggingIterator<'log, BaseIterator::Output, BaseIterator> |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
846 | where BaseIterator : AlgIterator, |
0 | 847 | BaseIterator::Output : 'log { |
848 | type State = BaseIterator::State; | |
849 | type Output = (); | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
850 | type Input = BaseIterator::Input; |
0 | 851 | |
852 | #[inline] | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
853 | fn prestep(&mut self) -> Option<Self::State> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
854 | self.base_iterator.prestep() |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
855 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
856 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
857 | #[inline] |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
858 | fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<(), Self::State, E> where E : Error { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
859 | match self.base_iterator.poststep(res) { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
860 | Step::Result(v, _) => { |
0 | 861 | self.logger.log(v); |
862 | Step::Quiet | |
863 | }, | |
864 | Step::Quiet => Step::Quiet, | |
865 | Step::Terminated => Step::Terminated, | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
866 | Step::Failure(e) => Step::Failure(e), |
0 | 867 | } |
868 | } | |
869 | ||
870 | #[inline] | |
871 | fn iteration(&self) -> usize { | |
872 | self.base_iterator.iteration() | |
873 | } | |
874 | ||
875 | #[inline] | |
876 | fn state(&self) -> Self::State { | |
877 | self.base_iterator.state() | |
878 | } | |
879 | } | |
880 | ||
881 | /// This [`AlgIteratorFactory`] allows output mapping. | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
882 | /// |
5 | 883 | /// Typically produced with [`AlgIteratorFactory::mapped`]. |
0 | 884 | #[derive(Debug)] |
885 | pub struct MappingIteratorFactory<G, BaseFactory> { | |
5 | 886 | /// Base [`AlgIteratorFactory`] on which to build |
887 | base_options : BaseFactory, | |
888 | /// A closure `G : Fn(usize, BaseFactory::Output) -> U` that gets the current iteration | |
889 | /// and the output of the base factory as input, and produces a new output. | |
890 | map : G, | |
0 | 891 | } |
892 | ||
5 | 893 | /// [`AlgIterator`] produced by [`MappingIteratorFactory`]. |
0 | 894 | pub struct MappingIterator<G, BaseIterator> { |
895 | base_iterator : BaseIterator, | |
896 | map : G, | |
897 | } | |
898 | ||
899 | ||
900 | impl<V, U, G, BaseFactory> AlgIteratorFactory<V> | |
901 | for MappingIteratorFactory<G, BaseFactory> | |
902 | where BaseFactory : AlgIteratorFactory<V>, | |
903 | G : Fn(usize, BaseFactory::Output) -> U { | |
904 | type State = BaseFactory::State; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
905 | type Iter = MappingIterator<G, BaseFactory::Iter>; |
0 | 906 | type Output = U; |
907 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
908 | fn prepare(self) -> Self::Iter { |
0 | 909 | MappingIterator { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
910 | base_iterator : self.base_options.prepare(), |
0 | 911 | map : self.map |
912 | } | |
913 | } | |
914 | ||
915 | #[inline] | |
916 | fn is_quiet(&self) -> bool { | |
917 | self.base_options.is_quiet() | |
918 | } | |
919 | } | |
920 | ||
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
921 | impl<U, G, BaseIterator> AlgIterator |
0 | 922 | for MappingIterator<G, BaseIterator> |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
923 | where BaseIterator : AlgIterator, |
0 | 924 | G : Fn(usize, BaseIterator::Output) -> U { |
925 | type State = BaseIterator::State; | |
926 | type Output = U; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
927 | type Input = BaseIterator::Input; |
0 | 928 | |
929 | #[inline] | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
930 | fn prestep(&mut self) -> Option<Self::State> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
931 | self.base_iterator.prestep() |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
932 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
933 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
934 | #[inline] |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
935 | fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<Self::Output, Self::State, E> where E : Error { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
936 | match self.base_iterator.poststep(res) { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
937 | Step::Result(v, state) => Step::Result((self.map)(self.iteration(), v), state), |
0 | 938 | Step::Quiet => Step::Quiet, |
939 | Step::Terminated => Step::Terminated, | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
940 | Step::Failure(e) => Step::Failure(e), |
0 | 941 | } |
942 | } | |
943 | ||
944 | #[inline] | |
945 | fn iteration(&self) -> usize { | |
946 | self.base_iterator.iteration() | |
947 | } | |
948 | ||
949 | #[inline] | |
950 | fn state(&self) -> Self::State { | |
951 | self.base_iterator.state() | |
952 | } | |
953 | } | |
954 | ||
955 | // | |
956 | // Timing iterator | |
957 | // | |
958 | ||
5 | 959 | /// An [`AlgIteratorFactory`] for an [`AlgIterator`] that adds spent CPU time to verbose events. |
0 | 960 | #[derive(Debug)] |
961 | pub struct TimingIteratorFactory<BaseFactory>(pub BaseFactory); | |
962 | ||
963 | /// Iterator produced by [`TimingIteratorFactory`] | |
964 | #[derive(Debug)] | |
965 | pub struct TimingIterator<BaseIterator> { | |
966 | base_iterator : BaseIterator, | |
967 | start_time : ProcessTime, | |
968 | } | |
969 | ||
970 | /// Data `U` with production time attached | |
971 | #[derive(Copy, Clone, Debug, Serialize)] | |
972 | pub struct Timed<U> { | |
51 | 973 | /// CPU time taken |
0 | 974 | pub cpu_time : Duration, |
51 | 975 | /// Iteration number |
976 | pub iter : usize, | |
977 | /// User data | |
0 | 978 | //#[serde(flatten)] |
979 | pub data : U | |
980 | } | |
981 | ||
982 | impl<T> LogRepr for Timed<T> where T : LogRepr { | |
983 | fn logrepr(&self) -> ColoredString { | |
984 | format!("[{:.3}s] {}", self.cpu_time.as_secs_f64(), self.data.logrepr()).as_str().into() | |
985 | } | |
986 | } | |
987 | ||
988 | ||
989 | impl<V, BaseFactory> AlgIteratorFactory<V> | |
990 | for TimingIteratorFactory<BaseFactory> | |
991 | where BaseFactory : AlgIteratorFactory<V> { | |
992 | type State = BaseFactory::State; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
993 | type Iter = TimingIterator<BaseFactory::Iter>; |
0 | 994 | type Output = Timed<BaseFactory::Output>; |
995 | ||
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
996 | fn prepare(self) -> Self::Iter { |
0 | 997 | TimingIterator { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
998 | base_iterator : self.0.prepare(), |
0 | 999 | start_time : ProcessTime::now() |
1000 | } | |
1001 | } | |
1002 | ||
1003 | #[inline] | |
1004 | fn is_quiet(&self) -> bool { | |
1005 | self.0.is_quiet() | |
1006 | } | |
1007 | } | |
1008 | ||
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
1009 | impl<BaseIterator> AlgIterator |
0 | 1010 | for TimingIterator<BaseIterator> |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
1011 | where BaseIterator : AlgIterator { |
0 | 1012 | type State = BaseIterator::State; |
1013 | type Output = Timed<BaseIterator::Output>; | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1014 | type Input = BaseIterator::Input; |
0 | 1015 | |
1016 | #[inline] | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1017 | fn prestep(&mut self) -> Option<Self::State> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1018 | self.base_iterator.prestep() |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1019 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1020 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1021 | #[inline] |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1022 | fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<Self::Output, Self::State, E> where E : Error { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1023 | match self.base_iterator.poststep(res) { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1024 | Step::Result(data, state) => { |
0 | 1025 | Step::Result(Timed{ |
1026 | cpu_time : self.start_time.elapsed(), | |
51 | 1027 | iter : self.iteration(), |
0 | 1028 | data |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1029 | }, state) |
0 | 1030 | }, |
1031 | Step::Quiet => Step::Quiet, | |
1032 | Step::Terminated => Step::Terminated, | |
3
20db884b7028
Allow step closure of AlgIterators to indicate succesfull termination or failure.
Tuomo Valkonen <tuomov@iki.fi>
parents:
1
diff
changeset
|
1033 | Step::Failure(e) => Step::Failure(e), |
0 | 1034 | } |
1035 | } | |
1036 | ||
1037 | #[inline] | |
1038 | fn iteration(&self) -> usize { | |
1039 | self.base_iterator.iteration() | |
1040 | } | |
1041 | ||
1042 | #[inline] | |
1043 | fn state(&self) -> Self::State { | |
1044 | self.base_iterator.state() | |
1045 | } | |
1046 | } | |
1047 | ||
1048 | // | |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1049 | // New for-loop interface |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1050 | // |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1051 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1052 | pub struct AlgIteratorIterator<I : AlgIterator> { |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1053 | algi : Rc<RefCell<I>>, |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1054 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1055 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1056 | pub struct AlgIteratorIteration<I : AlgIterator> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1057 | state : I::State, |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1058 | algi : Rc<RefCell<I>>, |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1059 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1060 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1061 | impl<I : AlgIterator> std::iter::Iterator for AlgIteratorIterator<I> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1062 | type Item = AlgIteratorIteration<I>; |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1063 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1064 | fn next(&mut self) -> Option<Self::Item> { |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1065 | let algi = self.algi.clone(); |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1066 | RefCell::borrow_mut(&self.algi).prestep().map(|state| AlgIteratorIteration { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1067 | state, |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1068 | algi, |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1069 | }) |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1070 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1071 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1072 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1073 | /// Types of errors that may occur |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1074 | #[derive(Debug,PartialEq,Eq)] |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1075 | pub enum IterationError { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1076 | /// [`AlgIteratorIteration::if_verbose_check`] is not called in iteration order. |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1077 | ReportingOrderingError |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1078 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1079 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1080 | impl<I : AlgIterator> AlgIteratorIteration<I> { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1081 | /// Call `call_objective` if this is a verbose iteration. |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1082 | /// |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1083 | /// Verbosity depends on the [`AlgIterator`] that produced this state. |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1084 | /// |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1085 | /// The closure `calc_objective` should return an arbitrary value of type `V`, to be inserted |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1086 | /// into the log, or whatever is deemed by the [`AlgIterator`]. For usage instructions see the |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1087 | /// [module documentation][self]. |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1088 | /// |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1089 | /// This function may panic if result reporting is not ordered correctly (an unlikely mistake |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1090 | /// if using this facility correctly). For a version that propagates errors, see |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1091 | /// [`Self::if_verbose_check`]. |
46 | 1092 | pub fn if_verbose(self, calc_objective : impl FnOnce() -> I::Input) { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1093 | self.if_verbose_check(calc_objective).unwrap() |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1094 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1095 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1096 | /// Version of [`Self::if_verbose`] that propagates errors instead of panicking. |
46 | 1097 | pub fn if_verbose_check(self, calc_objective : impl FnOnce() -> I::Input) |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1098 | -> Result<(), IterationError> { |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1099 | let mut algi = match RefCell::try_borrow_mut(&self.algi) { |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1100 | Err(_) => return Err(IterationError::ReportingOrderingError), |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1101 | Ok(algi) => algi |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1102 | }; |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1103 | if self.state.iteration() != algi.iteration() { |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1104 | Err(IterationError::ReportingOrderingError) |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1105 | } else { |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1106 | let res : Step<I::Input, I::State, std::convert::Infallible> |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1107 | = self.state.if_verbose(calc_objective); |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1108 | algi.poststep(res); |
40
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1109 | Ok(()) |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1110 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1111 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1112 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1113 | /// Returns the current iteration count. |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1114 | pub fn iteration(&self) -> usize { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1115 | self.state.iteration() |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1116 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1117 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1118 | /// Indicates whether the iterator is quiet |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1119 | pub fn is_quiet(&self) -> bool { |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1120 | self.state.is_quiet() |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1121 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1122 | } |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1123 | |
daf0e3a70c79
New iteration interface, allowing for loops.
Tuomo Valkonen <tuomov@iki.fi>
parents:
38
diff
changeset
|
1124 | // |
0 | 1125 | // Tests |
1126 | // | |
1127 | ||
1128 | #[cfg(test)] | |
1129 | mod tests { | |
1130 | use super::*; | |
1131 | use crate::logger::Logger; | |
1132 | #[test] | |
1133 | fn iteration() { | |
1134 | let options = AlgIteratorOptions{ | |
1135 | max_iter : 10, | |
1136 | verbose_iter : Verbose::Every(3), | |
1137 | .. Default::default() | |
1138 | }; | |
1139 | ||
1140 | { | |
1141 | let mut start = 1 as int; | |
1142 | options.iterate(|state| { | |
1143 | start = start * 2; | |
1144 | state.if_verbose(|| start) | |
1145 | }); | |
1146 | assert_eq!(start, (2 as int).pow(10)); | |
1147 | } | |
1148 | ||
1149 | { | |
1150 | let mut start = 1 as int; | |
1151 | let mut log = Logger::new(); | |
1152 | let factory = options.instantiate() | |
1153 | .with_iteration_number() | |
1154 | .into_log(&mut log); | |
1155 | factory.iterate(|state| { | |
1156 | start = start * 2; | |
1157 | state.if_verbose(|| start) | |
1158 | }); | |
1159 | assert_eq!(start, (2 as int).pow(10)); | |
1160 | assert_eq!(log.data() | |
1161 | .iter() | |
1162 | .map(|LogItem{ data : v, iter : _ }| v.clone()) | |
1163 | .collect::<Vec<int>>(), | |
1
df3901ec2f5d
Fix some unit tests after fundamental changes that made them invalid
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
1164 | (1..10).map(|i| (2 as int).pow(i)) |
df3901ec2f5d
Fix some unit tests after fundamental changes that made them invalid
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
1165 | .skip(2) |
df3901ec2f5d
Fix some unit tests after fundamental changes that made them invalid
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
1166 | .step_by(3) |
0 | 1167 | .collect::<Vec<int>>()) |
1168 | } | |
1169 | } | |
41
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1170 | |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1171 | #[test] |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1172 | fn iteration_for_loop() { |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1173 | let options = AlgIteratorOptions{ |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1174 | max_iter : 10, |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1175 | verbose_iter : Verbose::Every(3), |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1176 | .. Default::default() |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1177 | }; |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1178 | |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1179 | { |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1180 | let mut start = 1 as int; |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1181 | for state in options.iter() { |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1182 | start = start * 2; |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1183 | state.if_verbose(|| start) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1184 | } |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1185 | assert_eq!(start, (2 as int).pow(10)); |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1186 | } |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1187 | |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1188 | { |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1189 | let mut start = 1 as int; |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1190 | let mut log = Logger::new(); |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1191 | let factory = options.instantiate() |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1192 | .with_iteration_number() |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1193 | .into_log(&mut log); |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1194 | for state in factory.iter() { |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1195 | start = start * 2; |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1196 | state.if_verbose(|| start) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1197 | } |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1198 | assert_eq!(start, (2 as int).pow(10)); |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1199 | assert_eq!(log.data() |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1200 | .iter() |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1201 | .map(|LogItem{ data : v, iter : _ }| v.clone()) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1202 | .collect::<Vec<int>>(), |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1203 | (1..10).map(|i| (2 as int).pow(i)) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1204 | .skip(2) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1205 | .step_by(3) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1206 | .collect::<Vec<int>>()) |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1207 | } |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1208 | } |
121cf065e9ed
Simplify iterate facility for-loop mechanism
Tuomo Valkonen <tuomov@iki.fi>
parents:
40
diff
changeset
|
1209 | |
0 | 1210 | } |