JAVA for Cplex(更新版)
一、Cplex的介绍
Cplex是一种专门用来求解大规模线性规划问题的求解工具。不仅仅是LP问题,对于二次规划 QP,二次有约束规划QCP,混合整数线性规划MIP问题,甚至Network Flow问题,都是很
好的求解工具。官网https://www.ibm.com/cn-zh/products/ilog-cplex-optimization-studio中有关于Cplex简单的介绍。Cplex的优势在于:
1、 能解决一些非常困难的行业问题;
2、 求解速度非常快。
3、 在Cplex的支持下,使得matlab对于大规模的问题,以及线性规划的效率都有很多大的提升。
二、Cplex的使用环境
本文中以eclipse为开发环境,代码的是使用java语言。
三、Cplex的简单案例。
3.1 Cplex求解器的构成。
先看一个官网给的例子。
代码:
'''
public class MyTest {
/**
* obj = x1 + 5x2 + 1x3
* -x1 + x2 + x3 <=56;
* x1 - 3x2 + x3 <= 39;
* 0 <= x1 <= 40;
* 0 <= x2, x3
* @throws IloException
*/
public static void main(String[] args) throws IloException {
IloNumVarType varType = IloNumVarType.Float;
int varNum = 3;
IloCplex cplex = new IloCplex();
//决策变量申明
IloNumVar [] vars = new IloNumVar[varNum];
double[] xishu = new double[]{1,5,1};
double[] mins = new double[]{0,0,0};
double[] maxs = new double[]{30,Double.MAX_VALUE,Double.MAX_VALUE};
for (int i = 0; i < vars.length; i++) {
vars[i] = cplex.numVar(mins[i], maxs[i],varType);
}
//目标函数
cplex.addMaximize(cplex.scalProd(vars, xishu));
//约束条件
cplex.addLe(cplex.sum(cplex.prod(1.0, vars[0]), cplex.prod(1.0, vars[1]), cplex.prod(1.0,vars[2])), 56);
cplex.addLe(cplex.sum(cplex.prod(1.0, vars[0]), cplex.prod(-3.0, vars[1]), cplex.prod(1.0,vars[2])), 39);
if(cplex.solve()){
cplex.output().println("Solution status = " + cplex.getStatus());
cplex.output().println("Solution value = " + cplex.getObjValue());
double[] val = cplex.getValues(vars);
int ncols = cplex.getNcols();
for (int j = 0; j < ncols; ++j)
cplex.output().println("Column: " + j + " Value = " + val[j])
}
cplex.end();}
运行结果:
以上代码实现了求目标函数在不等式约束条件下的最优解。由运行结果可以看出该线性规划问题的最优值是280,最优解x1,x2,x3的值分别是0,56,0。
总结一下,Cplex求解器的构成主要有三大部分:(1)决策变量的定义;(2)目标函数的形式;(3)约束条件的表达。这三部分是我们需要关注的重点,如果正确地表达出来,那
么我们便能利用Cplex求解任何的线性规划问题。简单地介绍一下,代码中IloNumVar [] vars = new IloNumVar[varNum];这里定义的是一个连续变量的数组,数组大小为
varNum。数组中存放的是决策变量x1,x2,x3. cplex.addMaximize()方法用于输入目标函数的形式,比如obj = 1x1 + 5x2 + 1*x3,我们可以这样表达
cplex.addMaximize(cplex.scalProd(vars, xishu));其中,cplex.scalProd()是一个先乘后加的方法。对于约束条件而言,不等式约束常常用cplex.addLe()方法。
四、Cplex的使用
4.1 变量定义
● IloNumVar(IloIntVar) :模型需要求解的决策变量。
eg:创建三个连续(离散)变量,lb和ub是变量取值的上限和下限。
IloNumVar[] x = cplex.numVarArray(3, lb, ub);
● IloNumExpr(IloIntExpr):模型的中间变量。通常是关于决策变量的表达式。
eg: 对于x0 + 2x1+3x2,cplex中写为:
IloNumExpr expr = cplex.sum(x[0], cplex.prod(2.0, x[1]),cplex.prod(3.0, x[2]))。
● IloRange : 模型的变量的约束范围。cplex.addLe()和cplex.addEq()的返回值.通常在添加约束的时候用到。
eg: 形如 lb <= expr <= ub,cplex.addLe(10, x1)表示的就是x1>=10。cplex.addEq(double arg0,IloNumExpr arg1): 返回值为IloRange,即arg0<=arg1<=arg0。也
就是arg1的值取值为arg0,相当于赋了一个常数。
● IloObjective :模型的优化目标。cplex.addMaximize()和cplex.addMinimize()的返回值。
eg : 最小化(最大化)目标函数。对于求表达式x1 + 2x2 + 3x3的最小值,cplex中写为(一种写法):
cplex.addMinimize(cplex.sum(x1,cplex.prob(2,x2),cplex.prob(3,x3))).另一种写法:double[] objvals = {1.0, 2.0, 3.0};
cplex.addMinimize(cplex.scalProd(x, objvals))。
4.2 常用方法
● 加法:cplex.sum();
● 减法:cplex.diff();
● 乘法:cplex.prod();
● 除法:cplex.prod();计算除法的方法和乘法的一致,也就是将除法转化为乘法。比如C=A/B就可以转化为A=B*C.
● 累加求和:cplex.scalProd(INumExpr[], double[]);有关括号里的参数类型需要根据具体问题具体分析。
eg:对于x1+2x2+3x3+4x4,cplex中写为:
double[] objvals = {1.0, 2.0, 3.0,4.0};
IloIntVar[]x=cplex.intVarArray(4,lb1,ub1);
cplex.scalProd(x, objvals);
● 平方cplex.square();
● 创建一个0-1变量:cplex.boolVar();
eg:若想定义一个取值为0或1的变量,cplex写为:IloIntVar y=cplex.boolVar();此时y的取值只能是0或1。
● 创建一个数组:cplex.numVarArray(),类似的还有,cplex.intVarArray(),cplex.boolVarArray,cplex.numExprArray()等等;
eg:创建一个包含8个变量的数组,上限为lb,下限为ub、cplex中写为:
IloNumVar[] x = cplex.numVarArray(8, lb, ub);
4.3约束方程的表达
● 不等式约束cplex.addLe();
eg: 对于不等式约束-x[0] + x[1] + x[2] <= 20.0,cplex中写为:
cplex.addLe(cplex.sum(cplex.negative(x[0]), x[1], x[2]), 20);
● 等式约束 cplex.addEq();
eg: 对于等式约束x0==x1,则可以用cplex.addEq(x0,x1)。
● cplex能接受的非线性表达式
1、 min和minl:多个数字表达式的最小值;
2、 max和maxl:多个数字表达式的最大值;
3、 abs:数字表达式的绝对值;
● 线性表达式:cplex.linearNumExpr();
eg: 创建一个线性表达式,求出一数组所有元素的总和。cplex写为:IloNumVar [][] x=new IloNumVar [][] x=new IloNumVar[20][30];
for(int i=0; i < 10; i++) {
IloLinearNumExpr summer=cplex.linearNumExpr();//默认为null.
for(int j=0; j < 10; j++) {
summer.addTerm(1.0, x[i][j]);
}
IloRange con = cplex.addEq(summer, 1);
con.setName("yourConstraintName(" + i + ")");
}
4.4数字表达式的分段线性组合
分段线性函数的表达:cplex.pieceiwiseLinear()
eg:表示一个分段线性函数:当x<=100,斜率为1;100<=x<=200,斜率为2;x>200,斜率为-3。代码实现:
IloNumVar x=cplex.numVar(-Double.MAX_VALUE, Double.MAX_VALUE);//定义一个实数范围内的x
double [] points={100,200};//两个分割点
double []slopes={1,2,-3};//斜率
IloNumExpr fx=cplex.piecewiseLinear(x1, points, slopes, 0, 300);
4.5求解模型
● IloCplex.solve():精确求解
● IloCplex.solveRelaxed():松弛求解
● IloCplex.getStatus():针对于模型无界或者不可行的情况,可调用该方法得到模型解的状态。
4.6输出格式
● cplex.output().println():cplex中的打印格式。
eg:
cplex.output().println("Solution status = " + cplex.getStatus());
cplex.output().println("Solution value = " + cplex.getObjValue());
● cplex.getObjValue(): 得到目标函数的最值。
● cplex.getValue(): 得到最优目标函数值所对应的最优解x,即决策变量的值。
● cplex.getstatus(): 返回optimal或者其他情况。
4.7 常见的异常
● java.lang.NullPointerException:空指针异常
空指针就是空引用,java空指针异常就是引用本身为空,却调用了方法,这个时候就会出现空指针异常。因为我们在定义一个中间变量IloNumExpr的时候,我们没有对其初始化,又
因该表达式默认是为null,所以,我们有必要为此类变量指定其存储数据的上下限。否则就会产生空指针异常。通常的做法是创建两个变量,一个作为下限,一个作为上限。指定上
限和下限的值,并令上文提到的变量处于上限和下限之间即可。举个例子,以下代码定义了EES_t数组变量的上下限变量lEES_t,uEES_t。然后指定其值分别是0,1000。最后通过
cplex.numVarArray()方法使得数组变量EES_t存储数据的取值范围处于0~1000。
int R1,R2=10;
double[][] lEES_t = new double[R1][R2];
double[][] uEES_t = new double[R1][R2];
for (int i = 0; i < R1; i++) {
for (int j = 0; j < R2; j++) {
lEES_t[i][j] = 0;
uEES_t[i][j] = 1000;
}
}
for (int i=0; i<R1; i++) {
EES_t[i] = cplex.numVarArray(R2, lEES_t[i], uEES_t[i]);
}
五、小结
对比于lingo,Yalmip,guaobi,Cplex展现出了其独特的优势,比如运行速度快,在求解大规模问题上略胜一筹。它提供了python,java,c++等各大编程软件的API,是一款值得一用
的工具。关于Cplex建模的问题,当我们将实际问题建模,并转化为数学公式后,然后将公式写入Cplex的搭好的框架中,求解就很简单了。对于不同的线性或是非线性规划问题模
型,Cplex会依据目标函数的形式以及约束方程去判断模型是属于哪一种规划问题,这一方面显示出了其独特的优势。但Cplex也并非有足够地智能。当我们发现编译通过了,但是求
解的结果是不可行(不可行指的是不存在满足所有约束、界限和整数性限制的解)或者无界(无界指的是可以使目标函数任意大)的状态时,优化器只会告知不可行,我们往往不知道
不可行性的原因是什么。对于小型的模型而言,通过调参排查问题可以解决,但是对于大型的模型,一步一步排查约束条件,变量的范围是否规范等等就会显得力不从心了。当然,
Cplex仍然是一个很强大的工具,有待开发和利用。
六、相关资源
Cplex的官方链接如下:
这里包含更加全面的文档资源,供我们参考学习。另外还有运筹优化技术论坛:
]()https://www.optimize.fun/forum.php?mod=forumdisplay&fid=53。
里面有很多的Cplex环境配置问题以及开发中可能会遇到的技术问题的探讨与解答。覆盖的领域范围也比较广泛,涉及交通物流,电力,供应链等等经典的优化问题。
JAVA for Cplex(更新版)的更多相关文章
- 探索Antlr(Antlr 3.0更新版)
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明 http://www.blogbus.com/dreamhead-logs/10756716.html <探索Antlr> ...
- Rsession让Java调用R更简单
Rsession让Java调用R更简单 R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大. R语言作为统计学一门语言,一直在小众领域闪耀着光芒. ...
- Windows 7 Ultimate(旗舰版)SP1 32/64位官方原版下载(2011年5月12日更新版)
MSDN于2011年5月12日,最新发布简体中文Windows 7 Ultimate 旗舰版 SP1 DVD镜像安装包,分32位和64位两个版本.最新发行代号分别是:677486(32位),67740 ...
- 微软开放技术发布针对 Mac 和 Linux 的更新版 Azure Node.JS SDK 和命令行工具
发布于 2013-12-04 作者 Eduard Koller 这次为我们使用Linux 的朋友带来了更多关于部署云上虚拟机的消息.今天,微软开放技术有限公司 (MS Open Tech),想与大家分 ...
- (转载)Windows 7 Ultimate(旗舰版)SP1 32/64位官方原版下载(2011年5月12日更新版)
MSDN于2011年5月12日,最新发布简体中文Windows 7 Ultimate 旗舰版 SP1 DVD镜像安装包,分32位和64位两个版本.最新发行代号分别是:677486(32位),67740 ...
- macOs升级到10.13.1Beta || JAVA升级到最新版之后PhpStorm菜单栏问题
macOs升级到10.13.1Beta || JAVA升级到最新版之后PhpStorm菜单栏会消失,估计不止出现在PhpStorm,一系列jetbrains的产品可能都会有这个问题,包括eclipis ...
- 最简单的基于FFmpeg的视频编码器-更新版(YUV编码为HEVC(H.265))
===================================================== 最简单的基于FFmpeg的视频编码器文章列表: 最简单的基于FFMPEG的视频编码器(YUV ...
- Elasticsearch .net client NEST使用说明 2.x -更新版
Elasticsearch .net client NEST使用说明 目录: Elasticsearch .net client NEST 5.x 使用总结 elasticsearch_.net_cl ...
- Win 10更新版1709有哪些新功能值得关注!
windows 10秋季创意者更新版1709发布已经有段时间了,也有很多用户选择升级这次更新的系统.那么,这次Win 10 更新版1709有哪些新功能值得关注呢?下面,一起随主机吧来看一看吧! 1. ...
- 胡小兔的NOIP2017游记【出成绩后更新版】
胡小兔的NOIP2017游记[出成绩后更新版] 2017.11.22 Update 前几天成绩出来啦,看这篇博客访问量还挺多的,下面就分享一下结果吧: 我的Day1T2和Day2T1两道最水的题都跪了 ...
随机推荐
- 微信支付or支付宝支付调用流程图
微信支付or支付宝支付调用流程图 支付宝小程序支付调用流程https://opendocs.alipay.com/mini/03l735 微信H5支付调用流程https://pay.weixin.qq ...
- 实验一:Wireshark工具的使用
1.0 [实验目的] 了解Wireshark.TCP协议的概念,掌握Wireshark抓包工具的使用.FTP的搭建和登录,学会对Wireshark抓包结果的分析. 2.0[知识点] Wireshark ...
- 如何免费在 arm 官网上下载合适的手册
背景 有时候搞底层配置的时候(尤其是uboot),需要查阅文档. 这里介绍如何在arm 官网进行查找下载,这样就可以不用去 CSDN 了. 实际上CSDN上的一些文档就是这样下载下来二次收费的,强烈谴 ...
- Linux上快速安装 RabbitMQ
1.默认安装最新版,安装erlang apt-get install erlang 2.安装最新版 rabbitmq sudo apt-get update sudo apt-get install ...
- 面试官:Java类是如何被加载到内存中的?
面试连环call Java类是如何被加载到内存中的? Java类的生命周期都有哪些阶段? JVM加载的class文件都有哪些来源? JVM在加载class文件时,何时判断class文件的格式是否符合要 ...
- SpringBoot排查自动装配、Bean、Component、Configuration配置类
排除自动装配AutoConfiguration @SpringBootApplication( exclude = { DataSourceAutoConfiguration.class, Mybat ...
- influxdb得导出与导入
转载请注明出处: 1.备份元数据 基本语法: influxd backup <path-to-backup> 备份元数据,没有任何其他参数,备份将只转移当前状态的系统元数据到path-to ...
- UE4 WebUI使用指南2-通信
前面一篇WebUI的文章讲述的WebUI插件的下载,开启,在UE中创建,加载网页等. 本文继续讲述通过WebUI,UE和网页实现双向通信的实现思路. 一点说明 由于WebUI 使用的浏览器内核并不是最 ...
- vs2019如何自动生成有下划线前缀的字段名?
vs2019代码自动完成功能非常强大,今天要说的是根据构造函数的参数自动生成字段的事儿. 下图所示,IDE可以根据构造函数的参数自动生成私有字段 这个功能非常好,代码编写效率大大提升,生成的代码如下: ...
- TIER 1: Responder
TIER 1: Responder Active Directory Active Directory(AD)是由微软开发的目录服务,用于在网络环境中管理和组织用户.计算机.应用程序和其他资源.它是 ...