Java调用Cplex的基础简单教程

介绍

简单案例

官网给的例子

public class MyTest {

/**  
 * max z = 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[]{40, 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();  
}

相信大家通过注释和自己的理解应该能看出大概求解流程,当然上面的还只是简单案例


案例总结

  • Cplex 求解器的构成:
    1. 决策变量的定义
    2. 目标函数的形式
    3. 约束条件的表达

Cplex 的常用 api

变量定义

  • IloNumVar(IloIntVar)模型需要求解的决策变量

eg:创建三个连续(离散)变量,lb 和 ub 是变量取值的上限和下限。

IloNumVar[] x = cplex.numVarArray(3, lb, ub);

  • IloNumExpr(IloIntExpr)模型的中间变量。通常是关于决策变量的表达式

eg: 对于 x 0 + 2 x 1 + 3 x 2 x_0 + 2x_1+ 3x_2 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: 形如 l b < = e x p r < = u b lb <= expr <= ub lb<=expr<=ubcplex.addLe(10, x1) 表示的就是 x 1 ⩾ 10 x_1\geqslant10 x110cplex.addEq(double arg0,IloNumExpr arg1): 返回值为 IloRange,即 a r g 0 ⩽ a r g 1 ⩽ a r g 0 arg_0 \leqslant arg_1 \leqslant arg_0 arg0arg1arg0 。也就是 arg1 的值取值为 arg0,相当于赋了一个常数。

  • IloObjective :模型的优化目标。cplex.addMaximize()和 cplex.addMinimize()的返回值。

eg : 最小化(最大化)目标函数。
对于求表达式 x 1 + 2 x 2 + 3 x 3 x_1 + 2x_2 + 3x_3 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))


常用方法

  • 加法cplex.sum();

  • 减法cplex.diff();

  • 乘法cplex.prod();

  • 除法cplex.prod(); 计算除法的方法和乘法的一致,也就是将除法转化为乘法。比如 C=A/B 就可以转化为 A=B * C.

  • 累加求和cplex.scalProd(INumExpr[], double[]);有关括号里的参数类型需要根据具体问题具体分析。

eg:对于 x 1 + 2 x 2 + 3 x 3 + 4 x 4 x_1+2x_2+3x_3+4x_4 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);


约束方程的表达

  • 不等式约束cplex.addLe();

eg: 对于不等式约束 − x [ 0 ] + x [ 1 ] + x [ 2 ] < = 20.0 -x[0] + x[1] + x[2] <= 20.0 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: 对于等式约束 x 0 = = x 1 x_0==x_1 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 + ")"); 
}

数字表达式的分段线性组合

  • 分段线性函数的表达cplex.pieceiwiseLinear()

eg:表示一个分段线性函数: 当 x ⩽ 100 , 斜率为 1 ; 100 ⩽ x ⩽ 200 ,斜率为 2 ; x > 200 , 斜率为 − 3 当x\leqslant100,斜率为1;100\leqslant x \leqslant200,斜率为2;x>200,斜率为-3 x100,斜率为1100x200,斜率为2x>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);

求解模型

  • IloCplex.solve()精确求解

  • IloCplex.solveRelaxed()松弛求解

  • IloCplex.getStatus()针对于模型无界或者不可行的情况,可调用该方法得到模型解的状态。


输出格式

  • 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或者其他情况。


常见异常

  • 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]);
}

tips

  • 当我们发现编译通过了,但是求解的结果是不可行(不可行指的是不存在满足所有约束、界限和整数性限制的解)或者无界(无界指的是可以使目标函数任意大)的状态。
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值