diff --git a/src/core/fbs/fbs_optimizer.rs b/src/core/fbs/fbs_optimizer.rs index be54fa79..920d5a7e 100644 --- a/src/core/fbs/fbs_optimizer.rs +++ b/src/core/fbs/fbs_optimizer.rs @@ -6,6 +6,7 @@ use super::super::SolverStatus; use super::FBSEngine; use super::FBSOptimizer; use crate::constraints; +use std::time; const MAX_ITER: usize = 100_usize; @@ -22,6 +23,7 @@ where FBSOptimizer { fbs_engine: fbs_engine, max_iter: MAX_ITER, + max_duration: None, } } @@ -48,20 +50,37 @@ where self.max_iter = max_iter; self } + + /// Sets the maximum number of iterations + pub fn with_max_duration( + &mut self, + max_duration: time::Duration, + ) -> &mut FBSOptimizer<'a, GradientType, ConstraintType, CostType> { + self.max_duration = Some(max_duration); + self + } } impl<'life, GradientType, ConstraintType, CostType> Optimizer for FBSOptimizer<'life, GradientType, ConstraintType, CostType> where - GradientType: Fn(&[f64], &mut [f64]) -> i32 + 'life, + GradientType: Fn(&[f64], &mut [f64]) -> i32, CostType: Fn(&[f64], &mut f64) -> i32, - ConstraintType: constraints::Constraint + 'life, + ConstraintType: constraints::Constraint, { fn solve(&mut self, u: &mut [f64]) -> SolverStatus { + let now = time::Instant::now(); + self.fbs_engine.init(u); let mut num_iter: usize = 0; - while self.fbs_engine.step(u) && num_iter < self.max_iter { - num_iter += 1; + if let Some(dur) = self.max_duration { + while self.fbs_engine.step(u) && num_iter < self.max_iter && dur <= now.elapsed() { + num_iter += 1; + } + } else { + while self.fbs_engine.step(u) && num_iter < self.max_iter { + num_iter += 1; + } } // cost at the solution @@ -77,6 +96,7 @@ where SolverStatus::new( num_iter < self.max_iter, num_iter, + now.elapsed(), self.fbs_engine.cache.norm_fpr, cost_value, ) diff --git a/src/core/fbs/mod.rs b/src/core/fbs/mod.rs index cca80126..2aff9dd7 100644 --- a/src/core/fbs/mod.rs +++ b/src/core/fbs/mod.rs @@ -48,6 +48,7 @@ mod fbs_optimizer; use super::Problem; use crate::constraints; +use std::time; /// Cache for the forward-backward splitting (FBS), or projected gradient, algorithm /// @@ -90,6 +91,7 @@ where { fbs_engine: &'a mut FBSEngine<'a, GradientType, ConstraintType, CostType>, max_iter: usize, + max_duration: Option, } /* --------------------------------------------------------------------------------------------- */ diff --git a/src/core/mod.rs b/src/core/mod.rs index 34429e41..d4347cf4 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -2,6 +2,7 @@ //! //! use crate::constraints; +use std::time; pub mod fbs; pub mod panoc; @@ -18,6 +19,8 @@ pub struct SolverStatus { converged: bool, /// number of iterations for convergence num_iter: usize, + /// time it took to solve + solve_time: time::Duration, /// norm of the fixed-point residual (FPR) fpr_norm: f64, /// cost value at the candidate solution diff --git a/src/core/panoc/mod.rs b/src/core/panoc/mod.rs index 8c3ddca8..e3ff60f7 100644 --- a/src/core/panoc/mod.rs +++ b/src/core/panoc/mod.rs @@ -1,6 +1,7 @@ //! PANOC super-fast algorithm use super::Problem; use crate::constraints; +use std::time; mod panoc_cache; mod panoc_engine; @@ -55,6 +56,7 @@ where { panoc_engine: &'a mut PANOCEngine<'a, GradientType, ConstraintType, CostType>, max_iter: usize, + max_duration: Option, } #[cfg(test)] diff --git a/src/core/panoc/panoc_optimizer.rs b/src/core/panoc/panoc_optimizer.rs index 26ec9179..75e347da 100644 --- a/src/core/panoc/panoc_optimizer.rs +++ b/src/core/panoc/panoc_optimizer.rs @@ -6,6 +6,7 @@ use super::super::SolverStatus; use super::PANOCEngine; use super::PANOCOptimizer; use crate::constraints; +use std::time; const MAX_ITER: usize = 100_usize; @@ -22,6 +23,7 @@ where PANOCOptimizer { panoc_engine: panoc_engine, max_iter: MAX_ITER, + max_duration: None, } } @@ -48,6 +50,15 @@ where self.max_iter = max_iter; self } + + /// Sets the maximum solution time, useful in real-time applications + pub fn with_max_duration( + &mut self, + max_duation: time::Duration, + ) -> &mut PANOCOptimizer<'a, GradientType, ConstraintType, CostType> { + self.max_duration = Some(max_duation); + self + } } impl<'life, GradientType, ConstraintType, CostType> Optimizer @@ -58,16 +69,27 @@ where ConstraintType: constraints::Constraint + 'life, { fn solve(&mut self, u: &mut [f64]) -> SolverStatus { + let now = time::Instant::now(); + self.panoc_engine.init(u); + let mut num_iter: usize = 0; - while self.panoc_engine.step(u) && num_iter < self.max_iter { - num_iter += 1; + + if let Some(dur) = self.max_duration { + while self.panoc_engine.step(u) && num_iter < self.max_iter && now.elapsed() <= dur { + num_iter += 1; + } + } else { + while self.panoc_engine.step(u) && num_iter < self.max_iter { + num_iter += 1; + } } // export solution status SolverStatus::new( num_iter < self.max_iter, num_iter, + now.elapsed(), self.panoc_engine.cache.norm_gamma_fpr, self.panoc_engine.cache.cost_value, ) diff --git a/src/core/solver_status.rs b/src/core/solver_status.rs index 98aed416..82657131 100644 --- a/src/core/solver_status.rs +++ b/src/core/solver_status.rs @@ -2,6 +2,7 @@ //! //! pub use crate::core::SolverStatus; +use std::time; impl SolverStatus { /// Constructs a new instance of SolverStatus @@ -15,12 +16,19 @@ impl SolverStatus { /// quality /// - `cost_value` the value of the cost function at the solution /// - pub fn new(converged: bool, num_iter: usize, fpr_norm: f64, cost_value: f64) -> SolverStatus { + pub fn new( + converged: bool, + num_iter: usize, + solve_time: time::Duration, + fpr_norm: f64, + cost_value: f64, + ) -> SolverStatus { SolverStatus { - converged: converged, - num_iter: num_iter, - fpr_norm: fpr_norm, - cost_value: cost_value, + converged, + num_iter, + solve_time, + fpr_norm, + cost_value, } } @@ -34,6 +42,11 @@ impl SolverStatus { self.num_iter } + /// number of iterations taken by the algorithm + pub fn get_solve_time(&self) -> time::Duration { + self.solve_time + } + /// norm of the fixed point residual pub fn get_norm_fpr(&self) -> f64 { self.fpr_norm