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