1 #ifndef OPTIMIZATION_H_ 2 #define OPTIMIZATION_H_ 3 4 #include <boost/property_tree/ptree.hpp> 5 6 #include <nlopt.h> 7 8 #include "MUQ/Optimization/CostFunction.h" 9 10 namespace muq { 11 namespace Optimization { 12 /// Solve an optimization problem 13 /** 14 \f{eqnarray}{ 15 c &=& \min{J(x; \theta_1, ..., \theta_1)} \\ 16 f_i(x) &\leq& 0 \\ 17 g_i(x) &=& 0 18 \f} 19 */ 20 class Optimization : public muq::Modeling::WorkPiece { 21 public: 22 23 /** 24 @param[in] cost The cost function 25 @param[in] pt Parameters for the optimization problem 26 */ 27 Optimization(std::shared_ptr<CostFunction> cost, boost::property_tree::ptree pt); 28 29 virtual ~Optimization(); 30 31 /// Add an inequality constraint to the optimization 32 /** 33 @param[in] ineq The constraint 34 */ 35 void AddInequalityConstraint(std::shared_ptr<CostFunction> ineq); 36 37 /// Add an equality constraint to the optimization 38 /** 39 NOTE: the NLOPT algorithm used must be able to handle equality constraints 40 @param[in] ineq The constraint 41 */ 42 void AddEqualityConstraint(std::shared_ptr<CostFunction> eq); 43 44 /// Solve the optimization problem 45 /** 46 @param[in] inputs The first input is the variable we are optimizing over, then inputs to the cost function, and inputs to the constraints in the order they were added 47 \return First: the argmin, second: the minimum cost 48 */ 49 std::pair<Eigen::VectorXd, double> Solve(muq::Modeling::ref_vector<boost::any> const& inputs); 50 51 /// Solve the optimization problem 52 /** 53 @param[in] inputs The first input is the variable we are optimizing over, then inputs to the cost function, and inputs to the constraints in the order they were added 54 \return First: the argmin, second: the minimum cost 55 */ 56 std::pair<Eigen::VectorXd, double> Solve(std::vector<Eigen::VectorXd> const& inputs); 57 58 /// Solve the optimization problem 59 /** 60 @param[in] args The first input is the variable we are optimizing over, then inputs to the cost function, and inputs to the constraints in the order they were added 61 \return First: the argmin, second: the minimum cost 62 */ 63 template<typename ...Args> Solve(Args...args)64 inline std::pair<Eigen::VectorXd, double> Solve(Args... args) { 65 Evaluate(args...); 66 67 return std::pair<Eigen::VectorXd, double>(boost::any_cast<Eigen::VectorXd const&>(outputs[0]), boost::any_cast<double const>(outputs[1])); 68 } 69 70 private: 71 72 /// Override the evaluate impl method (solve the optimization problem) 73 /** 74 @param[in] args The first input is the variable we are optimizing over, then inputs to the cost function, and inputs to the constraints in the order they were added 75 */ 76 virtual void EvaluateImpl(muq::Modeling::ref_vector<boost::any> const& inputs) override; 77 78 /// Evaluate either the cost function or a constraint 79 /** 80 @param[in] n The size of the input 81 @param[in] x The current point 82 @param[out] grad The gradient of the cost/constraint 83 @param[in] f_data An Optimization::CostHelper 84 \return The cost/constraint value 85 */ 86 static double Cost(unsigned int n, const double* x, double* grad, void* f_data); 87 88 /// Update the inputs if a constraint is added 89 /** 90 Adding a constraint (potentially) increases the number of inputs to the optimization problem. If the constraint requires inputs, add them to the optimization. 91 @param[in] numNewIns The number of inputs (not the state) that the constraint requires 92 */ 93 void UpdateInputs(unsigned int const numNewIns); 94 95 /// Get the NLOPT algorithm we are using 96 /** 97 @param[in] alg User-input algorithm 98 \return The NLOPT algorithm 99 */ 100 nlopt_algorithm NLOptAlgorithm(std::string const& alg) const; 101 102 /// The algorithm used to solve the problem 103 const nlopt_algorithm algorithm; 104 105 /// A structure to help evaluate the cost function and constraints 106 struct CostHelper { 107 /** 108 @param[in] cost The muq::Optimization::CostFunction that evaluates either the cost function or the constraint 109 @param[in] firstin The index of the optimziation inputs where this functions inputs begin 110 */ 111 CostHelper(std::shared_ptr<CostFunction> cost, unsigned int const firstin); 112 113 virtual ~CostHelper(); 114 115 /// Given an input to the optimization problem, set the inputs of this fucntion 116 /** 117 @param[in] ins The inputs to the optimization problem 118 */ 119 void SetInputs(muq::Modeling::ref_vector<boost::any> const& ins); 120 121 /// The cost function that we are trying to minimize or a cosntraint 122 std::shared_ptr<CostFunction> cost; 123 124 /// The index of the optimziation inputs where this functions inputs begin 125 const unsigned int firstin; 126 127 /// The inputs to this function 128 muq::Modeling::ref_vector<Eigen::VectorXd> inputs; 129 }; 130 131 /// The cost function that we are trying to minimize 132 CostHelper opt; 133 134 /// Inequality constraints 135 std::vector<CostHelper> ineqConstraints; 136 137 /// Equality constraints 138 /** 139 NOTE: the solver muq::Optimization::Optimization::algorithm must be able to handle equality constraints 140 */ 141 std::vector<CostHelper> eqConstraints; 142 143 /// Relative and absoluste tolerances on the cost function value and on the difference between successive values of the state 144 const double ftol_rel, ftol_abs, xtol_rel, xtol_abs; 145 146 /// Tolerance on the constraints 147 const double constraint_tol; 148 149 /// Maximum number of cost function evaluations 150 const unsigned int maxEvals; 151 152 /// Are minimizing the objection function? 153 /** 154 true: minmize the objection function, false: maximize the objective function 155 */ 156 const bool minimize; 157 }; 158 } // namespace Optimization 159 } // namespace muq 160 161 #endif 162