src/iterate.rs

changeset 90
b3c35d16affe
parent 87
72968cf30033
--- a/src/iterate.rs	Tue Feb 20 12:33:16 2024 -0500
+++ b/src/iterate.rs	Mon Feb 03 19:22:16 2025 -0500
@@ -19,6 +19,7 @@
     .. Default::default()
 };
 let mut x = 1 as float;
+# let mut iter_clone = iter.clone();
 iter.iterate(|state|{
     // This is our computational step
     x = x + x.sqrt();
@@ -26,7 +27,17 @@
         // return current value when requested
         return x
      })
-})
+});
+// or alternatively (avoiding problems with moves)
+# iter = iter_clone;
+for state in iter.iter() {
+    // This is our computational step
+    x = x + x.sqrt();
+    state.if_verbose(||{
+        // return current value when requested
+        return x
+    })
+}
 ```
 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.
 
@@ -52,6 +63,8 @@
 use std::marker::PhantomData;
 use std::time::Duration;
 use std::error::Error;
+use std::cell::RefCell;
+use std::rc::Rc;
 use crate::types::*;
 use crate::logger::*;
 
@@ -114,7 +127,7 @@
 ///
 /// This is the parameter obtained by the closure passed to [`AlgIterator::iterate`] or
 /// [`AlgIteratorFactory::iterate`].
-pub trait AlgIteratorState {
+pub trait AlgIteratorState : Sized {
     /// Call `call_objective` if this is a verbose iteration.
     ///
     /// Verbosity depends on the [`AlgIterator`] that produced this state.
@@ -122,15 +135,18 @@
     /// The closure `calc_objective` should return an arbitrary value of type `V`, to be inserted
     /// into the log, or whatever is deemed by the [`AlgIterator`]. For usage instructions see the
     /// [module documentation][self].
-    fn if_verbose<V, E : Error>(&self, calc_objective : impl FnMut() -> V) -> Step<V, E>;
+    fn if_verbose<V, E : Error>(self, calc_objective : impl FnOnce() -> V) -> Step<V, Self, E>;
 
     /// Returns the current iteration count.
     fn iteration(&self) -> usize;
+
+    /// Indicates whether the iterator is quiet
+    fn is_quiet(&self) -> bool;
 }
 
 /// Result of a step of an [`AlgIterator`]
 #[derive(Debug, Serialize)]
-pub enum Step<V, Fail : Error = std::convert::Infallible> {
+pub enum Step<V, S, Fail : Error = std::convert::Infallible> {
     /// Iteration should be terminated
     Terminated,
     /// Iteration should be terminated due to failure
@@ -138,14 +154,14 @@
     /// No result this iteration (due to verbosity settings)
     Quiet,
     /// Result of this iteration (due to verbosity settings)
-    Result(V),
+    Result(V, S),
 }
 
-impl<V, E : Error> Step<V, E> {
+impl<V, S, E : Error> Step<V, S, E> {
     /// Maps the value contained within the `Step`, if any, by the closure `f`.
-    pub fn map<U>(self, mut f : impl FnMut(V) -> U) -> Step<U, E> {
+    pub fn map<U>(self, mut f : impl FnMut(V) -> U) -> Step<U, S, E> {
         match self {
-            Step::Result(v) =>  Step::Result(f(v)),
+            Step::Result(v, s) =>  Step::Result(f(v), s),
             Step::Failure(e) => Step::Failure(e),
             Step::Quiet =>      Step::Quiet,
             Step::Terminated => Step::Terminated,
@@ -153,6 +169,12 @@
     }
 }
 
+impl<V, S, E : Error> Default for Step<V, S, E> {
+    fn default() -> Self {
+        Step::Quiet
+    }
+}
+
 /// An iterator for algorithms, produced by [`AlgIteratorFactory::prepare`].
 ///
 /// Typically not accessed directly, but transparently produced by an [`AlgIteratorFactory`].
@@ -160,13 +182,26 @@
 pub trait AlgIterator : Sized {
     /// The state type
     type State : AlgIteratorState;
-    /// The output type for [`Self::step`].
+    /// The output type for [`Self::poststep`] and [`Self::step`].
     type Output;
-    /// The error type for [`Self::step`] and [`Self::iterate`].
-    type Err : Error;
+    /// The input type for [`Self::poststep`].
+    type Input;
 
-    /// Advance the iterator.
-    fn step(&mut self) -> Step<Self::Output, Self::Err>;
+    /// Advance the iterator, performing `step_fn` with the state
+    fn step<F, E>(&mut self, step_fn : &mut F) -> Step<Self::Output, Self::State, E>
+    where F : FnMut(Self::State) -> Step<Self::Input, Self::State, E>,
+          E : Error {
+        self.prestep().map_or(Step::Terminated,
+                              |state| self.poststep(step_fn(state)))
+    }
+
+    /// Initial stage of advancing the iterator, before the actual step
+    fn prestep(&mut self) -> Option<Self::State>;
+
+    /// Handle step result
+    fn poststep<E>(&mut self, result : Step<Self::Input, Self::State, E>)
+    -> Step<Self::Output, Self::State, E>
+    where E : Error;
 
     /// Return current iteration count.
     fn iteration(&self) -> usize {
@@ -176,56 +211,29 @@
     /// Return current state.
     fn state(&self) -> Self::State;
 
-    /// Iterate the `AlgIterator` until termination.
+    /// Iterate the `AlgIterator` until termination, erforming `step_fn` on each step.
     ///
     /// Returns either `()` or an error if the step closure terminated in [`Step::FailureĀ“].
     #[inline]
