NLOPT中的SLSQP因高条件数二次函数而失败

时间:2016-09-24 06:36:22

标签: c++ mathematical-optimization numerical-methods nlopt

我使用简单的10D二次函数对SLSQP算法进行基准测试:

f(x) = x_1^2 + 10^6\sum\limits_{i=2}^{D}x_i^2

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;
}

0 个答案:

没有答案