非线性优化--NLopt算法使用及C++实例

简介: 非线性优化--NLopt算法使用及C++实例

看这篇之前建议先看这篇,里面讲了非线性优化的原理即相关名词的概念,然后介绍了NLopt的使用方法,这个方法是基于C语言的,本片介绍一个NLopt的实例,用的C++语言。

在实例之前,先介绍下NLopt支持的算法,以及算法使用的注意事项

NLopt 支持的算法

NLopt 包含很多种不同的优化算法。

在头文件里面算法名称的枚举类型为

  enum algorithm {
     GN_DIRECT = 0,
     GN_DIRECT_L,
     GN_DIRECT_L_RAND,
     GN_DIRECT_NOSCAL,
     GN_DIRECT_L_NOSCAL,
     GN_DIRECT_L_RAND_NOSCAL,
     GN_ORIG_DIRECT,
     GN_ORIG_DIRECT_L,
     GD_STOGO,
     GD_STOGO_RAND,
     LD_LBFGS_NOCEDAL,
     LD_LBFGS,
     LN_PRAXIS,
     LD_VAR1,
     LD_VAR2,
     LD_TNEWTON,
     LD_TNEWTON_RESTART,
     LD_TNEWTON_PRECOND,
     LD_TNEWTON_PRECOND_RESTART,
     GN_CRS2_LM,
     GN_MLSL,
     GD_MLSL,
     GN_MLSL_LDS,
     GD_MLSL_LDS,
     LD_MMA,
     LN_COBYLA,
     LN_NEWUOA,
     LN_NEWUOA_BOUND,
     LN_NELDERMEAD,
     LN_SBPLX,
     LN_AUGLAG,
     LD_AUGLAG,
     LN_AUGLAG_EQ,
     LD_AUGLAG_EQ,
     LN_BOBYQA,
     GN_ISRES,
     AUGLAG,
     AUGLAG_EQ,
     G_MLSL,
     G_MLSL_LDS,
     LD_SLSQP,
     LD_CCSAQ,
     GN_ESCH,
     NUM_ALGORITHMS /*不是一种算法 只是算法的数量*/
  };

命名规律:

G/L代表的就是 全局(global)或者局部(local)优化
N/D代表的就是 不需导数 或者 需要导数 的优化

例如 LN_COBYLA 就是用的 COBYLA 算法 ,然后该算法用于局部(L)无需导数(N)的优化

算法选择

那么我们在使用的时候用哪种算法呢?随意选择吗?NO
对于一个确定的数学模型的优化问题,比较好的方式是 通过比较几种可用的算法,再确定选哪种,因为没有最佳算法,不同优化问题对于最佳的解决方式不同。

在比较算法的时候也要注意,不同算法适配的 函数值容差和参数容差 也应该是不同的。

有一种比较好的比较两种算对于一个数学模型的优劣的方式:
先运行一个算法得到最小值,然后运行第二个算法的时候设定就收敛到那个值,然后比较运行的时间

选择全局优化要注意的问题

当前,所有全局优化算法都要求对所有优化参数指定边界约束。
并且一定要注意的是
在这些算法中 只有 ISRES, AGS,ORIG_DIRECT 支持非线性不等式约束
只有 ISRES 支持非线性等式约束

有一种很好的做法就是通过全局算法找到一个最优点,然后以这个最优点作为局部优化的起点,使结果更准确

全局优化算法在找到最优点时 比局部优化算法要 花的精力多很多

Code

数学模型:

求 :max(lnx1+lnx2)    目标函数
约束: p1x1+p2x2=5        等式约束
            x1<=x2                  不等式约束                
            x1>=0;x2>=0         边界约束

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <nlopt.hpp> //nlopt的头文件

引用头文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//声明一个 是否使用梯度的 全局变量
bool grad_bool=1;

声明一个 是否使用梯度的 全局变量
这样方便在切换 基于梯度的算法和不需要导数的算法的时候可以 改下这个变量就可以
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

double myfunc(const std::vector<double>& x,std::vector<double>&grad,void* f_data )
{
    double result;//声明结果
    if (grad_bool)
    {
        grad[0] = 1 / x[0];
        grad[1] = 1 / x[1];
    }
    result = log(x[0])+log(x[1]);//计算结果
    return result;//返回结果
}