-    fn iterate(&mut self) -> Result<(), Self::Err> {
+    fn iterate<F, E>(&mut self, mut step_fn : F) -> Result<(), E>
+    where F : FnMut(Self::State) -> Step<Self::Input, Self::State, E>,
+          E : Error {
         loop {
-            match self.step() {
+            match self.step(&mut step_fn) {
                 Step::Terminated => return Ok(()),
                 Step::Failure(e) => return Err(e),
                 _ => {},
             }
         }
     }
-
-    /// Converts the `AlgIterator` into a plain [`Iterator`].
-    ///
-    /// [`Step::Quiet`] results are discarded, and [`Step::Failure`] results **panic**.
-    fn downcast(self) -> AlgIteratorI<Self> {
-        AlgIteratorI(self)
-    }
-}
-
-/// Conversion of an `AlgIterator` into a plain [`Iterator`].
-///
-/// The conversion discards [`Step::Quiet`] and **panics** on [`Step::Failure`].
-pub struct AlgIteratorI<A>(A);
-
-impl<A> Iterator for AlgIteratorI<A>
-where A : AlgIterator {
-    type Item = A::Output;
-
-    fn next(&mut self) -> Option<A::Output> {
-        loop {
-            match self.0.step() {
-                Step::Result(v) => return Some(v),
-                Step::Failure(e) => panic!("{e:?}"),
-                Step::Terminated => return None,
-                Step::Quiet => continue,
-            }
-        }
-    }
 }
 
 /// A factory for producing an [`AlgIterator`].
 ///
 /// For usage instructions see the [module documentation][self].
 pub trait AlgIteratorFactory<V> : Sized {
-    type Iter<F, E> : AlgIterator<State = Self::State, Output = Self::Output, Err = E>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter : AlgIterator<State = Self::State, Input = V, Output = Self::Output>;
+
     /// The state type of the corresponding [`AlgIterator`].
     /// A reference to this is passed to the closures passed to methods such as [`Self::iterate`].
     type State : AlgIteratorState;
@@ -235,12 +243,7 @@
     type Output;
 
     /// Prepare an [`AlgIterator`], consuming the factory.
-    ///
-    /// The function `step_fn` should accept a `state` ([`AlgIteratorState`] parameter, and return
-    /// a [`Step`].
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error;
+    fn prepare(self) -> Self::Iter;
 
     /// Iterate the the closure `step`.
     ///
@@ -252,12 +255,12 @@
     /// This method is equivalent to [`Self::prepare`] followed by [`AlgIterator::iterate`].
     #[inline]
     fn iterate_fallible<F, E>(self, step : F) -> Result<(), E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
+    where F : FnMut(Self::State) -> Step<V, Self::State, E>,
           E : Error {
-        self.prepare(step).iterate()
+        self.prepare().iterate(step)
     }
 
-    /// Iterate the the closure `step`.
+    /// Iterate the closure `step`.
     ///
     /// The closure should accept a `state` parameter (satisfying the trait [`AlgIteratorState`]),
     /// It should return the output of
@@ -269,7 +272,7 @@
     /// with the error type `E=`[`std::convert::Infallible`].
     #[inline]
     fn iterate<F>(self, step : F)
-    where F : FnMut(&Self::State) -> Step<V> {
+    where F : FnMut(Self::State) -> Step<V, Self::State> {
         self.iterate_fallible(step).unwrap_or_default()
     }
 
@@ -285,13 +288,14 @@
     ///
     /// For usage instructions see the [module documentation][self].
     #[inline]
-    fn iterate_data_fallible<F, D, I, E>(self, mut datasource : I, mut step : F) -> Result<(), E>
-    where F : FnMut(&Self::State, D) -> Step<V, E>,
+    fn iterate_data_fallible<F, D, I, E>(self, mut datasource : I, mut step : F)
+    -> Result<(), E>
+    where F : FnMut(Self::State, D) -> Step<V, Self::State, E>,
           I : Iterator<Item = D>,
           E : Error {
-        self.prepare(move |state| {
+        self.prepare().iterate(move |state| {
             datasource.next().map_or(Step::Terminated, |d| step(state, d))
-        }).iterate()
+        })
     }
 
     /// Iterate the closure `step` with data produced by `datasource`.
@@ -306,7 +310,7 @@
     /// For usage instructions see the [module documentation][self].
     #[inline]
     fn iterate_data<F, D, I>(self, datasource : I, step : F)
-    where F : FnMut(&Self::State, D) -> Step<V>,
+    where F : FnMut(Self::State, D) -> Step<V, Self::State>,
           I : Iterator<Item = D> {
         self.iterate_data_fallible(datasource, step).unwrap_or_default()
     }
@@ -395,6 +399,26 @@
 
     /// Is the iterator quiet, i.e., on-verbose?
     fn is_quiet(&self) -> bool { false }
+
+    /// Returns an an [`std::iter::Iterator`] that can be used in a `for`-loop.
+    fn iter(self) -> AlgIteratorIterator<Self::Iter> {
+        AlgIteratorIterator {
+            algi : Rc::new(RefCell::new(self.prepare())),
+        }
+    }
+
+    /// Returns an an [`std::iter::Iterator`] that can be used in a `for`-loop,
+    /// also inputting an initial iteration status calculated by `f` if needed.
+    fn iter_init(self, f : impl FnOnce() -> <Self::Iter as AlgIterator>::Input)
+    -> AlgIteratorIterator<Self::Iter> {
+        let mut i = self.prepare();
+        let st = i.state();
+        let step : Step<<Self::Iter as AlgIterator>::Input, Self::State> = st.if_verbose(f);
+        i.poststep(step);
+        AlgIteratorIterator {
+            algi : Rc::new(RefCell::new(i)),
+        }
+    }
 }
 
 /// Options for [`BasicAlgIteratorFactory`].
@@ -427,6 +451,11 @@
     /// * every 10 iterations from there on until 100 iterations,
     /// * every 100 iteartinos frmo there on until 1000 iterations, etc.
     Logarithmic(usize),
+    /// Same as `Logarithmic`, but $\log_b(n)$ is replaced by $min\{c, \log_b(n)\}$ where $c$
+    /// is the given `cap`. For example, with `base=10` and `cap=2`, the first ten iterations
+    /// will be output, then every tenth iteration, and after 100 iterations, every 100th iteration,
+    /// without further logarithmic progression.
+    LogarithmicCap{ base : usize, cap : u32 },
 }
 
 impl Verbose {
@@ -443,6 +472,10 @@
                 let every = base.pow((iter as float).log(base as float).floor() as u32);
                 iter % every == 0
             }
+            &Verbose::LogarithmicCap{base, cap} => {
+                let every = base.pow(((iter as float).log(base as float).floor() as u32).min(cap));
+                iter % every == 0
+            }
         }
     }
 }
