Sun, 20 Oct 2024 23:53:43 -0500
Simplify iterate facility for-loop mechanism
src/iterate.rs | file | annotate | diff | comparison | revisions | |
src/sets.rs | file | annotate | diff | comparison | revisions |
--- a/src/iterate.rs Sun Oct 20 23:28:16 2024 -0500 +++ b/src/iterate.rs Sun Oct 20 23:53:43 2024 -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,8 +63,8 @@ use std::marker::PhantomData; use std::time::Duration; use std::error::Error; +use std::cell::RefCell; use std::rc::Rc; -use std::cell::Cell; use crate::types::*; use crate::logger::*; @@ -392,11 +403,7 @@ /// Returns an an [`std::iter::Iterator`] that can be used in a `for`-loop. fn iter(self) -> AlgIteratorIterator<Self::Iter> { AlgIteratorIterator { - algi : self.prepare(), - result : Rc::new(AlgIteratorResponse{ - expected_iter : 0, - response : Cell::new(Step::Quiet) - }) + algi : Rc::new(RefCell::new(self.prepare())), } } } @@ -1015,50 +1022,27 @@ // New for-loop interface // -struct AlgIteratorResponse<I : AlgIterator> { - expected_iter : usize, - response : Cell<Step<I::Input, I::State>>, -} pub struct AlgIteratorIterator<I : AlgIterator> { - algi : I, - result : Rc<AlgIteratorResponse<I>>, + algi : Rc<RefCell<I>>, } pub struct AlgIteratorIteration<I : AlgIterator> { state : I::State, - result : Rc<AlgIteratorResponse<I>>, -} - -impl<I : AlgIterator> AlgIteratorIterator<I> { - fn poststep(&mut self, even_if_quiet : bool) { - let res = self.result.response.take(); - if !even_if_quiet { - if let Step::Quiet = res { - return - } - } - self.algi.poststep(res); - } + algi : Rc<RefCell<I>>, } impl<I : AlgIterator> std::iter::Iterator for AlgIteratorIterator<I> { type Item = AlgIteratorIteration<I>; fn next(&mut self) -> Option<Self::Item> { - self.poststep(true); - self.algi.prestep().map(|state| AlgIteratorIteration { + let algi = self.algi.clone(); + RefCell::borrow_mut(&self.algi).prestep().map(|state| AlgIteratorIteration { state, - result : self.result.clone(), + algi, }) } } -impl<I : AlgIterator> Drop for AlgIteratorIterator<I> { - fn drop(&mut self) { - self.poststep(false) - } -} - /// Types of errors that may occur #[derive(Debug,PartialEq,Eq)] pub enum IterationError { @@ -1083,13 +1067,18 @@ } /// Version of [`Self::if_verbose`] that propagates errors instead of panicking. - pub fn if_verbose_check(self, mut calc_objective : impl FnMut() -> I::Input) + pub fn if_verbose_check(self, calc_objective : impl FnMut() -> I::Input) -> Result<(), IterationError> { - if self.result.expected_iter != self.state.iteration() { + 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 = calc_objective(); - self.result.response.replace(Step::Result(res, self.state)); + let res : Step<I::Input, I::State, std::convert::Infallible> + = self.state.if_verbose(calc_objective); + algi.poststep(res); Ok(()) } } @@ -1151,4 +1140,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>>()) + } + } + }