Я сравниваю алгоритм SLSQP с простой 10D-функцией:
Функция c ++:
double myfunc(const std::vector<double> &x, std::vector<double> &grad, void *)
{
++counter;
assert(x.size() == 10);
double y = pow(x[0], 2);
double factor = 1e6;
for (size_t i = 1; i < 10; ++i)
y += factor * pow(x[i], 2);
if (!grad.empty())
{
assert(grad.size() == 10);
grad[0] = 2 * x[0];
for (size_t i = 1; i < 10; ++i)
grad[i] = 2 * factor * x[i];
}
return y;
}
К моему удивлению, SLSQP не работает для этой простой функции, но если я переключу алгоритм на nlopt::LD_LBFGS
, Nlopt по-прежнему оптимизировать функцию эффективно.
Кто-нибудь может объяснить, почему SLSQP не работает для этой демонстрационной функции?
Версия NLOPT — 2.4.2 (предоставлена nlopt::version
) ниже приведен полный код:
#include <cassert>
#include <cmath>
#include <iostream>
#include <nlopt.hpp>
#include <random>
#include <vector>
using namespace std;
mt19937_64 engine(random_device{}());
static int counter = 0;
double myfunc(const std::vector<double> &x, std::vector<double> &grad, void *)
{
++counter;
assert(x.size() == 10);
double y = pow(x[0], 2);
double factor = 1e6;
for (size_t i = 1; i < 10; ++i)
y += factor * pow(x[i], 2);
if (!grad.empty())
{
assert(grad.size() == 10);
grad[0] = 2 * x[0];
for (size_t i = 1; i < 10; ++i)
grad[i] = 2 * factor * x[i];
}
return y;
}
int main()
{
nlopt::opt opt(nlopt::LD_LBFGS, 10);
std::vector<double> lb(10, -100);
std::vector<double> ub(10, 100);
opt.set_lower_bounds(lb);
opt.set_upper_bounds(ub);
opt.set_min_objective(myfunc, NULL);
opt.set_maxeval(1000);
// opt.add_inequality_constraint(myfunc_constr, nullptr, 1);
vector<double> x(10);
uniform_real_distribution<double> distr(-100, 100);
for (auto &vx : x)
vx = distr(engine);
double minf = 1e20;
vector<double> fake_grad;
cout << "f(x0) = " << myfunc(x, fake_grad, nullptr) << endl;
try
{
counter = 0;
nlopt::result result = opt.optimize(x, minf);
cout << "exit val: " << result << endl;
}
catch (runtime_error &err)
{
cerr << err.what() << endl;
}
cout << endl;
cout << "optimized: " << minf << endl;
cout << "counter: " << counter << endl;
cout << opt.get_algorithm_name() << endl;
int maj, min, bugf;
nlopt::version(maj, min, bugf);
cout << "version: " << maj << "." << min << "." << bugf << endl;
return 0;
}
Задача ещё не решена.
Других решений пока нет …