基于Java的Cplex入门

2023-11-11

Cplex是一种数学优化技术。主要用于提高效率、快速实现策略并提高收益率。Cplex提供灵活的高性能优化程序,解决线性规划 (Linear Programming)、二次方程规划 (Quadratic Programming)、二次方程约束规划 (Quadratically Constrained Programming) 和混合整型规划 (Mixed Integer Programming) 问题。

在Eclipse下配置Cplex环境参考:在Ecplise下调用Cplex环境配置

一. 前言

目前基于Java的Cplex求解规划问题的文章或是教程并不算多,新手入门只能通过官方文档和别人少量的程序中总结摸索。我最近也在做规划相关的项目,在这里将我一些学习的心得和编码技巧分享给大家。

官网的界面如下图所示,大家根据自己Cplex的版本在左边选择对应版本的教程。入门时大家可以先从Getting Started with CPLEX开始,然后可以自己随便翻一翻看一看,但是我认为最重要的部分就是下面这个CPLEX Java Reference Manual,里面包含了所有API的使用方法及说明:

在这里插入图片描述
其中ilog.concert库包含了跟变量的定义相关的,例如优化变量的定义,表达式的定义等;ilog.cplex库包含了跟模型相关的,比如各类模型的定义,算法等。文档里给的API有非常多,但是常用的其实就那几个,接下来我将介绍一下Cplex编程的一般流程及常用接口。

二. Cplex入门

2.1 程序模板

Cplex程序的模板通常如下所示,我们只需要在相应的位置填写内容即可:

import ilog.concert.*;
import ilog.cplex.*;

public class Cplex{ //类的名字必须跟.java的名字一样
 
	public static void main(String[] args) {
		try {
			// 1. 创建模型
			
			// 2. 定义优化参数
			
			// 3. 设置目标函数

			// 4. 设置约束
			
			// 5. 模型求解及输出
						
		} catch (IloException e) {
			System.err.println("Concert exception caught: " + e);
		}
	}
}

2.2 创建模型

IloCplex cplex = new IloCplex(); // creat a model

2.3 定义优化参数

这里定义将要求解的优化参数,参数类型包括单个变量、一维及二维数组类型。

//1.单个变量
//1.1 实数型变量
IloNumVar x= cplex.numVar(0, 5); 
//1.2 整型变量
IloIntVar x= cplex.intVar(0, 5); 
/*括号中的参数表示变量的取值范围,例如该变量的取值范围为0≤x≤5,若不想定义范围可以设置为-Double.MAX_VALUE和Double.MAX_VALUE,表示负无穷到正无穷*/

//2. 一维数组
// 2.1 实数型变量
IloNumVar[] x = cplex.numVarArray(3, 0.0, 5.0);
// 2.2 整型变量
IloIntVar[] x = cplex.intVarArray(3, 0, 5);
/*括号中的参数表示数组的大小、最小值和最大值*/
// 2.3 每个变量设置不同的范围
double[] rg = {0,5,1,2,4,5}; //每个变量的最小值和最大值
IloNumVar[] a = new IloNumVar[3];
for(int i=0;i<3;i++)
{
	a[i] = cplex.numVar(rg[2*i], rg[2*i+1]);
}
/*这种方式就将数组中的三个变量设置了不同的取值范围,分别为0-5,1-2,4-5*/

