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