1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "dart/optimizer/Problem.hpp"
34 
35 #include <algorithm>
36 #include <limits>
37 
38 #include "dart/common/Console.hpp"
39 #include "dart/math/Helpers.hpp"
40 #include "dart/optimizer/Function.hpp"
41 
42 namespace dart {
43 namespace optimizer {
44 
45 //==============================================================================
46 template <typename T>
getVectorObjectIfAvailable(std::size_t _idx,const std::vector<T> & _vec)47 static T getVectorObjectIfAvailable(
48     std::size_t _idx, const std::vector<T>& _vec)
49 {
50   // TODO: Should we have an out-of-bounds assertion or throw here?
51   if (_idx < _vec.size())
52     return _vec[_idx];
53 
54   return nullptr;
55 }
56 
57 //==============================================================================
Problem(std::size_t _dim)58 Problem::Problem(std::size_t _dim) : mDimension(0), mOptimumValue(0.0)
59 {
60   setDimension(_dim);
61 }
62 
63 //==============================================================================
setDimension(std::size_t _dim)64 void Problem::setDimension(std::size_t _dim)
65 {
66   if (_dim != mDimension)
67   {
68     mDimension = _dim;
69 
70     mInitialGuess = Eigen::VectorXd::Zero(mDimension);
71 
72     mLowerBounds = Eigen::VectorXd::Constant(
73         mDimension, -std::numeric_limits<double>::infinity());
74 
75     mUpperBounds = Eigen::VectorXd::Constant(
76         mDimension, std::numeric_limits<double>::infinity());
77 
78     mOptimalSolution = Eigen::VectorXd::Zero(mDimension);
79     clearAllSeeds();
80   }
81 }
82 
83 //==============================================================================
getDimension() const84 std::size_t Problem::getDimension() const
85 {
86   return mDimension;
87 }
88 
89 //==============================================================================
setInitialGuess(const Eigen::VectorXd & _initGuess)90 void Problem::setInitialGuess(const Eigen::VectorXd& _initGuess)
91 {
92   assert(
93       static_cast<std::size_t>(_initGuess.size()) == mDimension
94       && "Invalid size.");
95 
96   if (_initGuess.size() != static_cast<int>(mDimension))
97   {
98     dterr << "[Problem::setInitialGuess] Attempting to set the initial guess "
99           << "of a Problem of dimension [" << mDimension << "] to a vector of "
100           << "dimension [" << _initGuess.size() << "]. This initial guess "
101           << "will not be used!\n";
102     return;
103   }
104 
105   mInitialGuess = _initGuess;
106 }
107 
108 //==============================================================================
getInitialGuess() const109 const Eigen::VectorXd& Problem::getInitialGuess() const
110 {
111   return mInitialGuess;
112 }
113 
114 //==============================================================================
addSeed(const Eigen::VectorXd & _seed)115 void Problem::addSeed(const Eigen::VectorXd& _seed)
116 {
117   if (_seed.size() == static_cast<int>(mDimension))
118   {
119     mSeeds.push_back(_seed);
120   }
121   else
122   {
123     dtwarn << "[Problem::addSeed] Attempting to add a seed of dimension ["
124            << _seed.size() << "] a Problem of dimension [" << mDimension
125            << "]. The seed will not be added.\n";
126   }
127 }
128 
129 //==============================================================================
getSeed(std::size_t _index)130 Eigen::VectorXd& Problem::getSeed(std::size_t _index)
131 {
132   if (_index < mSeeds.size())
133     return mSeeds[_index];
134 
135   if (mSeeds.size() == 0)
136     dtwarn << "[Problem::getSeed] Requested seed at index [" << _index << "], "
137            << "but there are currently no seeds. Returning the problem's "
138            << "initial guess instead.\n";
139   else
140     dtwarn << "[Problem::getSeed] Requested seed at index [" << _index << "], "
141            << "but the current max index is [" << mSeeds.size() - 1 << "]. "
142            << "Returning the Problem's initial guess instead.\n";
143 
144   return mInitialGuess;
145 }
146 
147 //==============================================================================
getSeed(std::size_t _index) const148 const Eigen::VectorXd& Problem::getSeed(std::size_t _index) const
149 {
150   return const_cast<Problem*>(this)->getSeed(_index);
151 }
152 
153 //==============================================================================
getSeeds()154 std::vector<Eigen::VectorXd>& Problem::getSeeds()
155 {
156   return mSeeds;
157 }
158 
159 //==============================================================================
getSeeds() const160 const std::vector<Eigen::VectorXd>& Problem::getSeeds() const
161 {
162   return mSeeds;
163 }
164 
165 //==============================================================================
clearAllSeeds()166 void Problem::clearAllSeeds()
167 {
168   mSeeds.clear();
169 }
170 
171 //==============================================================================
setLowerBounds(const Eigen::VectorXd & _lb)172 void Problem::setLowerBounds(const Eigen::VectorXd& _lb)
173 {
174   assert(static_cast<std::size_t>(_lb.size()) == mDimension && "Invalid size.");
175   mLowerBounds = _lb;
176 }
177 
178 //==============================================================================
getLowerBounds() const179 const Eigen::VectorXd& Problem::getLowerBounds() const
180 {
181   return mLowerBounds;
182 }
183 
184 //==============================================================================
setUpperBounds(const Eigen::VectorXd & _ub)185 void Problem::setUpperBounds(const Eigen::VectorXd& _ub)
186 {
187   assert(static_cast<std::size_t>(_ub.size()) == mDimension && "Invalid size.");
188   mUpperBounds = _ub;
189 }
190 
191 //==============================================================================
getUpperBounds() const192 const Eigen::VectorXd& Problem::getUpperBounds() const
193 {
194   return mUpperBounds;
195 }
196 
197 //==============================================================================
setObjective(FunctionPtr _obj)198 void Problem::setObjective(FunctionPtr _obj)
199 {
200   assert(_obj && "nullptr pointer is not allowed.");
201   mObjective = _obj;
202 }
203 
204 //==============================================================================
getObjective() const205 FunctionPtr Problem::getObjective() const
206 {
207   return mObjective;
208 }
209 
210 //==============================================================================
addEqConstraint(FunctionPtr _eqConst)211 void Problem::addEqConstraint(FunctionPtr _eqConst)
212 {
213   assert(_eqConst);
214   mEqConstraints.push_back(_eqConst);
215 }
216 
217 //==============================================================================
addIneqConstraint(FunctionPtr _ineqConst)218 void Problem::addIneqConstraint(FunctionPtr _ineqConst)
219 {
220   assert(_ineqConst);
221   mIneqConstraints.push_back(_ineqConst);
222 }
223 
224 //==============================================================================
getNumEqConstraints() const225 std::size_t Problem::getNumEqConstraints() const
226 {
227   return mEqConstraints.size();
228 }
229 
230 //==============================================================================
getNumIneqConstraints() const231 std::size_t Problem::getNumIneqConstraints() const
232 {
233   return mIneqConstraints.size();
234 }
235 
236 //==============================================================================
getEqConstraint(std::size_t _idx) const237 FunctionPtr Problem::getEqConstraint(std::size_t _idx) const
238 {
239   assert(_idx < mEqConstraints.size());
240   return getVectorObjectIfAvailable<FunctionPtr>(_idx, mEqConstraints);
241 }
242 
243 //==============================================================================
getIneqConstraint(std::size_t _idx) const244 FunctionPtr Problem::getIneqConstraint(std::size_t _idx) const
245 {
246   assert(_idx < mIneqConstraints.size());
247   return getVectorObjectIfAvailable<FunctionPtr>(_idx, mIneqConstraints);
248 }
249 
250 //==============================================================================
removeEqConstraint(FunctionPtr _eqConst)251 void Problem::removeEqConstraint(FunctionPtr _eqConst)
252 {
253   // TODO(JS): Need to delete?
254   mEqConstraints.erase(
255       std::remove(mEqConstraints.begin(), mEqConstraints.end(), _eqConst),
256       mEqConstraints.end());
257 }
258 
259 //==============================================================================
removeIneqConstraint(FunctionPtr _ineqConst)260 void Problem::removeIneqConstraint(FunctionPtr _ineqConst)
261 {
262   // TODO(JS): Need to delete?
263   mIneqConstraints.erase(
264       std::remove(mIneqConstraints.begin(), mIneqConstraints.end(), _ineqConst),
265       mIneqConstraints.end());
266 }
267 
268 //==============================================================================
removeAllEqConstraints()269 void Problem::removeAllEqConstraints()
270 {
271   // TODO(JS): Need to delete?
272   mEqConstraints.clear();
273 }
274 
275 //==============================================================================
removeAllIneqConstraints()276 void Problem::removeAllIneqConstraints()
277 {
278   // TODO(JS): Need to delete?
279   mIneqConstraints.clear();
280 }
281 
282 //==============================================================================
setOptimumValue(double _val)283 void Problem::setOptimumValue(double _val)
284 {
285   mOptimumValue = _val;
286 }
287 
288 //==============================================================================
getOptimumValue() const289 double Problem::getOptimumValue() const
290 {
291   return mOptimumValue;
292 }
293 
294 //==============================================================================
setOptimalSolution(const Eigen::VectorXd & _optParam)295 void Problem::setOptimalSolution(const Eigen::VectorXd& _optParam)
296 {
297   assert(
298       static_cast<std::size_t>(_optParam.size()) == mDimension
299       && "Invalid size.");
300   mOptimalSolution = _optParam;
301 }
302 
303 //==============================================================================
getOptimalSolution()304 const Eigen::VectorXd& Problem::getOptimalSolution()
305 {
306   return mOptimalSolution;
307 }
308 
309 } // namespace optimizer
310 } // namespace dart
311