我正在使用 NLOpt 库实现非线性优化问题,但在使用 C++ 接口定义向量值不等式约束时遇到一些麻烦。
NLOpt 文档似乎表明它们支持定义成本函数以及接受
std::vector<double>&
参数的等式和不等式约束函数,而不是指向数组的指针 (double*
)。请参阅以下链接的“C++ 示例”部分中的
myvfunc()
和 myvconstraint()
签名。
到目前为止,我已经成功使用以下函数签名编写了成本函数和等式约束:
double cost_fcn(const std::vector<double>& x, std::vector<double>& grad, void* data);
double eq_constraint(const std::vector<double>& x, std::vector<double>& grad, void* data);
NLOpt 文档还描述了对向量值相等和不等式约束的支持。但它们提供的函数签名(如下所示)是 C 格式(使用数组指针)。
void ineq_constraint(
unsigned m, double *result, unsigned n, const double* x, double* grad, void* f_data);
其中
m
是约束向量的维度,n
是参数空间的维度。
从文档中尚不清楚向量值约束是否支持 C++ 风格的函数签名,但我尝试实现以下内容,但它不起作用:
void ineq_constraint(
std::vector<double>& result, const std::vector<double>& x, std::vector<double>& grad, void* data);
此时,我将转而尝试使用 C 风格函数签名,但最好能得到关于 NLOpt 目前是否支持向量值约束的 C++ 风格函数签名的明确答案。
add_equality_constraint
和 add_inequality_constraint
具有相同的签名,它们采用签名为 的函数
double myvconstraint(const std::vector<double>& x, std::vector<double>& grad, void* data)
示例:
#include <nlopt.hpp>
#include <iomanip>
#include <iostream>
#include <vector>
struct my_constraint_data {
double a, b;
};
double myvfunc(const std::vector<double>& x, std::vector<double>& grad, void* my_func_data)
{
if (!grad.empty()) {
grad[0] = 0.0;
grad[1] = 0.5 / sqrt(x[1]);
}
return sqrt(x[1]);
}
double myvconstraint(const std::vector<double>& x, std::vector<double>& grad, void* data)
{
my_constraint_data* d = reinterpret_cast<my_constraint_data*>(data);
double a = d->a, b = d->b;
if (!grad.empty()) {
grad[0] = 3 * a * (a * x[0] + b) * (a * x[0] + b);
grad[1] = -1.0;
}
return ((a * x[0] + b) * (a * x[0] + b) * (a * x[0] + b) - x[1]);
}
int main()
{
nlopt::opt opt(nlopt::LD_SLSQP, 2);
std::vector<double> lb(2);
lb[0] = -HUGE_VAL; lb[1] = 0;
opt.set_lower_bounds(lb);
opt.set_min_objective(myvfunc, NULL);
my_constraint_data data[2] = { {0.33,0.29}, {-1,1} };
opt.add_equality_constraint(myvconstraint, &data[0], 1e-8);
opt.add_inequality_constraint(myvconstraint, &data[1], 1e-8);
opt.set_xtol_rel(1e-4);
std::vector<double> x(2);
x[0] = 1.234; x[1] = 5.678;
double minf;
try {
nlopt::result result = opt.optimize(x, minf);
std::cout << "found minimum at f(" << x[0] << "," << x[1] << ") = "
<< std::setprecision(10) << minf << std::endl;
}
catch (std::exception& e) {
std::cout << "nlopt failed: " << e.what() << std::endl;
}
}