2

我有几个关于使用非线性约束设置 NLopt 的问题:

  1. 如果约束的数量大于变量的数量,我们如何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]);
}

同时,将非自动方法应用于大规模问题并不容易,因为它效率低且编程复杂。

  1. 有什么方法可以使用 NLopt 求解非线性联立方程?(当应用拉格朗日多路复用器时,在约束数大于变量数的情况下,应求解非线性联立方程。)。

我们感谢您的回答。这对我们真的很有帮助。谢谢你的好意。

4

1 回答 1

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.
}
于 2019-03-18T00:09:17.560 回答