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