目标函数是 max(lnx1+x2)
定义目标函数 注意函数的参数的形式 是不可以变化的
参数x 是 要优化的参数向量
grad返回为此时最优化参数的梯度 就是数学模型里里 对x求偏导的结果 如果要求偏导那么 lnx1+lnx2 对x1求偏导,及1/x1 也就是 代码的 grad[0] = 1 / x[0]; 这个地方
f_data 是要传入的参数
返回值 为在一个x向量下的目标函数的值
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

double myconstraint(const std::vector<double>& x,std::vector<double>&grad,void* f_data)
{
    double *p = (double *) f_data;
    if (grad_bool)
    {
        grad[0] = p[0];
        grad[1] = p[1];
    }
    double result;//声明结果    
    result = x[0] * p[0] + x[1] * p[1] - 5;//计算结果
    return result;//返回结果
}

定义等式约束函数
数学模型的等式是:p1x1+p2x2=5
p1和p2以外部参数的方式传进来

最好的方式换种写法,这样什么样的参数格式都可以套用

typedef struct{
    double p1,p2;
}my_constraint_data;

声明要传入参数的结构体

double myconstraint(const std::vector<double>& x,std::vector<double>&grad,void* f_data)
{
    my_constraint_data *d = (my_constraint_data*)f_data;
    //double *p = (double *) f_data;
    double p1 = d->p1;
    double p2 = d->p2;
    if (grad_bool)
    {
        grad[0] = p1;
        grad[1] = p2;
    }
    double result;//声明结果    
    result = x[0] *  p1  + x[1] * p2 - 5;//计算结果
    return result;//返回结果
}

然后取参数的时候这样就可以

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

double myinconstraint(const  std::vector<double>& x,std::vector<double>&grad,void* f_data)
{
    if (grad_bool)
    {
        grad[0] = 1;
        grad[1] = -1;
    }

    double result;//声明结果    
    result = x[0]  - x[1] ;//计算结果
    return result;//返回结果
}

