关于设置具有非线性约束的NLopt,我有几个问题:
grad[ ]
?是否有任何(自动)方法可以解决此问题而无需引入拉格朗日乘数?使用拉格朗日多路复用器,我知道我们可以解决问题。但是,使用拉格朗日多路复用器,我们必须手动获得my_constraint_data
,这很难解决大规模问题。
例如,假设我要最小化该功能
f(x1,x2) = -((x1)^3)-(2*(x2)^2)+(10*(x1))-6-(2*(x2)^3)
受到以下限制:
约束1:c1 = 10-(x1)*(x2) >= 0
约束2:c2 = ((x1)*(x2)^2)-5 >= 0
约束3:c3 = (x2)-(x1)*(x2)^3 >= 0
在NLopt教程中,我们知道grad[0] = d(c1)/d(x1)
和grad[1] = d(c2)/d(x2)
是约束的梯度。然后,我们将grad
设置如下:
double myconstraint(unsigned n, const double *x, double *grad, void *data) {
my_constraint_data *d = (my_constraint_data *)data;
if (grad) {
grad[0] = -x[1]; //grad[0] = d(c1)/dx[1]
grad[1] = 2*x[0]+x[1]; //grad[1] = d(c2)/dx[2]
grad[2] = ???; //grad[2] = d(c3)/dx[3] but we only have 2 variable (x1)&(x2)
}
return (10-x[0]*x[1], x[0]*x[1]*x[1]-5, x[1]-x[0]*x[1]*x[1]*x[1];
}
问题是,如果约束数量大于变量数量,我们将不知道如何设置grad[ ]
(尤其是c3
)。
当然,我们可以使用拉格朗日多路复用器(l1,l2,l3)使用如下所示的非自动方法解决问题
grad[0] = -l1*(d(c1)/d(x1))-l2*(d(c2)/d(x1))-l3*(d(c)/d(x1))
和
grad[1] = -l1*(d(c1)/d(x2))-l2*(d(c2)/d(x2))-l3*(d(c)/d(x3))
double myconstraint(unsigned n, const double *x, double *grad, void *data) {
my_constraint_data *d = (my_constraint_data *)data;
//set l1, l2, and l3 as parameter of lagrangian multiplier
double l1=d->l1,l2=d->l2,l3=d->l3;
++count;
if (grad) {
grad[0] = l1*x[1]-l2*x[1]*x[1]-l3*x[1]*x[1]*x[1];
grad[1] = l1*x[0]-2*l2*x[0]*x[1]-l3+3*l3*x[0]*x[1]*x[1];
}
return (10-x[0]*x[1], x[0]*x[1]*x[1]-5, x[1]-x[0]*x[1]*x[1]*x[1]);
}
同时,将非自动方法应用于大规模问题并不容易,因为它将使编程效率低下且复杂。
感谢您的答复。这对我们真的很有帮助。谢谢您的好意。
答案 0 :(得分:0)
我认为您已经将要最小化的约束和变量混淆了。如果我正确理解了您的问题,则需要为三个约束创建三个单独的约束函数。例如:
double c1(unsigned n, const double *x, double *grad, void *data)
{
/* Enforces the constraint
*
* 10 - x1*x2 >= 0
*
* Note we compute x1*x2 - 10 instead of 10 - x1*x2 since nlopt expects
* inequality constraints to be of the form h(x) <= 0. */
if (grad) {
grad[0] = x[1]; // grad[0] = d(c1)/dx1
grad[1] = x[0]; // grad[1] = d(c1)/dx2
}
return x[0]*x[1] - 10;
}
double c2(unsigned n, const double *x, double *grad, void *data)
{
/* Enforces the constraint
*
* x1*x2^2 - 5 >= 0
*
* Note we compute -x1*x2^2 - 5 instead of x1*x2^2 - 5 since nlopt expects
* inequality constraints to be of the form h(x) <= 0. */
if (grad) {
grad[0] = -x[1]*x[1];
grad[1] = -2*x[0]*x[1];
}
return -x[0]*x[1]*x[1] + 5;
}
然后,在您的main
函数中,您需要分别添加每个不等式约束:
int main(int argc, char **argv)
{
// set up nlopt here
/* Add our constraints. */
nlopt_add_inequality_constraint(opt, c1, NULL, 1e-8);
nlopt_add_inequality_constraint(opt, c2, NULL, 1e-8);
// etc.
}