|
| 1 | +// Illustration of how to use prima with COBYLA. |
| 2 | +// |
| 3 | +// Minimize the chained Rosenbrock function subject to various constraints. |
| 4 | +// |
| 5 | +// Translated from Zaikun Zhang's modern-Fortran reference implementation in PRIMA. |
| 6 | +// |
| 7 | +// Dedicated to late Professor M. J. D. Powell FRS (1936--2015). |
| 8 | + |
| 9 | +#include <iostream> |
| 10 | +#include <cmath> |
| 11 | +#include <iomanip> |
| 12 | +#include <Eigen/Core> |
| 13 | +#include "prima/prima.hpp" |
| 14 | + |
| 15 | +using namespace prima; |
| 16 | +using namespace Eigen; |
| 17 | + |
| 18 | +// Chained Rosenbrock function |
| 19 | +double chrosen(const VectorXd& x) { |
| 20 | + int n = x.size(); |
| 21 | + double f = 0; |
| 22 | + for (int i = 0; i < n - 1; ++i) { |
| 23 | + f += std::pow(1 - x(i), 2) + 4 * std::pow(x(i + 1) - x(i) * x(i), 2); |
| 24 | + } |
| 25 | + return f; |
| 26 | +} |
| 27 | + |
| 28 | +// Nonlinear inequality constraint: x(i)^2 >= x(i+1) |
| 29 | +VectorXd nlc_ineq(const VectorXd& x) { |
| 30 | + int n = x.size(); |
| 31 | + VectorXd c(n - 1); |
| 32 | + for (int i = 0; i < n - 1; ++i) { |
| 33 | + c(i) = x(i) * x(i) - x(i + 1); |
| 34 | + } |
| 35 | + return c; |
| 36 | +} |
| 37 | + |
| 38 | +// Nonlinear equality constraint: ||x||^2 = 1 |
| 39 | +VectorXd nlc_eq(const VectorXd& x) { |
| 40 | + VectorXd c(1); |
| 41 | + c(0) = x.squaredNorm() - 1; |
| 42 | + return c; |
| 43 | +} |
| 44 | + |
| 45 | +int main() { |
| 46 | + std::cout << std::setprecision(4); |
| 47 | + std::cout << "Minimize the chained Rosenbrock function with three variables " |
| 48 | + << "subject to various constraints using COBYLA.\n" << std::endl; |
| 49 | + |
| 50 | + VectorXd x0(3); |
| 51 | + x0 << 0, 0, 0; |
| 52 | + |
| 53 | + // ---------------------------------------------------------------- // |
| 54 | + // 1. Nonlinear constraints |
| 55 | + // ||x||_2^2 = 1, x(i)^2 >= x(i+1) >= 0.5*x(i) >= 0 for i = 1, 2 |
| 56 | + // ---------------------------------------------------------------- // |
| 57 | + std::cout << "1. Nonlinear constraints --- ||x||_2^2 = 1, " |
| 58 | + << "x(i)^2 >= x(i+1) >= 0.5*x(i) >= 0 for i = 1, 2:\n" << std::endl; |
| 59 | + |
| 60 | + VectorXd lb(3); lb << 0, 0, 0; |
| 61 | + VectorXd ub(3); ub << std::numeric_limits<double>::infinity(), |
| 62 | + std::numeric_limits<double>::infinity(), |
| 63 | + std::numeric_limits<double>::infinity(); |
| 64 | + Bounds bounds(lb, ub); |
| 65 | + |
| 66 | + // Linear constraints: 0.5*x(i) - x(i+1) <= 0 |
| 67 | + MatrixXd A(2, 3); |
| 68 | + A << 0.5, -1, 0, |
| 69 | + 0, 0.5, -1; |
| 70 | + LinearConstraint lin_con(A, |
| 71 | + VectorXd::Constant(2, -std::numeric_limits<double>::infinity()), |
| 72 | + VectorXd::Constant(2, 0.0)); |
| 73 | + |
| 74 | + // Nonlinear constraints |
| 75 | + NonlinearConstraint nlc_ineq_obj(nlc_ineq, |
| 76 | + VectorXd::Constant(2, 0.0), |
| 77 | + VectorXd::Constant(2, std::numeric_limits<double>::infinity())); |
| 78 | + NonlinearConstraint nlc_eq_obj(nlc_eq, |
| 79 | + VectorXd::Constant(1, 0.0), |
| 80 | + VectorXd::Constant(1, 0.0)); |
| 81 | + |
| 82 | + auto nlc_ineq_t = transform_constraint_function(nlc_ineq_obj); |
| 83 | + auto nlc_eq_t = transform_constraint_function(nlc_eq_obj); |
| 84 | + |
| 85 | + MinimizeOptions opts; |
| 86 | + opts.quiet = true; |
| 87 | + |
| 88 | + // COBYLA only handles one NonlinearConstraintFunction, so combine them |
| 89 | + NonlinearConstraintFunction combined_nlc = [nlc_ineq_t, nlc_eq_t](const VectorXd& x) -> VectorXd { |
| 90 | + VectorXd v1 = nlc_ineq_t(x); |
| 91 | + VectorXd v2 = nlc_eq_t(x); |
| 92 | + VectorXd r(v1.size() + v2.size()); |
| 93 | + r.head(v1.size()) = v1; |
| 94 | + r.tail(v2.size()) = v2; |
| 95 | + return r; |
| 96 | + }; |
| 97 | + |
| 98 | + auto result = minimize(chrosen, x0, "cobyla", &bounds, &lin_con, &combined_nlc, opts); |
| 99 | + std::cout << " x = [" << result.x(0) << ", " << result.x(1) << ", " << result.x(2) << "]" << std::endl; |
| 100 | + std::cout << " f = " << result.fun << " nfev = " << result.nfev << std::endl; |
| 101 | + std::cout << " ||x||^2 = " << result.x.squaredNorm() << std::endl; |
| 102 | + |
| 103 | + // ---------------------------------------------------------------- // |
| 104 | + // 2. Linear constraints |
| 105 | + // sum(x) = 1, x(i+1) <= x(i) <= 1 for i = 1, 2 |
| 106 | + // ---------------------------------------------------------------- // |
| 107 | + std::cout << "\n2. Linear constraints --- sum(x) = 1, x(i+1) <= x(i) <= 1 for i = 1, 2:\n" << std::endl; |
| 108 | + |
| 109 | + Bounds bounds2( |
| 110 | + VectorXd::Constant(3, -std::numeric_limits<double>::infinity()), |
| 111 | + VectorXd::Constant(3, 1.0)); |
| 112 | + MatrixXd A2(3, 3); |
| 113 | + A2 << -1, 1, 0, |
| 114 | + 0, -1, 1, |
| 115 | + 1, 1, 1; |
| 116 | + LinearConstraint lin_con2(A2, |
| 117 | + Vector3d(-std::numeric_limits<double>::infinity(), |
| 118 | + -std::numeric_limits<double>::infinity(), 1.0), |
| 119 | + Vector3d(0.0, 0.0, 1.0)); |
| 120 | + |
| 121 | + auto result2 = minimize(chrosen, x0, "cobyla", &bounds2, &lin_con2, nullptr, opts); |
| 122 | + std::cout << " x = [" << result2.x(0) << ", " << result2.x(1) << ", " << result2.x(2) << "]" << std::endl; |
| 123 | + std::cout << " f = " << result2.fun << " nfev = " << result2.nfev << std::endl; |
| 124 | + std::cout << " sum(x) = " << result2.x.sum() << std::endl; |
| 125 | + |
| 126 | + // ---------------------------------------------------------------- // |
| 127 | + // 3. Bound constraints: -0.5 <= x(1) <= 0.5, 0 <= x(2) <= 0.25 |
| 128 | + // ---------------------------------------------------------------- // |
| 129 | + std::cout << "\n3. Bound constraints --- -0.5 <= x(1) <= 0.5, 0 <= x(2) <= 0.25:\n" << std::endl; |
| 130 | + |
| 131 | + Bounds bounds3( |
| 132 | + Vector3d(-0.5, 0.0, -std::numeric_limits<double>::infinity()), |
| 133 | + Vector3d(0.5, 0.25, std::numeric_limits<double>::infinity())); |
| 134 | + |
| 135 | + auto result3 = minimize(chrosen, x0, "cobyla", &bounds3, nullptr, nullptr, opts); |
| 136 | + std::cout << " x = [" << result3.x(0) << ", " << result3.x(1) << ", " << result3.x(2) << "]" << std::endl; |
| 137 | + std::cout << " f = " << result3.fun << " nfev = " << result3.nfev << std::endl; |
| 138 | + |
| 139 | + // ---------------------------------------------------------------- // |
| 140 | + // 4. No constraints |
| 141 | + // ---------------------------------------------------------------- // |
| 142 | + std::cout << "\n4. No constraints:\n" << std::endl; |
| 143 | + auto result4 = minimize(chrosen, x0, "cobyla", nullptr, nullptr, nullptr, opts); |
| 144 | + std::cout << " x = [" << result4.x(0) << ", " << result4.x(1) << ", " << result4.x(2) << "]" << std::endl; |
| 145 | + std::cout << " f = " << result4.fun << " nfev = " << result4.nfev << std::endl; |
| 146 | + |
| 147 | + return 0; |
| 148 | +} |
0 commit comments