pub struct Problem<O> {
pub problem: Option<O>,
pub counts: HashMap<&'static str, u64>,
}
Expand description
Wrapper around problems defined by users.
Keeps track of how many times methods such as apply
, cost
, gradient
, jacobian
,
hessian
, anneal
and so on are called. It is used to pass the problem from one iteration of
a solver to the next.
Fields§
§problem: Option<O>
Problem defined by user
counts: HashMap<&'static str, u64>
Keeps track of how often methods of problem
have been called.
Implementations§
source§impl<O> Problem<O>
impl<O> Problem<O>
sourcepub fn new(problem: O) -> Self
pub fn new(problem: O) -> Self
Wraps a problem into an instance of Problem
.
§Example
let wrapped_problem = Problem::new(UserDefinedProblem {});
sourcepub fn problem<T, F: FnOnce(&O) -> Result<T, Error>>(
&mut self,
counts_string: &'static str,
func: F,
) -> Result<T, Error>
pub fn problem<T, F: FnOnce(&O) -> Result<T, Error>>( &mut self, counts_string: &'static str, func: F, ) -> Result<T, Error>
Gives access to the stored problem
via the closure func
and keeps track of how many
times the function has been called. The function counts will be passed to observers labeled
with counts_string
. Per convention, counts_string
is chosen as <something>_count
.
§Example
let cost = problem.problem("cost_count", |problem| problem.cost(¶m));
This is typically used when designing a trait which optimization problems need to implement
for certain solvers. For instance, for a trait Anneal
used in Simulated Annealing, one
would write the following to enable the solver to call .anneal(...)
on an Problem
directly:
pub trait Anneal {
type Param;
type Output;
type Float;
fn anneal(&self, param: &Self::Param, extent: Self::Float) -> Result<Self::Output, Error>;
}
impl<O: Anneal> Problem<O> {
pub fn anneal(&mut self, param: &O::Param, extent: O::Float) -> Result<O::Output, Error> {
self.problem("anneal_count", |problem| problem.anneal(param, extent))
}
}
// ...
let new_param = problem.anneal(¶m, 1.0f64);
Note that this will unfortunately only work inside the argmin
crate itself due to the fact
that it is not possible to impl
a type from another crate. Therefore if one implements a
solver outside of argmin, .problem(...)
has to be called directly as shown in the first
example.
sourcepub fn bulk_problem<T, F: FnOnce(&O) -> Result<T, Error>>(
&mut self,
counts_string: &'static str,
num_param_vecs: usize,
func: F,
) -> Result<T, Error>
pub fn bulk_problem<T, F: FnOnce(&O) -> Result<T, Error>>( &mut self, counts_string: &'static str, num_param_vecs: usize, func: F, ) -> Result<T, Error>
Gives access to the stored problem
via the closure func
and keeps track of how many
times the function has been called. In contrast to the problem
method, this also allows
to pass the number of parameter vectors which will be processed by the underlying problem.
This is used by the bulk_*
methods, which process multiple parameters at once.
The function counts will be passed to observers labeled with counts_string
.
Per convention, counts_string
is chosen as <something>_count
.
sourcepub fn take_problem(&mut self) -> Option<O>
pub fn take_problem(&mut self) -> Option<O>
Returns the internally stored problem and replaces it with None
.
§Example
let mut problem = Problem::new(UserDefinedProblem {});
let user_problem: Option<UserDefinedProblem> = problem.take_problem();
assert_eq!(user_problem.unwrap(), UserDefinedProblem {});
assert!(problem.problem.is_none());
sourcepub fn consume_problem(&mut self, other: Problem<O>)
pub fn consume_problem(&mut self, other: Problem<O>)
Consumes another instance of Problem
. The internally stored user defined problem of the
passed Problem
instance is moved to Self
. The function evaluation counts are
merged/summed up.
§Example
let mut problem1 = Problem::new(UserDefinedProblem {});
// Simulate function evaluation counts in `problem1`
problem1.counts.insert("cost_count", 2);
// Take the internally stored problem such that `None` remains in its place.
let _ = problem1.take_problem();
assert!(problem1.problem.is_none());
let mut problem2 = Problem::new(UserDefinedProblem {});
// Simulate function evaluation counts in `problem2`
problem2.counts.insert("cost_count", 1);
problem2.counts.insert("gradient_count", 4);
// `problem1` consumes `problem2` by moving its internally stored user defined problem and
// by merging the function evaluation counts
problem1.consume_problem(problem2);
// `problem1` now holds a problem of type `UserDefinedProblem` (taken from `problem2`)
assert_eq!(problem1.problem.unwrap(), UserDefinedProblem {});
// The function evaluation counts have been merged
assert_eq!(problem1.counts["cost_count"], 3);
assert_eq!(problem1.counts["gradient_count"], 4);
sourcepub fn consume_func_counts<O2>(&mut self, other: Problem<O2>)
pub fn consume_func_counts<O2>(&mut self, other: Problem<O2>)
Consumes another instance of Problem
by summing ob the function evaluation counts.
In contrast to consume_problem
, the internally stored problem
remains untouched.
Therefore the two internally stored problems do not need to be of the same type.
§Example
let mut problem1 = Problem::new(UserDefinedProblem1 {});
// Simulate function evaluation counts in `problem1`.
problem1.counts.insert("cost_count", 2);
// Take the internally stored problem such that `None` remains in its place.
let _ = problem1.take_problem();
assert!(problem1.problem.is_none());
let mut problem2 = Problem::new(UserDefinedProblem2 {});
// Simulate function evaluation counts in `problem2`
problem2.counts.insert("cost_count", 1);
problem2.counts.insert("gradient_count", 4);
// `problem1` consumes `problem2` by merging the function evaluation counts.
problem1.consume_func_counts(problem2);
// The internally stored problem remains being `None` (in contrast to `consume_problem`).
assert!(problem1.problem.is_none());
// The function evaluation counts have been merged.
assert_eq!(problem1.counts["cost_count"], 3);
assert_eq!(problem1.counts["gradient_count"], 4);
sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Resets the function evaluation counts to zero.
§Example
let mut problem = Problem::new(UserDefinedProblem {});
// Simulate function evaluation counts in `problem1`.
problem.counts.insert("cost_count", 2);
problem.counts.insert("gradient_count", 4);
assert_eq!(problem.counts["cost_count"], 2);
assert_eq!(problem.counts["gradient_count"], 4);
// Set function evaluation counts to 0
problem.reset();
assert_eq!(problem.counts["cost_count"], 0);
assert_eq!(problem.counts["gradient_count"], 0);
sourcepub fn get_problem(self) -> Option<O>
pub fn get_problem(self) -> Option<O>
Returns the internally stored user defined problem by consuming Self
.
§Example
let problem = Problem::new(UserDefinedProblem {});
let user_problem = problem.get_problem();
assert_eq!(user_problem.unwrap(), UserDefinedProblem {});
source§impl<O: Operator> Problem<O>
impl<O: Operator> Problem<O>
Wraps a call to apply
defined in the Operator
trait and as such allows to call apply
on
an instance of Problem
. Internally, the number of evaluations of apply
is counted.
sourcepub fn apply(&mut self, param: &O::Param) -> Result<O::Output, Error>
pub fn apply(&mut self, param: &O::Param) -> Result<O::Output, Error>
Calls apply
defined in the Operator
trait and keeps track of the number of evaluations.
§Example
// `UserDefinedProblem` implements `Operator`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param = vec![2.0f64, 1.0f64];
let res = problem1.apply(¶m);
assert_eq!(problem1.counts["operator_count"], 1);
sourcepub fn bulk_apply<P>(&mut self, params: &[P]) -> Result<Vec<O::Output>, Error>
pub fn bulk_apply<P>(&mut self, params: &[P]) -> Result<Vec<O::Output>, Error>
Calls bulk_apply
defined in the Operator
trait and keeps track of the number of
evaluations.
§Example
// `UserDefinedProblem` implements `Operator`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param1 = vec![2.0f64, 1.0f64];
let param2 = vec![3.0f64, 5.0f64];
let params = vec![¶m1, ¶m2];
let res = problem1.bulk_apply(¶ms);
assert_eq!(problem1.counts["operator_count"], 2);
source§impl<O: CostFunction> Problem<O>
impl<O: CostFunction> Problem<O>
Wraps a call to cost
defined in the CostFunction
trait and as such allows to call cost
on
an instance of Problem
. Internally, the number of evaluations of cost
is counted.
sourcepub fn cost(&mut self, param: &O::Param) -> Result<O::Output, Error>
pub fn cost(&mut self, param: &O::Param) -> Result<O::Output, Error>
Calls cost
defined in the CostFunction
trait and keeps track of the number of
evaluations.
§Example
// `UserDefinedProblem` implements `CostFunction`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param = vec![2.0f64, 1.0f64];
let res = problem1.cost(¶m);
assert_eq!(problem1.counts["cost_count"], 1);
sourcepub fn bulk_cost<P>(&mut self, params: &[P]) -> Result<Vec<O::Output>, Error>
pub fn bulk_cost<P>(&mut self, params: &[P]) -> Result<Vec<O::Output>, Error>
Calls bulk_cost
defined in the CostFunction
trait and keeps track of the number of
evaluations.
§Example
// `UserDefinedProblem` implements `CostFunction`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param1 = vec![2.0f64, 1.0f64];
let param2 = vec![3.0f64, 5.0f64];
let params = vec![¶m1, ¶m2];
let res = problem1.bulk_cost(¶ms);
assert_eq!(problem1.counts["cost_count"], 2);
source§impl<O: Gradient> Problem<O>
impl<O: Gradient> Problem<O>
Wraps a call to gradient
defined in the Gradient
trait and as such allows to call gradient
on
an instance of Problem
. Internally, the number of evaluations of gradient
is counted.
sourcepub fn gradient(&mut self, param: &O::Param) -> Result<O::Gradient, Error>
pub fn gradient(&mut self, param: &O::Param) -> Result<O::Gradient, Error>
Calls gradient
defined in the Gradient
trait and keeps track of the number of
evaluations.
§Example
// `UserDefinedProblem` implements `Gradient`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param = vec![2.0f64, 1.0f64];
let res = problem1.gradient(¶m);
assert_eq!(problem1.counts["gradient_count"], 1);
sourcepub fn bulk_gradient<P>(
&mut self,
params: &[P],
) -> Result<Vec<O::Gradient>, Error>
pub fn bulk_gradient<P>( &mut self, params: &[P], ) -> Result<Vec<O::Gradient>, Error>
Calls bulk_gradient
defined in the Gradient
trait and keeps track of the number of
evaluations.
§Example
// `UserDefinedProblem` implements `Gradient`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param1 = vec![2.0f64, 1.0f64];
let param2 = vec![3.0f64, 5.0f64];
let params = vec![¶m1, ¶m2];
let res = problem1.bulk_gradient(¶ms);
assert_eq!(problem1.counts["gradient_count"], 2);
source§impl<O: Hessian> Problem<O>
impl<O: Hessian> Problem<O>
Wraps a call to hessian
defined in the Hessian
trait and as such allows to call hessian
on
an instance of Problem
. Internally, the number of evaluations of hessian
is counted.
sourcepub fn hessian(&mut self, param: &O::Param) -> Result<O::Hessian, Error>
pub fn hessian(&mut self, param: &O::Param) -> Result<O::Hessian, Error>
Calls hessian
defined in the Hessian
trait and keeps track of the number of evaluations.
§Example
// `UserDefinedProblem` implements `Hessian`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param = vec![2.0f64, 1.0f64];
let res = problem1.hessian(¶m);
assert_eq!(problem1.counts["hessian_count"], 1);
sourcepub fn bulk_hessian<P>(
&mut self,
params: &[P],
) -> Result<Vec<O::Hessian>, Error>
pub fn bulk_hessian<P>( &mut self, params: &[P], ) -> Result<Vec<O::Hessian>, Error>
Calls bulk_hessian
defined in the Hessian
trait and keeps track of the number of
evaluations.
§Example
// `UserDefinedProblem` implements `Hessian`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param1 = vec![2.0f64, 1.0f64];
let param2 = vec![3.0f64, 5.0f64];
let params = vec![¶m1, ¶m2];
let res = problem1.bulk_hessian(¶ms);
assert_eq!(problem1.counts["hessian_count"], 2);
source§impl<O: Jacobian> Problem<O>
impl<O: Jacobian> Problem<O>
Wraps a call to jacobian
defined in the Jacobian
trait and as such allows to call jacobian
on an instance of Problem
. Internally, the number of evaluations of jacobian
is counted.
sourcepub fn jacobian(&mut self, param: &O::Param) -> Result<O::Jacobian, Error>
pub fn jacobian(&mut self, param: &O::Param) -> Result<O::Jacobian, Error>
Calls jacobian
defined in the Jacobian
trait and keeps track of the number of
evaluations.
§Example
// `UserDefinedProblem` implements `Jacobian`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param = vec![2.0f64, 1.0f64];
let res = problem1.jacobian(¶m);
assert_eq!(problem1.counts["jacobian_count"], 1);
sourcepub fn bulk_jacobian<P>(
&mut self,
params: &[P],
) -> Result<Vec<O::Jacobian>, Error>
pub fn bulk_jacobian<P>( &mut self, params: &[P], ) -> Result<Vec<O::Jacobian>, Error>
Calls bulk_jacobian
defined in the Jacobian
trait and keeps track of the number of
evaluations.
§Example
// `UserDefinedProblem` implements `Jacobian`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let params = vec![vec![2.0f64, 1.0f64], vec![3.0f64, 5.0f64]];
let res = problem1.bulk_jacobian(¶ms);
assert_eq!(problem1.counts["jacobian_count"], 2);
source§impl<O: LinearProgram> Problem<O>
impl<O: LinearProgram> Problem<O>
Wraps a calls to c
, b
and A
defined in the LinearProgram
trait and as such allows to
call those methods on an instance of Problem
.
sourcepub fn c(&self) -> Result<Vec<O::Float>, Error>
pub fn c(&self) -> Result<Vec<O::Float>, Error>
Calls c
defined in the LinearProgram
trait.
§Example
// `UserDefinedProblem` implements `LinearProgram`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let c = problem1.c();
let b = problem1.b();
source§impl<O: Anneal> Problem<O>
impl<O: Anneal> Problem<O>
Wraps a call to anneal
defined in the Anneal
trait and as such allows to call anneal
on
an instance of Problem
. Internally, the number of evaluations of anneal
is counted.
sourcepub fn anneal(
&mut self,
param: &O::Param,
extent: O::Float,
) -> Result<O::Output, Error>
pub fn anneal( &mut self, param: &O::Param, extent: O::Float, ) -> Result<O::Output, Error>
Calls anneal
defined in the Anneal
trait and keeps track of the number of evaluations.
§Example
// `UserDefinedProblem` implements `Anneal`.
let mut problem1 = Problem::new(UserDefinedProblem {});
let param = vec![2.0f64, 1.0f64];
let res = problem1.anneal(¶m, 1.0);
assert_eq!(problem1.counts["anneal_count"], 1);
Trait Implementations§
Auto Trait Implementations§
impl<O> Freeze for Problem<O>where
O: Freeze,
impl<O> RefUnwindSafe for Problem<O>where
O: RefUnwindSafe,
impl<O> Send for Problem<O>where
O: Send,
impl<O> Sync for Problem<O>where
O: Sync,
impl<O> Unpin for Problem<O>where
O: Unpin,
impl<O> UnwindSafe for Problem<O>where
O: UnwindSafe,
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self
from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self
is actually part of its subset T
(and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset
but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self
to the equivalent element of its superset.