使用 NLOPT SLSQP(基于梯度的算法)时 C 中的 NLopt nullptr 异常
NLopt nullptr exception in C while using the NLOPT SLSQP(Gradient-Based-Algorithm)
Servus 伙计们
我正在用 Nlopt(SLSQP) 做一个关于 参数识别 的项目,我写了一个测试代码,但是在 3 次迭代之后,编译器总是抛出异常Nullptr at 'grad' in 'myfunc'(objectfunction) :
'Exception thrown: write access violation. grad was nullptr.'
,这里我使用了有限差分来计算梯度,因为有限差分可以在我的项目中计算复杂模型的梯度。
我曾尝试将不同的 步长 从 1e-8 更改为 1e-6 以获得有限差分,之后代码无一例外地正常工作,我不知道原因,有人能告诉我吗?
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 是命令 window 的结果,步长为 1e-8
grad[0] 是 1.000000 grad[1] 是 1.000000
x[0] 是 1.000000 x[1] 是 1.000000
grad[0] 是 0.600000 grad[1] 是 0.600000
x[0] 为 1.666667 x[1] 为 1.666667
grad[0] 是 0.600000 grad[1] 是 0.600000
x[0] 为 1.666667 x[1] 为 1.666667
之后抛出编译器异常
你必须检查 grad
是否为 NULL,只有 return 不为 NULL 时才检查梯度。来自文档:
Also, if the parameter grad is not NULL, then we set grad[0] and
grad[1] to the partial derivatives of our objective with respect to
x[0] and x[1]. The gradient is only needed for gradient-based
algorithms; if you use a derivative-free optimization algorithm, grad
will always be NULL and you need never compute any derivatives.
因此您的代码应如下所示:
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]);
}
Servus 伙计们 我正在用 Nlopt(SLSQP) 做一个关于 参数识别 的项目,我写了一个测试代码,但是在 3 次迭代之后,编译器总是抛出异常Nullptr at 'grad' in 'myfunc'(objectfunction) :
'Exception thrown: write access violation. grad was nullptr.'
,这里我使用了有限差分来计算梯度,因为有限差分可以在我的项目中计算复杂模型的梯度。
我曾尝试将不同的 步长 从 1e-8 更改为 1e-6 以获得有限差分,之后代码无一例外地正常工作,我不知道原因,有人能告诉我吗?
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 是命令 window 的结果,步长为 1e-8
grad[0] 是 1.000000 grad[1] 是 1.000000
x[0] 是 1.000000 x[1] 是 1.000000
grad[0] 是 0.600000 grad[1] 是 0.600000
x[0] 为 1.666667 x[1] 为 1.666667
grad[0] 是 0.600000 grad[1] 是 0.600000
x[0] 为 1.666667 x[1] 为 1.666667
之后抛出编译器异常
你必须检查 grad
是否为 NULL,只有 return 不为 NULL 时才检查梯度。来自文档:
Also, if the parameter grad is not NULL, then we set grad[0] and grad[1] to the partial derivatives of our objective with respect to x[0] and x[1]. The gradient is only needed for gradient-based algorithms; if you use a derivative-free optimization algorithm, grad will always be NULL and you need never compute any derivatives.
因此您的代码应如下所示:
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]);
}