//3. 二维数组
//3.1 实数型变量
IloNumVar[][] x = new IloNumVar[2][];
for (int i=0; i<2; i++) 
{
	x[i] = cplex.numVarArray(2, 0.0, 5.0);
}
//3.2 整型变量
IloIntVar[][] x = new IloIntVar[2][];
for (int i=0; i<2; i++) 
{
	x[i] = cplex.intVarArray(2, 0, 5);
}
/*以上这种方式定义了2行2列的变量,变量范围为0-5,若像设置不同的取值范围,按照一维数组的方式修改即可

2.4 设置目标函数及约束

目标函数一般是取一个表达式的最大值或是最小值,约束一般是设定一个表达式的取值范围,他们有一个共同点就是都需要先定义表达式,而且他们定义表达式的方式是完全相同的。

2.4.1 定义表达式

如图所示,最后四个字母为Expr的方法即为可以定义的表达式类型:

在这里插入图片描述
官方根据表达式类型的不同提供了不同的接口,包括:

接口 描述
IloIntExpr/IloNumExpr 整数/实数表达式的基本公共接口
IloLinearIntExpr/IloLinearNumExpr 整数/实数类型变量的一次线性表达式的接口
IloLQIntExpr/IloLQNumExpr 具有线性和二次项的一般表达式
IloQuadIntExpr/IloQuadNumExpr 整数/实数型二次数值表达式

大家可以根据自己表达式类型的不同选择适合自己接口形式,例如我的表达式为x1+2*x2+3*x3,属于线性类型,那么就可以一次线性表达式的接口:

//定义变量
IloNumVar[] x = cplex.numVarArray(3, -5, 5);

IloLinearNumExpr cs= cplex.linearNumExpr();
cs.addTerm(1, x[0]);
cs.addTerm(2, x[1]); 
cs.addTerm(3, x[2]);

每个接口都提供了非常多的方法,大家可以在官方文档中查看各个接口的使用方法及说明。

尽管官方为不同形式的表达式提供了不同的接口,但是存在一定的问题,比如你无法在一次线性表达式中添加二次项,当表达式比较复杂的时候通常不止有一种类型。因此我比较习惯于就用最基本的公式接口IloNumExpr,在这个接口中你可以利用cplex模型库中的加减乘除来添加任何形式表达式。

先创建模型IloCplex cplex = new IloCplex();后就可以通过cplex.XXX的方式使用模型中各种运算方法,常用的包括:

方法 说明 方法 说明
sum 求和 diff 求差
prod 乘积 abs 绝对值

有了以上这四种方法基本就可以应对大部分的表达式了,例如上面那个表达式x1+2*x2+3*x3,用基本公共接口表示为:

IloNumVar[] x = cplex.numVarArray(3, -5.0, 5.0);
					
double[] a = {1,2,3};
IloNumExpr cs = cplex.numExpr();
for(int i=0;i<3;i++)
{
	cs = cplex.sum(cs,cplex.prod(x[i], a[i]));
}

虽然这种方式增加了代码量,但是代码的可读性增强了,所以我更喜欢用这种方式定义表达式。

下面我再举一个例子,求变量x的平方和和绝对值之和:

IloNumVar[] x = cplex.numVarArray(3, -5.0, 5.0);

IloNumExpr cs1 = cplex.numExpr();
IloNumExpr cs2 = cplex.numExpr();
for(int i=0;i<3;i++)	
{
	cs1= cplex.sum(cs1,cplex.abs(x[i])); //绝对值之和
	cs2= cplex.sum(cs2,cplex.prod(x[i], x[i])); //平方和
}	

在定义了表达式之后就可以添加目标函数和约束了。

2.4.2 定义目标函数

假设定义后目标函数的表达式用obj表示:

函数 含义
cplex.addMinimize(obj) 求obj的最小值
cplex.addMaximize(obj) 求obj的最大值

2.4.3 定义约束

假设定义后约束的表达式用cs表示:

函数 含义 函数 含义
cplex.addEq(cs,a) cs=a cplex.addGe(cs,a) cs≥a
cplex.addLe(cs,a) cs≤a cplex.addRange(a,cs,b) a≤cs≤b

在添加了约束后我们可以通过cplex.diff(cs,cs)来清空表达式cs,然后就可以在cs中添加新的表达式。

2.4.4 清空表达式

有时候在定义目标函数和约束时需要通过循环来定义新的表达式,每次重新初始化表达式很麻烦,这时候就需要清空表达式:

  • cplex.diff(cs,cs)
  • cs = cplex.numExpr()

第一种方式有时候会报内存溢出的错误,因此推荐使用第二种方式。

2.5 模型求解及输出

模型求解及输出的模板如下所示:

if (cplex.solve()) {
cplex.output().println("Solution status = " + cplex.getStatus());
cplex.output().println("Solution value = " + cplex.getObjValue());
double[] val = cplex.getValues(x);
for (int j = 0; j < val.length; j++)
	System.out.println("x" + (j+1) + "  = " + val[j]);
}
cplex.end();

其中:

函数 含义
cplex.getStatus() 获得模型求解的状态
cplex.getObjValue() 获取目标函数的值
cplex.getValues(x) 获取优化变量的值
cplex.end() 结束模型

模型求解包括以下几个状态:

状态 含义 状态 含义
Optimal 找到了一个最优的解决方 Feasible 找到了一个可行的解决方案
Infeasible 该模型不可行 Error 遇到了错误
Bounded 模型不是无界的 Unbounded 模型是无界的

三. 案例展示

在这里插入图片描述

import ilog.concert.*;
import ilog.cplex.*;

public class test {
	public static void main(String[] args) {
		try {
			IloCplex cplex = new IloCplex(); // create a model
			
			IloNumVar[] x = cplex.numVarArray(3, -Double.MAX_VALUE, Double.MAX_VALUE);
			
			IloNumExpr cs1 = cplex.numExpr();
			for(int i=0;i<3;i++)
			{
				cs1 = cplex.sum(cs1,cplex.prod(x[i], x[i]));
			}
				
			cplex.addMinimize(cs1);
			
			cplex.addEq(cplex.sum(x[0], x[1]),1);
			cplex.addEq(cplex.sum(x[0], x[2]),1);
			cplex.addEq(cplex.sum(x[1], x[2]),1);
					
			if (cplex.solve()) {
				cplex.output().println("Solution status = " + cplex.getStatus());
				cplex.output().println("Solution value = " + cplex.getObjValue());
				double[] val = cplex.getValues(x);
				for (int j = 0; j < val.length; j++)
					System.out.println("x" + (j+1) + "  = " + val[j]);
			}
			cplex.end();
			
		} catch (IloException e) {
			System.err.println("Concert exception caught: " + e);
		}
	}
}

运行结果为:
在这里插入图片描述

程序比较简单这里不再做讲述,大家可以结合第二部分的内容理解一下。

总而言之,别人的程序、官方文档和官方案例是学习Cplex的最好教程,希望大家多加摸索!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Java的Cplex入门 的相关文章

随机推荐

  • windows7 64位机上,libjpeg-turbo的安装和使用

    libjpeg turbo是对libjpeg的扩展 支持SIMD指令 如X86架构的MMX SSE SSE2 3DNOW ARM架构的NEON 在对jpeg进行编码和解码的过程中能提高速度 MMX 多媒体扩展的缩写 第六代CPU芯片重要特点
  • 【Modbus】 RTU CRC校验码计算方法

    Modbus是美国Modicon公司 即现在的Schneider Electric公司 于1979年开发的一种通信协议 其目的是采用一根双绞线实现多个设备之间的通信 Modbus 协议采用问答式的通信方式 具有简单 硬件便宜 通用性强 使用
  • 2023_华为OD机试真题_Java_001_AI处理器组合

    AI处理器组合 题目描述 某公司研发了一款高性能AI处理器 每台物理设备具备8颗AI处理器 编号分别为0 1 2 3 4 5 6 7 编号0 3的处理器处于同一个链路中 编号4 7的处理器处于另外一个链路中 不通链路中的处理器不能通信 如下
  • pip 删除安装包_最新版pip用法一览

    pip 是 Python 包管理工具 该工具提供了对Python 包的查找 下载 安装 卸载的功能 熟练使用此工具 也是python的基本功 https pypi org目前最新版本为20 2 2 以下就以此版本来演示其使用 下面演示 是在
  • pytorch学习(六)---搭建简单的神经网络以及sequential的使用

    本篇自学笔记来自于b站 PyTorch深度学习快速入门教程 绝对通俗易懂 小土堆 Up主讲的非常通俗易懂 文章下方有视频连接 如有需要可移步up主讲解视频 如有侵权 实非故意 深表歉意 请与我联系 删除相关内容 本节以CIFAR10的模型结
  • emwin多语言实现的两种方式

    MCU开发中经常会涉及到多语言的制作和支持 本文将介绍两种制作字库的方法 字库的实现主要包含两部分 一是 字库 一是要显示的字符串 将这两个东西准备好 就可以实现了 第一种方法 详细的可以直接参考这篇博客 可 EMWIN 多国语言实现方法
  • 【信号采集】基于FPGA的高速信号采集系统

    1 高速采集系统实现的功能 FPGA内部功能模块组成 2 高速ADC接口的FPGA实现 3 数字下变频 DDC 的FPGA实现 4 三倍抽取功能的FPGA实现 5 Aurora接口的FPGA实现 高速采集系统的功能和组成 1 实现功能 对中
  • 《消息队列高手课》传输协议:应用程序之间对话的语言

    传输协议就是应用程序之间对话的语言 设计传输协议 并没有太多规范和要求 只要是通信双方的应用程序都能正确处理这个协议 并且没有歧义就好了 这节课 我们就来说一下设计高性能传输协议的一些方法和技巧 如何 断句 既然传输协议也是一种语言 那么在
  • CentOS8基础篇5:用户账号与用户组的创建

    一 用户与用户组概念 Linux是一个多用户 多任务的服务器操作系统 多用户多任务指可以在系统上建立多个用户 而多个用户可以在同一时间内登录同一个系统执行各自不同的任务 而互不影响 Linux用户是根据角色定义的 具体分为三种角色 超级用户
  • C++中拒绝编译器自动生成copy构造函数和copy赋值运算符操作(6)---《Effective C++》

    C 是一片荆棘遍布的雷区 等待用于挑战的你去探索 在 Effective C 系列的第5篇中我们已经看到当用户进行赋值或者拷贝操作的时候 即使我们没有定义拷贝构造函数或者拷贝赋值运算符操作 编译器也会自动为其生成copy构造函数和copy赋
  • P50发布,鸿蒙OS用户突破4000万!

    大家期盼已久的华为 P50 系列手机终于来了 7 月 29 日晚间 华为在线上举行 万象新生 为主题的旗舰新品发布会 华为旗舰新机 P50 系列正式全球发布 太难了 迟到 4 个月的 P50 发布 在今年 6 月份华为鸿蒙 2 0 发布会上
  • 基于HashHeap的LFU实现

    普通heap支持的操作和queue stack一样 就是push pop 只是pop出的是最小值 具体点就是add delMin hashheap支持一般HashMap的功能 同时维护最小值 和LinkedHashMap是对等的 后者是Ha
  • 手机开启应急预警通知 / 地震预警

    前言 安卓手机在检测到地震时 将发送地震预警通知 但此设置是默认关闭的 原因是以防引发用户恐慌从而引发安全问题 且开启此设置需要完成指引教程 因此默认关闭此设置 下文介绍如何开启此设置 开启方法 华为手机开启方法 以华为手机为例 详细介绍开
  • Metasploit渗透测试框架的基本使用

    1 Metasploit体系框架 1 基础库 metasploit基础库文件位于源码根目录路径下的libraries目录中 包括Rex framework core和framework base三部分 Rex是整个框架所依赖的最基础的一些组
  • Linux-fork(),vfork()和clone的区别

    在linux系统中 fork vfork 和clone函数都可以创建一个进程 但是它们的区别是什么呢 本文就这三者做一个较深入的分析 1 fork fork 函数的作用是创建一个新进程 由fork创建的进程称为子进程 fork函数调用一次返
  • 简单人脸检测

    1 1 Haar特征分类器介绍 Haar特征分类器就是一个XML文件 该文件中会描述人体各个部位的Haar特征值 包括人脸 眼睛 嘴唇等等 Haar特征分类器存放目录 D wsbSoft Anaconda3 envs tensorflow
  • 通过adbshell获取android的权限集合

    在Window控制台中输入如下命令可以看到Android系统中列出的所有权限 如果自定义权限注册成功 在这里也会找到这些自定义的权限 adb shell pm list permissions html view plain copy C
  • 解决Tomcat中POST方式传送参数大小限制问题

    之前我在做项目的时候遇到了这个问题 Tomcat是使用POST的方式发送请求参数 请求参数有九万多个 点击提交就没有反应了 后来查询资料知道了是请求参数过多了 超过了Tomcat的上传文件最大值2M 通过以下方法进行修改后解决了问题 在to
  • 云上城之个服务器维护时间,云上城之歌时间之塔开服时间表_云上城之歌新区开服预告_第一手游网手游开服表...

    今日开服 15 00 三十八区苍炎之门 已经开服 2021 08 10 10 00 三十八区巨石林野 已经开服 2021 08 09 15 00 三十八区荧光要塞 已经开服 10 00 三十八区雷神圣所 已经开服 2021 08 07 10
  • 基于Java的Cplex入门

    Cplex是一种数学优化技术 主要用于提高效率 快速实现策略并提高收益率 Cplex提供灵活的高性能优化程序 解决线性规划 Linear Programming 二次方程规划 Quadratic Programming 二次方程约束规划 Q