#![warn(missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts, trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces, unused_qualifications)]
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[allow(missing_docs)]
pub mod errors {
error_chain! {
errors {
ValueLimit
IterLimit(limit: usize) {
description("Max iteration limit exceeded")
display("Could not converge function after {} iterations", limit)
}
}
}
}
use errors::*;
pub fn fixedpoint<T, U>(func: &Fn(U, &T) -> U, x0: U, args: &T, maxiter: Option<usize>, maxval: Option<U>) -> Result<U>
where U: PartialEq + PartialOrd + Copy + std::fmt::Debug {
let maxiter = maxiter.unwrap_or(100);
let mut itr = maxiter;
let mut x = x0;
let mut val = func(x0, args);
while val != x {
trace!("Iteration: {}", maxiter - itr);
x = val;
val = func(x, args);
trace!("\tx: {:?}; F(x): {:?}", x, val);
itr -= 1;
if itr == 0 {
debug!("Max Iterations reached. Last value: {:?}", val);
bail!(ErrorKind::IterLimit(maxiter));
} else if val > maxval.unwrap_or(val) {
debug!("Maximum value of function reached. Last value: {:?}", val);
bail!(ErrorKind::ValueLimit);
}
};
Ok(val)
}
#[cfg(test)]
mod tests {
use fixedpoint;
fn func_with_fixed_point(num: u32, param: &u32) -> u32 {
150 + (((num as f32 / param.clone() as f32).ceil() as u32)*100)
}
#[test]
fn basic_tests() {
assert_eq!(fixedpoint(&func_with_fixed_point, 0, &150, None, None).unwrap(), 450);
assert_eq!(fixedpoint(&func_with_fixed_point, 0, &150, None, Some(400)).is_err(), true);
assert_eq!(fixedpoint(&func_with_fixed_point, 0, &10, Some(5), None).is_err(), true);
}
#[test]
#[should_panic(expected = "attempt to multiply with overflow")]
fn maxiter() {
fixedpoint(&func_with_fixed_point, 0, &10, Some(10), None).unwrap_or(0);
}
}