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