使用NLopt做简单优化

                                        

工作中经常遇到优化的问题,比如多数的统计方法最终都可以归结为一个优化问题。一般的统计和数值计算软件都会包含最优化算法的函数,比如Matlab中的fminsearch等,不过对于C等其他语言,很多时候可以选择的并不多。

之前工作中经常用到的是GSL中的优化算法,不过由于最近更经常使用MKL,所以希望能摆脱对GSL的依赖。这个时候找到了NLopt这个包。

NLopt使用起来非常简单,且支持非常多的语言,常见的语言比如C/ C++/ Julia/ Python/ R/ Fortran/ Lua/ OCaml/ Octave等都支持,所以算是一个“一招鲜,吃遍天”的包。除此之外,NLopt还有很多其他优点,比如:

  1. 可以方便的在不更改代码的情况下更改算法进行尝试,
  2. 支持一些常见的全局最优算法
  3. 支持一些高维的问题
  4. 支持常见的需要导数和不需要导数的多种算法
  5. 支持等式、不等式、有界等不同的约束极值问题

总之,很好用!

NLopt的安装也非常简单,与一般的源码安装过程一样,从官网NLopt - AbInitio 下载源码,然后:

./configure
make
sudo make install

就可以了,默认安装在/usr/local/lib/下。windows下可以用MinGW。

NLopt支持的算法可以从NLopt Algorithms 查询,包括:

下面是如下问题的一个实例代码:

\max_{x_1,x_2}\ln x_1+\ln x_2
s.t.
p_1 \cdot x_1+p_2\cdot x_2=5
x_1\leq x_2, x_1\geq 0, x_2\geq 0

注意其中有一个等式约束和一个不等式约束。我们使用Sequential Least-Squares Quadratic Programming (SLSQP) 算法来求解这个优化问题。

代码:

#include <stdio.h>
#include <math.h>
#include "nlopt.h"
#define INF (1.0/0.0)

double utility(unsigned n, const double *x, double *grad, void *data){
  grad[0]=1.0/x[0];
  grad[1]=1.0/x[1];
  printf("%f, %f, %f ", x[0],x[1],log(x[0])+log(x[1]));
  return log(x[0])+log(x[1]);
}

double constraint(unsigned n, const double *x, double *grad, void *data){
  double *p=(double *)data;
  grad[0]=*p;
  grad[1]=*(p+1);
  printf("Constraint: %f\n", x[0]*(*p)+x[1]*(*(p+1))-5);
  return x[0]*(*p)+x[1]*(*(p+1))-5;
}

double inconstraint(unsigned n, const double *x, double *grad, void *data){
  grad[0]=1;
  grad[1]=-1;
  return x[0]-x[1];
}

int main(int argc, char const *argv[]) {
  double p[2]={1,2};
  double tol=1e-8;
  double lb[2]={0,0};
  double ub[2]={INF,INF};
  double x[2]={1,1};
  double f_max=-INF;
  // set up optimizer
  nlopt_opt opter=nlopt_create(NLOPT_LD_SLSQP, 2);
  // lower and upper bound
  nlopt_set_lower_bounds(opter, lb);
  nlopt_set_upper_bounds(opter, ub);
  // objective function
  nlopt_set_max_objective(opter, utility, NULL);
  // equality constraint
  nlopt_add_equality_constraint(opter, constraint, p, tol);
  // inequality constraint
  nlopt_add_inequality_constraint(opter, inconstraint, NULL, tol);
  // stopping criterion
  nlopt_set_xtol_rel(opter, tol);
  nlopt_set_ftol_abs(opter, tol);
  nlopt_set_force_stop(opter, tol);
  // optimize
  nlopt_result result=nlopt_optimize(opter, x, &f_max);
  if (result)
    printf("Maximum utility=%f, x=(%f,%f)\n", f_max, x[0], x[1]);
  // free
  nlopt_destroy(opter);
  return 0;
}

编译:

gcc main.c -lnlopt -lm -Wall -O3 -o main

可以得到结果:

1.000000, 1.000000, 0.000000 Constraint: -2.000000

1.666667, 1.666667, 1.021651 Constraint: 0.000000

Maximum utility=1.021651, x=(1.666667,1.666667)

程序非常快速的收敛到了正确的结果。

过段时间再试试Julia的NLopt。

康格鹿

康格鹿1 年前

数值优化的程序包或者软件很多,往往不需要自己造车轮,只要能适当调用,往往能事半功倍。

3回复踩举报

张亮

张亮1 年前

您好,请问这里有能代替matlab中fmincon函数,用于求解非线性约束优化问题函数吗?

赞回复踩举报

慧航

慧航 (作者) 回复张亮1 年前

当然可以,如果是在matlab里面用,我是没用过,不过官网上有matlab里面怎么使用nlopt的,你可以看看

1查看对话回复踩举报

猫酱

猫酱1 年前

谢谢。我知道身边一些组是用这个package的,不知道nlopt可不可以做quadratic/conic programming,他和其他一些商业软件比如mosek比有什么优势劣势呢?
我也准备趁十二月假期多好好研究一下。

1回复踩举报

zhong z

zhong z1 年前

用了julia的jump你就知道c里面调用方式是多浪费人生了

赞回复踩举报

慧航

慧航 (作者) 回复zhong z1 年前

用过啊~

赞查看对话回复踩举报

慧航

慧航 (作者) 回复zhong z1 年前

我一般会先用julia写一个大概,然后把计算密集型的部分用C写,用了MKL、Openmp、TBB之后的C程序仍然不是Julia能相比的

赞查看对话回复踩举报

张亮

张亮回复慧航 (作者)1 年前

谢谢!我是用C/C++实现MATLAB里这个函数的功能,之前也只是简单了解过NLOPT这个库,当时看的很浅显,并没有实现相应的功能,我还是回头再仔细学习一下吧

赞查看对话回复踩举报

某财

某财1 年前

第一次见这个优化程序,我注意到您举例的优化问题是线性的,想请教下:1 非线性的优化问题能求解吗? 2 得出的结果保证是最优的吗?

赞回复踩举报

慧航

慧航 (作者) 回复某财1 年前

我的问题哪里是线性的。。。。

赞查看对话回复踩举报

某财

某财回复慧航 (作者)1 年前

1尴尬了,没仔细看目标函数....不好意思!那第二个问题,结果是最优的吗?

赞查看对话回复踩举报

慧航

慧航 (作者) 回复某财1 年前

包里面包含了全局最优的算法,不过是不是全局最优,谁知道呢。

1查看对话回复踩举报

某财

某财回复慧航 (作者)1 年前

多谢指教!

赞查看对话回复踩举报

曹血芹

曹血芹回复张亮1 年前

如果是凸优化的话也许可以用CVX

1查看对话回复踩举报

慧航

慧航 (作者) 回复曹血芹1 年前

matlab里面的?

赞查看对话回复踩举报

陈辉辉

陈辉辉1 年前

本人是新手,不知道用minGW怎么安装nlopt啊?有没有大神救救我

赞回复踩举报

慧航

慧航 (作者) 回复陈辉辉1 年前

configure-make-make install

赞查看对话回复踩举报

云设那般

云设那般10 个月前

请问三个方程式解六元 在做约束该怎么写呢?也就是*p*x[0]+..+ .*(p+5) * x[5] = 13,*d*x[0]+..+ .*(d+5) * x[5] = 21,....

赞回复踩举报

酸荔枝

酸荔枝1 个月前

您好,请教一下,就是在utility()、constraint()等中有grad求导一项,这应该是一个全局变量,但是并没有包含在函数返回中,请问这个是由什么用呢?

转:https://zhuanlan.zhihu.com/p/24350637

猜你喜欢

转载自blog.csdn.net/eric_e/article/details/81079079