不等式的约束函数
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int main(int argc, char** argv) 
{
    //初始化节点
    ros::init(argc, argv, "lidar_align");

    //声明两个句柄   
    ros::NodeHandle nh;

然后就是main函数的,我是在ros下做的,所以加个节点的初始化
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //数学模型里的参数
    //double p[2]={1,2};
    my_constraint_data data = {1,2};

    //待优化 求取的参数
    std::vector<double> x{1,1};

声明数学模型里面 等式约束的 参数 my_constraint_data这个结构体在上面定义了
声明 待优化 求取的参数 1,1相当于初始化了
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //声明一个优化器
    nlopt::opt opter;

声明一个NLopt的优化器

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /*局部优化算法*/
    //opter = nlopt::opt(nlopt::LD_SLSQP,2);  //有导数
    //opter = nlopt::opt(nlopt::LN_COBYLA,2); //无导数
    /*全局优化算法*/
    opter = nlopt::opt(nlopt::GN_ISRES,2);    //无导数  是可以的   x1 = 1.66667    x2= 1.66667  fmax = 1.02165

给优化器设置使用什么优化算法,并设置因子个数,就是x的个数
优化算法在nlopt.hpp里面有, 可以从里面选择想用的

但是注意并不是所有算法都可以计算出来,例如这个数学模型有 不等式约束和等式约束的 全局优化算法里面只有ISRES可以使用

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /*优化参数的边界约束*/
    std::vector<double> lb {1,1};//注意参数的个数要对应上
    std::vector<double> ub {10000,10000};//注意参数的个数要对应上
        //设置 参数 边界
    opter.set_lower_bounds(lb);//设置参数下限
    opter.set_upper_bounds(ub);//设置参数上限

优化参数的边界约束

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /*设置优化精度*/
    double tol = 1e-8;//容差
    opter.set_xtol_rel(tol);
    opter.set_force_stop(tol);

设置优化精度
控制优化什么时候停止
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /*设置目标函数  其中目标函数是自己定义的 */
    // myfunc 是自己定义的函数名字 ,第二个参数为 可传入数据 没有数据则为NULL
    opter.set_max_objective(myfunc,NULL);

设置目标函数

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /*设置数学模型的 等式 约束 和 不等式 约束   */
    //myconstraint 是自己定义的函数名字  ,第二个参数为 可传入数据,
    opter.add_equality_constraint(myconstraint,&data,tol);
    opter.add_inequality_constraint(myinconstraint, NULL,tol);

设置数学模型的 等式 约束 和 不等式 约束
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /* 获取结果 最大值储存在f_max内 对应的向量储存在x内*/
    double f_max = -10000;
    nlopt::result res = opter.optimize(x,f_max);

执行优化计算
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 std::cout<<"x1 = " <<x[0]<<"    x2= "<<x[1]<<"  fmax = "<<f_max<<std::endl;

打印计算结果

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Result

在这里插入图片描述

相关文章
|
9天前
|
算法
基于GA遗传算法的PID控制器参数优化matlab建模与仿真
本项目基于遗传算法(GA)优化PID控制器参数,通过空间状态方程构建控制对象,自定义GA的选择、交叉、变异过程,以提高PID控制性能。与使用通用GA工具箱相比,此方法更灵活、针对性强。MATLAB2022A环境下测试,展示了GA优化前后PID控制效果的显著差异。核心代码实现了遗传算法的迭代优化过程,最终通过适应度函数评估并选择了最优PID参数,显著提升了系统响应速度和稳定性。
|
13天前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
6天前
|
算法
基于WOA鲸鱼优化的购售电收益与风险评估算法matlab仿真
本研究提出了一种基于鲸鱼优化算法(WOA)的购售电收益与风险评估算法。通过将售电公司购售电收益风险计算公式作为WOA的目标函数,经过迭代优化计算出最优购电策略。实验结果表明,在迭代次数超过10次后,风险价值收益优化值达到1715.1万元的最大值。WOA还确定了中长期市场、现货市场及可再生能源等不同市场的最优购电量,验证了算法的有效性。核心程序使用MATLAB2022a实现,通过多次迭代优化,实现了售电公司收益最大化和风险最小化的目标。
|
10天前
|
算法
通过matlab分别对比PSO,反向学习PSO,多策略改进反向学习PSO三种优化算法
本项目使用MATLAB2022A版本,对比分析了PSO、反向学习PSO及多策略改进反向学习PSO三种优化算法的性能,主要通过优化收敛曲线进行直观展示。核心代码实现了标准PSO算法流程,加入反向学习机制及多种改进策略,以提升算法跳出局部最优的能力,增强全局搜索效率。
|
6天前
|
算法
通过matlab对比遗传算法优化前后染色体的变化情况
该程序使用MATLAB2022A实现遗传算法优化染色体的过程,通过迭代选择、交叉和变异操作,提高染色体适应度,优化解的质量,同时保持种群多样性,避免局部最优。代码展示了算法的核心流程,包括适应度计算、选择、交叉、变异等步骤,并通过图表直观展示了优化前后染色体的变化情况。
|
10天前
|
算法
基于大爆炸优化算法的PID控制器参数寻优matlab仿真
本研究基于大爆炸优化算法对PID控制器参数进行寻优,并通过Matlab仿真对比优化前后PID控制效果。使用MATLAB2022a实现核心程序,展示了算法迭代过程及最优PID参数的求解。大爆炸优化算法通过模拟宇宙大爆炸和大收缩过程,在搜索空间中迭代寻找全局最优解,特别适用于PID参数优化,提升控制系统性能。
|
10天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于贝叶斯优化CNN-GRU网络的数据分类识别算法matlab仿真
本项目展示了使用MATLAB2022a实现的贝叶斯优化、CNN和GRU算法优化效果。优化前后对比显著,完整代码附带中文注释及操作视频。贝叶斯优化适用于黑盒函数,CNN用于时间序列特征提取,GRU改进了RNN的长序列处理能力。
|
12天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
36 1
|
16天前
|
存储 关系型数据库 分布式数据库
PolarDB的PolarStore存储引擎以其高效的索引结构、优化的数据压缩算法、出色的事务处理能力著称
PolarDB的PolarStore存储引擎以其高效的索引结构、优化的数据压缩算法、出色的事务处理能力著称。本文深入解析PolarStore的内部机制及优化策略,包括合理调整索引、优化数据分布、控制事务规模等,旨在最大化其性能优势,提升数据存储与访问效率。
23 5
|
8天前
|
算法 决策智能
基于遗传优化算法的TSP问题求解matlab仿真
本项目使用遗传算法解决旅行商问题(TSP),目标是在四个城市间找到最短路径。算法通过编码、选择、交叉、变异等步骤,在MATLAB2022A上实现路径优化,最终输出最优路径及距离。