Struct argmin::core::Problem

source ·
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>

source

pub fn new(problem: O) -> Self

Wraps a problem into an instance of Problem.

Example
let wrapped_problem = Problem::new(UserDefinedProblem {});
source

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(&param));

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(&param, 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.

source

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.

source

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());
source

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);
source

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);
source

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);
source

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>

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.

source

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(&param);

assert_eq!(problem1.counts["operator_count"], 1);
source

pub fn bulk_apply<P>(&mut self, params: &[P]) -> Result<Vec<O::Output>, Error>
where P: Borrow<O::Param> + SyncAlias, O::Output: SendAlias, O: SyncAlias,

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![&param1, &param2];

let res = problem1.bulk_apply(&params);

assert_eq!(problem1.counts["operator_count"], 2);
source§

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.

source

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(&param);

assert_eq!(problem1.counts["cost_count"], 1);
source

pub fn bulk_cost<P>(&mut self, params: &[P]) -> Result<Vec<O::Output>, Error>
where P: Borrow<O::Param> + SyncAlias, O::Output: SendAlias, O: SyncAlias,

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![&param1, &param2];

let res = problem1.bulk_cost(&params);

assert_eq!(problem1.counts["cost_count"], 2);
source§

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.

source

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(&param);

assert_eq!(problem1.counts["gradient_count"], 1);
source

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![&param1, &param2];

let res = problem1.bulk_gradient(&params);

assert_eq!(problem1.counts["gradient_count"], 2);
source§

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.

source

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(&param);

assert_eq!(problem1.counts["hessian_count"], 1);
source

pub fn bulk_hessian<P>( &mut self, params: &[P] ) -> Result<Vec<O::Hessian>, Error>
where P: Borrow<O::Param> + SyncAlias, O::Hessian: SendAlias, O: SyncAlias,

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![&param1, &param2];

let res = problem1.bulk_hessian(&params);

assert_eq!(problem1.counts["hessian_count"], 2);
source§

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.

source

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(&param);

assert_eq!(problem1.counts["jacobian_count"], 1);
source

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(&params);

assert_eq!(problem1.counts["jacobian_count"], 2);
source§

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.

source

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

pub fn b(&self) -> Result<Vec<O::Float>, Error>

Calls b defined in the LinearProgram trait.

Example
// `UserDefinedProblem` implements `LinearProgram`.
let mut problem1 = Problem::new(UserDefinedProblem {});

let b = problem1.b();
source

pub fn A(&self) -> Result<Vec<Vec<O::Float>>, Error>

Calls A defined in the LinearProgram trait.

Example
// `UserDefinedProblem` implements `LinearProgram`.
let mut problem1 = Problem::new(UserDefinedProblem {});

let a = problem1.A();
source§

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.

source

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(&param, 1.0);

assert_eq!(problem1.counts["anneal_count"], 1);

Trait Implementations§

source§

impl<O: Clone> Clone for Problem<O>

source§

fn clone(&self) -> Problem<O>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<O: Debug> Debug for Problem<O>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<O: Default> Default for Problem<O>

source§

fn default() -> Problem<O>

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

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> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> SendAlias for T

source§

impl<T> SyncAlias for T