@@ -467,6 +500,8 @@
     verbose : bool,
     /// Whether results should be calculated.
     calc : bool,
+    /// Indicates whether the iteration is quiet
+    quiet : bool,
 }
 
 /// [`AlgIteratorFactory`] for [`BasicAlgIterator`]
@@ -478,11 +513,10 @@
 
 /// The simplest [`AlgIterator`], created by [`BasicAlgIteratorFactory`]
 #[derive(Clone,Debug)]
-pub struct BasicAlgIterator<F, V, E : Error> {
+pub struct BasicAlgIterator<V> {
     options : AlgIteratorOptions,
     iter : usize,
-    step_fn : F,
-    _phantoms : PhantomData<(V, E)>,
+    _phantoms : PhantomData<V>,
 }
 
 impl AlgIteratorOptions {
@@ -500,18 +534,13 @@
 impl<V> AlgIteratorFactory<V> for AlgIteratorOptions
 where V : LogRepr {
     type State = BasicState;
-    type Iter<F, E> = BasicAlgIterator<F, V, E>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = BasicAlgIterator<V>;
     type Output = V;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         BasicAlgIterator{
             options : self,
             iter : 0,
-            step_fn,
             _phantoms : PhantomData,
         }
     }
@@ -525,18 +554,13 @@
 impl<V> AlgIteratorFactory<V> for BasicAlgIteratorFactory<V>
 where V : LogRepr {
     type State = BasicState;
-    type Iter<F, E> = BasicAlgIterator<F, V, E>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = BasicAlgIterator<V>;
     type Output = V;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         BasicAlgIterator {
             options : self.options,
             iter : 0,
-            step_fn,
             _phantoms : PhantomData
         }
     }
@@ -547,33 +571,33 @@
     }
 }
 
