1// Ceres Solver - A fast non-linear least squares minimizer 2// Copyright 2014 Google Inc. All rights reserved. 3// http://code.google.com/p/ceres-solver/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are met: 7// 8// * Redistributions of source code must retain the above copyright notice, 9// this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above copyright notice, 11// this list of conditions and the following disclaimer in the documentation 12// and/or other materials provided with the distribution. 13// * Neither the name of Google Inc. nor the names of its contributors may be 14// used to endorse or promote products derived from this software without 15// specific prior written permission. 16// 17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27// POSSIBILITY OF SUCH DAMAGE. 28// 29// Author: sameeragarwal@google.com (Sameer Agarwal) 30// 31// Bounds constrained test problems from the paper 32// 33// Testing Unconstrained Optimization Software 34// Jorge J. More, Burton S. Garbow and Kenneth E. Hillstrom 35// ACM Transactions on Mathematical Software, 7(1), pp. 17-41, 1981 36// 37// A subset of these problems were augmented with bounds and used for 38// testing bounds constrained optimization algorithms by 39// 40// A Trust Region Approach to Linearly Constrained Optimization 41// David M. Gay 42// Numerical Analysis (Griffiths, D.F., ed.), pp. 72-105 43// Lecture Notes in Mathematics 1066, Springer Verlag, 1984. 44// 45// The latter paper is behind a paywall. We obtained the bounds on the 46// variables and the function values at the global minimums from 47// 48// http://www.mat.univie.ac.at/~neum/glopt/bounds.html 49// 50// A problem is considered solved if of the log relative error of its 51// objective function is at least 5. 52 53 54#include <cmath> 55#include <iostream> // NOLINT 56#include "ceres/ceres.h" 57#include "gflags/gflags.h" 58#include "glog/logging.h" 59 60namespace ceres { 61namespace examples { 62 63const double kDoubleMax = std::numeric_limits<double>::max(); 64 65#define BEGIN_MGH_PROBLEM(name, num_parameters, num_residuals) \ 66 struct name { \ 67 static const int kNumParameters = num_parameters; \ 68 static const double initial_x[kNumParameters]; \ 69 static const double lower_bounds[kNumParameters]; \ 70 static const double upper_bounds[kNumParameters]; \ 71 static const double constrained_optimal_cost; \ 72 static const double unconstrained_optimal_cost; \ 73 static CostFunction* Create() { \ 74 return new AutoDiffCostFunction<name, \ 75 num_residuals, \ 76 num_parameters>(new name); \ 77 } \ 78 template <typename T> \ 79 bool operator()(const T* const x, T* residual) const { 80 81#define END_MGH_PROBLEM return true; } }; // NOLINT 82 83// Rosenbrock function. 84BEGIN_MGH_PROBLEM(TestProblem1, 2, 2) 85 const T x1 = x[0]; 86 const T x2 = x[1]; 87 residual[0] = T(10.0) * (x2 - x1 * x1); 88 residual[1] = T(1.0) - x1; 89END_MGH_PROBLEM; 90 91const double TestProblem1::initial_x[] = {-1.2, 1.0}; 92const double TestProblem1::lower_bounds[] = {-kDoubleMax, -kDoubleMax}; 93const double TestProblem1::upper_bounds[] = {kDoubleMax, kDoubleMax}; 94const double TestProblem1::constrained_optimal_cost = 95 std::numeric_limits<double>::quiet_NaN(); 96const double TestProblem1::unconstrained_optimal_cost = 0.0; 97 98// Freudenstein and Roth function. 99BEGIN_MGH_PROBLEM(TestProblem2, 2, 2) 100 const T x1 = x[0]; 101 const T x2 = x[1]; 102 residual[0] = T(-13.0) + x1 + ((T(5.0) - x2) * x2 - T(2.0)) * x2; 103 residual[1] = T(-29.0) + x1 + ((x2 + T(1.0)) * x2 - T(14.0)) * x2; 104END_MGH_PROBLEM; 105 106const double TestProblem2::initial_x[] = {0.5, -2.0}; 107const double TestProblem2::lower_bounds[] = {-kDoubleMax, -kDoubleMax}; 108const double TestProblem2::upper_bounds[] = {kDoubleMax, kDoubleMax}; 109const double TestProblem2::constrained_optimal_cost = 110 std::numeric_limits<double>::quiet_NaN(); 111const double TestProblem2::unconstrained_optimal_cost = 0.0; 112 113// Powell badly scaled function. 114BEGIN_MGH_PROBLEM(TestProblem3, 2, 2) 115 const T x1 = x[0]; 116 const T x2 = x[1]; 117 residual[0] = T(10000.0) * x1 * x2 - T(1.0); 118 residual[1] = exp(-x1) + exp(-x2) - T(1.0001); 119END_MGH_PROBLEM; 120 121const double TestProblem3::initial_x[] = {0.0, 1.0}; 122const double TestProblem3::lower_bounds[] = {0.0, 1.0}; 123const double TestProblem3::upper_bounds[] = {1.0, 9.0}; 124const double TestProblem3::constrained_optimal_cost = 0.15125900e-9; 125const double TestProblem3::unconstrained_optimal_cost = 0.0; 126 127// Brown badly scaled function. 128BEGIN_MGH_PROBLEM(TestProblem4, 2, 3) 129 const T x1 = x[0]; 130 const T x2 = x[1]; 131 residual[0] = x1 - T(1000000.0); 132 residual[1] = x2 - T(0.000002); 133 residual[2] = x1 * x2 - T(2.0); 134END_MGH_PROBLEM; 135 136const double TestProblem4::initial_x[] = {1.0, 1.0}; 137const double TestProblem4::lower_bounds[] = {0.0, 0.00003}; 138const double TestProblem4::upper_bounds[] = {1000000.0, 100.0}; 139const double TestProblem4::constrained_optimal_cost = 0.78400000e3; 140const double TestProblem4::unconstrained_optimal_cost = 0.0; 141 142// Beale function. 143BEGIN_MGH_PROBLEM(TestProblem5, 2, 3) 144 const T x1 = x[0]; 145 const T x2 = x[1]; 146 residual[0] = T(1.5) - x1 * (T(1.0) - x2); 147 residual[1] = T(2.25) - x1 * (T(1.0) - x2 * x2); 148 residual[2] = T(2.625) - x1 * (T(1.0) - x2 * x2 * x2); 149END_MGH_PROBLEM; 150 151const double TestProblem5::initial_x[] = {1.0, 1.0}; 152const double TestProblem5::lower_bounds[] = {0.6, 0.5}; 153const double TestProblem5::upper_bounds[] = {10.0, 100.0}; 154const double TestProblem5::constrained_optimal_cost = 0.0; 155const double TestProblem5::unconstrained_optimal_cost = 0.0; 156 157// Jennrich and Sampson function. 158BEGIN_MGH_PROBLEM(TestProblem6, 2, 10) 159 const T x1 = x[0]; 160 const T x2 = x[1]; 161 for (int i = 1; i <= 10; ++i) { 162 residual[i - 1] = T(2.0) + T(2.0 * i) - 163 exp(T(static_cast<double>(i)) * x1) - 164 exp(T(static_cast<double>(i) * x2)); 165 } 166END_MGH_PROBLEM; 167 168const double TestProblem6::initial_x[] = {1.0, 1.0}; 169const double TestProblem6::lower_bounds[] = {-kDoubleMax, -kDoubleMax}; 170const double TestProblem6::upper_bounds[] = {kDoubleMax, kDoubleMax}; 171const double TestProblem6::constrained_optimal_cost = 172 std::numeric_limits<double>::quiet_NaN(); 173const double TestProblem6::unconstrained_optimal_cost = 124.362; 174 175// Helical valley function. 176BEGIN_MGH_PROBLEM(TestProblem7, 3, 3) 177 const T x1 = x[0]; 178 const T x2 = x[1]; 179 const T x3 = x[2]; 180 const T theta = T(0.5 / M_PI) * atan(x2 / x1) + (x1 > 0.0 ? T(0.0) : T(0.5)); 181 182 residual[0] = T(10.0) * (x3 - T(10.0) * theta); 183 residual[1] = T(10.0) * (sqrt(x1 * x1 + x2 * x2) - T(1.0)); 184 residual[2] = x3; 185END_MGH_PROBLEM; 186 187const double TestProblem7::initial_x[] = {-1.0, 0.0, 0.0}; 188const double TestProblem7::lower_bounds[] = {-100.0, -1.0, -1.0}; 189const double TestProblem7::upper_bounds[] = {0.8, 1.0, 1.0}; 190const double TestProblem7::constrained_optimal_cost = 0.99042212; 191const double TestProblem7::unconstrained_optimal_cost = 0.0; 192 193// Bard function 194BEGIN_MGH_PROBLEM(TestProblem8, 3, 15) 195 const T x1 = x[0]; 196 const T x2 = x[1]; 197 const T x3 = x[2]; 198 199 double y[] = {0.14, 0.18, 0.22, 0.25, 200 0.29, 0.32, 0.35, 0.39, 0.37, 0.58, 201 0.73, 0.96, 1.34, 2.10, 4.39}; 202 203 for (int i = 1; i <=15; ++i) { 204 const T u = T(static_cast<double>(i)); 205 const T v = T(static_cast<double>(16 - i)); 206 const T w = T(static_cast<double>(std::min(i, 16 - i))); 207 residual[i - 1] = T(y[i - 1]) - x1 + u / (v * x2 + w * x3); 208 } 209END_MGH_PROBLEM; 210 211const double TestProblem8::initial_x[] = {1.0, 1.0, 1.0}; 212const double TestProblem8::lower_bounds[] = { 213 -kDoubleMax, -kDoubleMax, -kDoubleMax}; 214const double TestProblem8::upper_bounds[] = { 215 kDoubleMax, kDoubleMax, kDoubleMax}; 216const double TestProblem8::constrained_optimal_cost = 217 std::numeric_limits<double>::quiet_NaN(); 218const double TestProblem8::unconstrained_optimal_cost = 8.21487e-3; 219 220// Gaussian function. 221BEGIN_MGH_PROBLEM(TestProblem9, 3, 15) 222 const T x1 = x[0]; 223 const T x2 = x[1]; 224 const T x3 = x[2]; 225 226 const double y[] = {0.0009, 0.0044, 0.0175, 0.0540, 0.1295, 0.2420, 0.3521, 227 0.3989, 228 0.3521, 0.2420, 0.1295, 0.0540, 0.0175, 0.0044, 0.0009}; 229 for (int i = 0; i < 15; ++i) { 230 const T t_i = T((8.0 - i - 1.0) / 2.0); 231 const T y_i = T(y[i]); 232 residual[i] = x1 * exp(-x2 * (t_i - x3) * (t_i - x3) / T(2.0)) - y_i; 233 } 234END_MGH_PROBLEM; 235 236const double TestProblem9::initial_x[] = {0.4, 1.0, 0.0}; 237const double TestProblem9::lower_bounds[] = {0.398, 1.0, -0.5}; 238const double TestProblem9::upper_bounds[] = {4.2, 2.0, 0.1}; 239const double TestProblem9::constrained_optimal_cost = 0.11279300e-7; 240const double TestProblem9::unconstrained_optimal_cost = 0.112793e-7; 241 242// Meyer function. 243BEGIN_MGH_PROBLEM(TestProblem10, 3, 16) 244 const T x1 = x[0]; 245 const T x2 = x[1]; 246 const T x3 = x[2]; 247 248 const double y[] = {34780, 28610, 23650, 19630, 16370, 13720, 11540, 9744, 249 8261, 7030, 6005, 5147, 4427, 3820, 3307, 2872}; 250 251 for (int i = 0; i < 16; ++i) { 252 T t = T(45 + 5.0 * (i + 1)); 253 residual[i] = x1 * exp(x2 / (t + x3)) - y[i]; 254 } 255END_MGH_PROBLEM 256 257 258const double TestProblem10::initial_x[] = {0.02, 4000, 250}; 259const double TestProblem10::lower_bounds[] ={ 260 -kDoubleMax, -kDoubleMax, -kDoubleMax}; 261const double TestProblem10::upper_bounds[] ={ 262 kDoubleMax, kDoubleMax, kDoubleMax}; 263const double TestProblem10::constrained_optimal_cost = 264 std::numeric_limits<double>::quiet_NaN(); 265const double TestProblem10::unconstrained_optimal_cost = 87.9458; 266 267#undef BEGIN_MGH_PROBLEM 268#undef END_MGH_PROBLEM 269 270template<typename TestProblem> string ConstrainedSolve() { 271 double x[TestProblem::kNumParameters]; 272 std::copy(TestProblem::initial_x, 273 TestProblem::initial_x + TestProblem::kNumParameters, 274 x); 275 276 Problem problem; 277 problem.AddResidualBlock(TestProblem::Create(), NULL, x); 278 for (int i = 0; i < TestProblem::kNumParameters; ++i) { 279 problem.SetParameterLowerBound(x, i, TestProblem::lower_bounds[i]); 280 problem.SetParameterUpperBound(x, i, TestProblem::upper_bounds[i]); 281 } 282 283 Solver::Options options; 284 options.parameter_tolerance = 1e-18; 285 options.function_tolerance = 1e-18; 286 options.gradient_tolerance = 1e-18; 287 options.max_num_iterations = 1000; 288 options.linear_solver_type = DENSE_QR; 289 Solver::Summary summary; 290 Solve(options, &problem, &summary); 291 292 const double kMinLogRelativeError = 5.0; 293 const double log_relative_error = -std::log10( 294 std::abs(2.0 * summary.final_cost - 295 TestProblem::constrained_optimal_cost) / 296 (TestProblem::constrained_optimal_cost > 0.0 297 ? TestProblem::constrained_optimal_cost 298 : 1.0)); 299 300 return (log_relative_error >= kMinLogRelativeError 301 ? "Success\n" 302 : "Failure\n"); 303} 304 305template<typename TestProblem> string UnconstrainedSolve() { 306 double x[TestProblem::kNumParameters]; 307 std::copy(TestProblem::initial_x, 308 TestProblem::initial_x + TestProblem::kNumParameters, 309 x); 310 311 Problem problem; 312 problem.AddResidualBlock(TestProblem::Create(), NULL, x); 313 314 Solver::Options options; 315 options.parameter_tolerance = 1e-18; 316 options.function_tolerance = 0.0; 317 options.gradient_tolerance = 1e-18; 318 options.max_num_iterations = 1000; 319 options.linear_solver_type = DENSE_QR; 320 Solver::Summary summary; 321 Solve(options, &problem, &summary); 322 323 const double kMinLogRelativeError = 5.0; 324 const double log_relative_error = -std::log10( 325 std::abs(2.0 * summary.final_cost - 326 TestProblem::unconstrained_optimal_cost) / 327 (TestProblem::unconstrained_optimal_cost > 0.0 328 ? TestProblem::unconstrained_optimal_cost 329 : 1.0)); 330 331 return (log_relative_error >= kMinLogRelativeError 332 ? "Success\n" 333 : "Failure\n"); 334} 335 336} // namespace examples 337} // namespace ceres 338 339int main(int argc, char** argv) { 340 google::ParseCommandLineFlags(&argc, &argv, true); 341 google::InitGoogleLogging(argv[0]); 342 343 using ceres::examples::UnconstrainedSolve; 344 using ceres::examples::ConstrainedSolve; 345 346#define UNCONSTRAINED_SOLVE(n) \ 347 std::cout << "Problem " << n << " : " \ 348 << UnconstrainedSolve<ceres::examples::TestProblem##n>(); 349 350#define CONSTRAINED_SOLVE(n) \ 351 std::cout << "Problem " << n << " : " \ 352 << ConstrainedSolve<ceres::examples::TestProblem##n>(); 353 354 std::cout << "Unconstrained problems\n"; 355 UNCONSTRAINED_SOLVE(1); 356 UNCONSTRAINED_SOLVE(2); 357 UNCONSTRAINED_SOLVE(3); 358 UNCONSTRAINED_SOLVE(4); 359 UNCONSTRAINED_SOLVE(5); 360 UNCONSTRAINED_SOLVE(6); 361 UNCONSTRAINED_SOLVE(7); 362 UNCONSTRAINED_SOLVE(8); 363 UNCONSTRAINED_SOLVE(9); 364 UNCONSTRAINED_SOLVE(10); 365 366 std::cout << "\nConstrained problems\n"; 367 CONSTRAINED_SOLVE(3); 368 CONSTRAINED_SOLVE(4); 369 CONSTRAINED_SOLVE(5); 370 CONSTRAINED_SOLVE(7); 371 CONSTRAINED_SOLVE(9); 372 373 return 0; 374} 375