首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用NLopt (基于梯度的算法)时,C中的NLOPT nullptr异常

使用NLopt (基于梯度的算法)时,C中的NLOPT nullptr异常
EN

Stack Overflow用户
提问于 2019-08-29 21:06:24
回答 1查看 151关注 0票数 1

Servus我正在用Nlopt(SLSQP)做一个关于参数识别的项目,我编写了一个测试代码,但是在3次迭代之后,编译器总是在'myfunc'(objectfunction)中的'grad‘处抛出关于Nullptr的异常:

抛出的异常:写访问违反. grad为nullptr.‘

,其中我使用有限差分来计算梯度,因为有限差分可以计算项目中复杂模型的梯度。

我尝试将一个不同的步长从1e-8改为1e-6,在此之后,代码毫无例外地正常工作,我不知道原因,有人能告诉我吗?

代码语言:javascript
复制
double myfunc(unsigned n, const double *x,double *grad,void *data){ 

    double h =1e-8;

    grad[0] = (log(x[0] + h) - log(x[0])) / h; //hier compiler throws exception
    grad[1] = (log(x[1] + h) - log(x[1])) / h;

    printf("\ngrad[0] is %10f grad[1] is %10f\n", grad[0], grad[1]);
    printf("\nx[0] is %10f x[1] is %10f\n",x[0],x[1]);

    return log(x[0]) + log(x[1]);
}

double myconstraint(unsigned n, const double *x, double *grad, void*data) {

    double *a = (double *)data; 
    grad[0] = a[0];
    grad[1] = a[1];
    return x[0] * a[0] + x[1] * a[1] - 5;
}

double myinconstraint(unsigned n, const double *x, double *grad, void *data) {

    grad[0] = 1;
    grad[1] = -1;
    return x[0] - x[1];
}

void main(){
    //test-code

    double f_max = -10000;
    double tol = 1e-16;
    double p[2] = { 1,2 };
    double x[2] = { 1,1 };
    double lb[2] = { 0,0 };
    double ub[2] = { 10000,10000 }; 

    nlopt_opt opter = nlopt_create(NLOPT_LD_SLSQP, 2);      
    nlopt_set_max_objective(opter, myfunc, NULL);

    nlopt_set_lower_bounds(opter, lb);
    nlopt_set_upper_bounds(opter, ub);
    nlopt_add_equality_constraint(opter, myconstraint, p, tol);
    nlopt_add_inequality_constraint(opter, myinconstraint, NULL, tol); 
    nlopt_set_xtol_rel(opter, tol);
    nlopt_set_ftol_abs(opter, tol);

    nlopt_result result = nlopt_optimize(opter, x, &f_max);//?

    printf("Maximum utility=%f, x=(%f,%f)\n", f_max, x[0], x[1]);

    system("pause");
}

hier是步骤大小为1e-8的命令窗口中的结果。

grad是1.000000 grad1是1.000000

X是1.000000 x1是1.000000

grad是0.600000 grad1是0.600000

X是1.666667 x1是1.666667

grad是0.600000 grad1是0.600000

X是1.666667 x1是1.666667

之后,抛出编译器异常。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-27 20:58:00

您必须检查grad是否为NULL,并且只在它不是NULL时返回梯度。从文件中:

另外,如果参数梯度不是空的,那么我们将grad和grad1设为关于x和x1的目标的偏导数。梯度只适用于基于梯度的算法;如果使用无导数优化算法,梯度将始终为空,并且永远不需要计算任何导数。

因此,代码应该如下所示:

代码语言:javascript
复制
double myfunc(unsigned n, const double *x,double *grad,void *data)
{ 
    double h = 1e-8;

    if (grad) {
        grad[0] = (log(x[0] + h) - log(x[0])) / h;
        grad[1] = (log(x[1] + h) - log(x[1])) / h;
    }

    return log(x[0]) + log(x[1]);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57717739

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档