-impl<F, V, E> AlgIterator for BasicAlgIterator<F, V, E>
-where V : LogRepr,
-      E : Error,
-      F : FnMut(&BasicState) -> Step<V, E> {
+impl<V> AlgIterator for BasicAlgIterator<V>
+where V : LogRepr {
     type State = BasicState;
     type Output = V;
-    type Err = E;
+    type Input = V;
 
     #[inline]
-    fn step(&mut self) -> Step<V, E> {
+    fn prestep(&mut self) -> Option<Self::State> {
         if self.iter >= self.options.max_iter {
-            Step::Terminated
+            None
         } else {
             self.iter += 1;
-            let state = self.state();
-            let res = (self.step_fn)(&state);
-            if let Step::Result(ref val) = res {
-                if state.verbose && !self.options.quiet {
-                    println!("{}{}/{} {}{}", "".dimmed(),
-                            state.iter,
-                            self.options.max_iter,
-                            val.logrepr(),
-                            "".clear());
-                }
+            Some(self.state())
+        }
+    }
+
+    fn poststep<E : Error>(&mut self, res : Step<V, Self::State, E>) -> Step<V, Self::State, E> {
+        if let Step::Result(ref val, ref state) = res {
+            if state.verbose && !self.options.quiet {
+                println!("{}{}/{} {}{}", "".dimmed(),
+                        state.iter,
+                        self.options.max_iter,
+                        val.logrepr(),
+                        "".clear());
             }
-            res
         }
+        res
     }
 
     #[inline]
@@ -585,19 +609,20 @@
     fn state(&self) -> BasicState {
         let iter = self.iter;
         let verbose = self.options.verbose_iter.is_verbose(iter);
-        BasicState{
+        BasicState {
             iter : iter,
             verbose : verbose,
             calc : verbose,
+            quiet : self.options.quiet
         }
     }
 }
 
 impl AlgIteratorState for BasicState {
     #[inline]
-    fn if_verbose<V, E : Error>(&self, mut calc_objective : impl FnMut() -> V) -> Step<V, E> {
+    fn if_verbose<V, E : Error>(self, calc_objective : impl FnOnce() -> V) -> Step<V, Self, E> {
         if self.calc {
-            Step::Result(calc_objective())
+            Step::Result(calc_objective(), self)
         } else {
             Step::Quiet
         }
@@ -605,7 +630,12 @@
 
     #[inline]
     fn iteration(&self) -> usize {
-        return self.iter;
+        self.iter
+    }
+
+    #[inline]
+    fn is_quiet(&self) -> bool {
+        self.quiet
     }
 }
 
@@ -636,17 +666,13 @@
 for StallIteratorFactory<U, BaseFactory>
 where BaseFactory : AlgIteratorFactory<V, Output=U>,
       U : SignedNum + PartialOrd {
-    type Iter<F, E> = StallIterator<U, BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = StallIterator<U, BaseFactory::Iter>;
     type State = BaseFactory::State;
     type Output = BaseFactory::Output;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         StallIterator {
-            base_iterator : self.base_options.prepare(step_fn),
+            base_iterator : self.base_options.prepare(),
             stall : self.stall,
             previous_value : None,
         }
@@ -662,18 +688,24 @@
 where BaseIterator : AlgIterator<Output=U>,
       U : SignedNum + PartialOrd {
     type State = BaseIterator::State;
-    type Output = BaseIterator::Output;
-    type Err = BaseIterator::Err;
+    type Output = U;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<U, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(nv) => {
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<U, Self::State, E>
+    where E : Error {
+        match self.base_iterator.poststep(res) {
+            Step::Result(nv, state) => {
                 let previous_v = self.previous_value;
                 self.previous_value = Some(nv);
                 match previous_v {
                     Some(pv) if (nv - pv).abs() <= self.stall * pv.abs() => Step::Terminated,
-                    _ => Step::Result(nv),
+                    _ => Step::Result(nv, state),
                 }
             },
             val => val,
@@ -711,17 +743,13 @@
 for ValueIteratorFactory<U, BaseFactory>
 where BaseFactory : AlgIteratorFactory<V, Output=U>,
       U : SignedNum + PartialOrd {
-    type Iter<F, E> = ValueIterator<U, BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = ValueIterator<U, BaseFactory::Iter>;
     type State = BaseFactory::State;
     type Output = BaseFactory::Output;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         ValueIterator {
-            base_iterator : self.base_options.prepare(step_fn),
+            base_iterator : self.base_options.prepare(),
             target : self.target
         }
     }
@@ -736,17 +764,22 @@
 where BaseIterator : AlgIterator<Output=U>,
       U : SignedNum + PartialOrd {
     type State = BaseIterator::State;
-    type Output = BaseIterator::Output;
-    type Err = BaseIterator::Err;
+    type Output = U;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<U, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(v) => {
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<U, Self::State, E> where E : Error{
+        match self.base_iterator.poststep(res) {
+            Step::Result(v, state) => {
                  if v <= self.target {
                     Step::Terminated
                  } else {
-                    Step::Result(v)
+                    Step::Result(v, state)
                  }
             },
             val => val,
@@ -792,16 +825,12 @@
 where BaseFactory : AlgIteratorFactory<V>,
       BaseFactory::Output : 'log {
     type State = BaseFactory::State;
-    type Iter<F, E> = LoggingIterator<'log, BaseFactory::Output, BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = LoggingIterator<'log, BaseFactory::Output, BaseFactory::Iter>;
     type Output = ();
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         LoggingIterator {
-            base_iterator : self.base_options.prepare(step_fn),
+            base_iterator : self.base_options.prepare(),
             logger : self.logger,
         }
     }
@@ -818,12 +847,17 @@
       BaseIterator::Output : 'log {
     type State = BaseIterator::State;
     type Output = ();
-    type Err = BaseIterator::Err;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<Self::Output, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(v) => {
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<(), Self::State, E> where E : Error {
+        match self.base_iterator.poststep(res) {
+            Step::Result(v, _) => {
                 self.logger.log(v);
                 Step::Quiet
             },
@@ -845,7 +879,7 @@
 }
 
 /// This [`AlgIteratorFactory`] allows output mapping.
-/// 
+///
 /// Typically produced with [`AlgIteratorFactory::mapped`].
 #[derive(Debug)]
 pub struct MappingIteratorFactory<G, BaseFactory> {
@@ -868,16 +902,12 @@
 where BaseFactory : AlgIteratorFactory<V>,
       G : Fn(usize, BaseFactory::Output) -> U {
     type State = BaseFactory::State;
-    type Iter<F, E> = MappingIterator<G, BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = MappingIterator<G, BaseFactory::Iter>;
     type Output = U;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         MappingIterator {
-            base_iterator : self.base_options.prepare(step_fn),
+            base_iterator : self.base_options.prepare(),
             map : self.map
         }
     }
@@ -894,12 +924,17 @@
       G : Fn(usize, BaseIterator::Output) -> U {
     type State = BaseIterator::State;
     type Output = U;
-    type Err = BaseIterator::Err;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<Self::Output, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(v) => Step::Result((self.map)(self.iteration(), v)),
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<Self::Output, Self::State, E> where E : Error {
+        match self.base_iterator.poststep(res) {
+            Step::Result(v, state) => Step::Result((self.map)(self.iteration(), v), state),
             Step::Quiet => Step::Quiet,
             Step::Terminated => Step::Terminated,
             Step::Failure(e) => Step::Failure(e),
@@ -935,7 +970,11 @@
 /// Data `U` with production time attached
 #[derive(Copy, Clone, Debug, Serialize)]
 pub struct Timed<U> {
+    /// CPU time taken
     pub cpu_time : Duration,
+    /// Iteration number
+    pub iter : usize,
+    /// User data
     //#[serde(flatten)]
     pub data : U
 }
@@ -951,16 +990,12 @@
 for TimingIteratorFactory<BaseFactory>
 where BaseFactory : AlgIteratorFactory<V> {
     type State = BaseFactory::State;
-    type Iter<F, E> = TimingIterator<BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = TimingIterator<BaseFactory::Iter>;
     type Output = Timed<BaseFactory::Output>;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         TimingIterator {
-            base_iterator : self.0.prepare(step_fn),
+            base_iterator : self.0.prepare(),
             start_time : ProcessTime::now()
         }
     }
@@ -976,16 +1011,22 @@
 where BaseIterator : AlgIterator {
     type State = BaseIterator::State;
     type Output = Timed<BaseIterator::Output>;
-    type Err = BaseIterator::Err;
+    type Input = BaseIterator::Input;
+
+    #[inline]
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
 
     #[inline]
-    fn step(&mut self) -> Step<Self::Output, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(data) => {
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<Self::Output, Self::State, E> where E : Error {
+        match self.base_iterator.poststep(res) {
+            Step::Result(data, state) => {
                 Step::Result(Timed{
                     cpu_time : self.start_time.elapsed(),
+                    iter : self.iteration(),
                     data
-                })
+                }, state)
             },
             Step::Quiet => Step::Quiet,
             Step::Terminated => Step::Terminated,
@@ -1005,6 +1046,82 @@
 }
 
 //
+// New for-loop interface
+//
+
+pub struct AlgIteratorIterator<I : AlgIterator> {
+    algi : Rc<RefCell<I>>,
+}
+
+pub struct AlgIteratorIteration<I : AlgIterator> {
+    state : I::State,
+    algi : Rc<RefCell<I>>,
+}
+
+impl<I : AlgIterator> std::iter::Iterator for AlgIteratorIterator<I> {
+    type Item = AlgIteratorIteration<I>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let algi = self.algi.clone();
+        RefCell::borrow_mut(&self.algi).prestep().map(|state| AlgIteratorIteration {
+            state,
+            algi,
+        })
+    }
+}
+
+/// Types of errors that may occur
+#[derive(Debug,PartialEq,Eq)]
+pub enum IterationError {
+    /// [`AlgIteratorIteration::if_verbose_check`] is not called in iteration order.
+    ReportingOrderingError
+}
+
+impl<I : AlgIterator> AlgIteratorIteration<I> {
+    /// Call `call_objective` if this is a verbose iteration.
+    ///
+    /// Verbosity depends on the [`AlgIterator`] that produced this state.
+    ///
+    /// The closure `calc_objective` should return an arbitrary value of type `V`, to be inserted
+    /// into the log, or whatever is deemed by the [`AlgIterator`]. For usage instructions see the
+    /// [module documentation][self].
+    ///
+    /// This function may panic if result reporting is not ordered correctly (an unlikely mistake
+    /// if using this facility correctly). For a version that propagates errors, see
+    /// [`Self::if_verbose_check`].
+    pub fn if_verbose(self, calc_objective : impl FnOnce() -> I::Input) {
+        self.if_verbose_check(calc_objective).unwrap()
+    }
+
+    /// Version of [`Self::if_verbose`] that propagates errors instead of panicking.
+    pub fn if_verbose_check(self, calc_objective : impl FnOnce() -> I::Input)
+    -> Result<(), IterationError> {
+        let mut algi = match RefCell::try_borrow_mut(&self.algi) {
+            Err(_) => return Err(IterationError::ReportingOrderingError),
+            Ok(algi) => algi
+        };
+        if self.state.iteration() != algi.iteration() {
+            Err(IterationError::ReportingOrderingError)
+        } else {
+            let res : Step<I::Input, I::State, std::convert::Infallible>
+                = self.state.if_verbose(calc_objective);
+            algi.poststep(res);
+            Ok(())
+        }
+    }
+
+    /// Returns the current iteration count.
+    pub fn iteration(&self) -> usize {
+        self.state.iteration()
+    }
+
+    /// Indicates whether the iterator is quiet
+    pub fn is_quiet(&self) -> bool {
+        self.state.is_quiet()
+    }
+}
+
+//
 // Tests
 //
 
@@ -1050,4 +1167,44 @@
                              .collect::<Vec<int>>())
         }
     }
+
+    #[test]
+    fn iteration_for_loop() {
+        let options = AlgIteratorOptions{
+            max_iter : 10,
+            verbose_iter : Verbose::Every(3),
+            .. Default::default()
+        };
+
+        {
+            let mut start = 1 as int;
+            for state in options.iter() {
+                start = start * 2;
+                state.if_verbose(|| start)
+            }
+            assert_eq!(start, (2 as int).pow(10));
+        }
+
+        {
+            let mut start = 1 as int;
+            let mut log = Logger::new();
+            let factory = options.instantiate()
+                                 .with_iteration_number()
+                                 .into_log(&mut log);
+            for state in factory.iter() {
+                start = start * 2;
+                state.if_verbose(|| start)
+            }
+            assert_eq!(start, (2 as int).pow(10));
+            assert_eq!(log.data()
+                          .iter()
+                          .map(|LogItem{ data : v, iter : _ }| v.clone())
+                          .collect::<Vec<int>>(),
+                      (1..10).map(|i| (2 as int).pow(i))
+                             .skip(2)
+                             .step_by(3)
+                             .collect::<Vec<int>>())
+        }
+    }
+
 }

mercurial