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