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

Wraps a problem into an instance of Problem.

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

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 labelled 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.

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 labelled with counts_string. Per convention, counts_string is chosen as <something>_count.

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

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

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

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

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 {});

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.

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

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

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.

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

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

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.

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

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

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.

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

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

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.

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

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

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.

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

Calls b defined in the LinearProgram trait.

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

let b = problem1.b();

Calls A defined in the LinearProgram trait.

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

let a = problem1.A();

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.

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

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

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

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

Should always be Self

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

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

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

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

The resulting type after obtaining ownership.

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

🔬 This is a nightly-only experimental API. (toowned_clone_into)

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

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.