![]() |
Home | Libraries | People | FAQ | More |
#include <boost/math/optimization/minimizer.hpp> namespace boost { namespace math { namespace optimization { template<typename RealType> struct optimization_result { size_t num_iter = 0; RealType objective_value; std::vector<RealType> objective_history; bool converged; }; /* Minimize an objective using a given optimizer. * * The optimizer `opt` must expose a `step()` method and the associated * typedefs: * - argument_container_t * - real_type_t * * The behavior of the minimization loop is controlled by policy objects: * - ConstraintPolicy: projects variables onto a feasible set * - ConvergencePolicy: determines when convergence has been reached * - TerminationPolicy: determines when optimization must stop regardless * of convergence (e.g. max iterations) * * The function returns an `optimization_result` summarizing the run. */ template<class Optimizer, class ConstraintPolicy = unconstrained_policy<typename Optimizer::argument_container_t>, class ConvergencePolicy = gradient_norm_convergence_policy<typename Optimizer::real_type_t>, class TerminationPolicy = max_iter_termination_policy> auto minimize(Optimizer& opt, ConstraintPolicy project = ConstraintPolicy{}, ConvergencePolicy converged = ConvergencePolicy{ static_cast<typename Optimizer::real_type_t>(1e-3) }, TerminationPolicy terminate = TerminationPolicy(100000), bool history = true)
This header provides a generic driver function minimize
that repeatedly advances an optimizer via step(), optionally projects parameters onto a
constraint set, and stops when either a convergence criterion is met or a
termination criterion triggers.
Optimizer&
opt : Optimizer instance.
ConstraintPolicy project
: Projection policy applied after each step(). Default is unconstrained_policy
(no projection).
ConvergencePolicy converged
: Stopping criterion. Default is gradient_norm_convergence_policy(tol=1e-3).
TerminationPolicy terminate
: Hard stop criterion. Default is max_iter_termination_policy(100000).
bool history
: If true, records opt.objective_value() after each iteration in optimization_result::objective_history.
Convergence policies decide when the optimization has converged. Each policy has the signature:
bool operator()(const GradientContainer& g, RealType objective_value) const;
Stops when the Euclidean norm of the gradient falls below a tolerance:
template<typename RealType> struct gradient_norm_convergence_policy { explicit gradient_norm_convergence_policy(RealType tol); template<class GradientContainer> bool operator()(const GradientContainer& g, RealType objective_v) const; };
Stops when the absolute change in objective value between successive iterations drops below a tolerance:
template<typename RealType> struct objective_tol_convergence_policy { explicit objective_tol_convergence_policy(RealType tol); template<class GradientContainer> bool operator()(const GradientContainer&, RealType objective_v) const; };
The first call always returns false
Stops when the relative objective change drops below a tolerance:
template<typename RealType> struct relative_objective_tol_policy { explicit relative_objective_tol_policy(RealType rel_tol); template<class GradientContainer> bool operator()(const GradientContainer&, RealType objective_v) const; };
The relative change is computed as:
abs(obj - last_obj) / max(1, abs(last_obj))
Combines two convergence policies and stops when either triggers:
template<class Policy1, class Policy2> struct combined_convergence_policy { combined_convergence_policy(Policy1 p1, Policy2 p2); template<class GradientContainer, class RealType> bool operator()(const GradientContainer& g, RealType obj) const; };
Termination policies provide a hard stop independent of convergence. Each policy has the signature:
bool operator()(size_t iter);
Stops after a fixed number of iterations
struct max_iter_termination_policy { explicit max_iter_termination_policy(size_t max_iter); bool operator()(size_t iter); };
Stops after a wall-clock time budget:
struct wallclock_termination_policy { explicit wallclock_termination_policy(std::chrono::milliseconds max_time); bool operator()(size_t iter) const; };
Projection policies modify the optimizer variables after each step. Each policy has the signature:
void operator()(ArgumentContainer& x) const;
No projection; leaves parameters unchanged
template<typename ArgumentContainer> struct unconstrained_policy { void operator()(ArgumentContainer&); };
Clamps each variable into [min, max]
template<typename ArgumentContainer, typename RealType> struct box_constraints { box_constraints(RealType min, RealType max); void operator()(ArgumentContainer& x); };
Sets anything less than 0 to
0
template<typename ArgumentContainer, typename RealType> struct nonnegativity_constraint { void operator()(ArgumentContainer& x) const; };
Projects onto the L2 ball
of radius radius by uniform
scaling when needed
template<typename ArgumentContainer, typename RealType> struct l2_ball_constraint { explicit l2_ball_constraint(RealType radius); void operator()(ArgumentContainer& x) const; };
Projects onto the L1 ball
of radius radius by uniform
scaling
template<typename ArgumentContainer, typename RealType> struct l1_ball_constraint { explicit l1_ball_constraint(RealType radius); void operator()(ArgumentContainer& x) const; };
This is not the exact Euclidean projection onto the L1 ball; it is a simple scaling-based constraint
Projects onto the scaled probability simplex by clipping negatives to 0 and renormalizing to sum to 1
template<typename ArgumentContainer, typename RealType> struct simplex_constraint { void operator()(ArgumentContainer& x) const; };
Wraps a user-provided projection function
template<typename ArgumentContainer> struct function_constraint { using func_t = void (*)(ArgumentContainer&); explicit function_constraint(func_t f); void operator()(ArgumentContainer& x) const; };
Normalizes the vector to unit L2 norm
template<typename ArgumentContainer, typename RealType> struct unit_sphere_constraint { void operator()(ArgumentContainer& x) const; };
This projects onto the unit sphere (if ||x||_2 > 0)