基于java语言,调用cplex求解线性/整数规划问题

目录

  • 引言
  • 简单的一维线性规划实例
    • 优化实例
    • cplex求解
    • 个人理解
  • 复杂的二维整数规划实例
    • 优化实例
    • cplex求解
    • 注意事项
  • 总结

引言

cplex是求解线性/整数规划问题的常用求解器之一,而java是应用非常广泛的程序开发语言。本文力争通过两个优化实例,描述清楚在java语言下,如何调用cplex高效求解线性/整数规划问题。

简单的一维线性规划实例

针对简单的问题,网上已有诸多实例,此处直接搬运:java调用cplex。

优化实例

优化变量为
x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3
目标函数为
m a x x 1 + 2 x 2 + 3 x 3 max \quad x_1+2x_2+3x_3 maxx1+2x2+3x3
约束条件为
− x 1 + x 2 + x 3 ≤ 20 x 1 − 3 x 2 + x 3 ≤ 40 0 ≤ x 1 ≤ 40 -x_1+x_2+x_3 \le20 \\ x_1-3x_2+x_3 \le40 \\ 0 \le x_1 \le 40 x1+x2+x320x13x2+x3400x140

cplex求解

import ilog.concert.IloException;
import ilog.concert.IloNumVar;
import ilog.cplex.IloCplex;

public class CplexExamples {

    public static void main(String[] args) {
        // cplex求解,一般都使用try...catch...
        try {
            // 声明cplex优化模型
            IloCplex cplex = new IloCplex();

            // 设定变量上下限
            double[] lb = {0.0, 0.0, 0.0};  // 下限
            double[] ub = {40.0, Double.MAX_VALUE, Double.MAX_VALUE};  // 上限
            IloNumVar[] x = cplex.numVarArray(3, lb, ub);  // 定义优化变量:IloNumVar,3维,以及对应的边界

            // 设定目标函数
            double[] objvals = {1.0, 2.0, 3.0};  // 目标函数系数
            cplex.addMaximize(cplex.scalProd(x, objvals));  // 定义目标函数:addMaximize最大化,scalProd,连乘

            // 设定约束条件
            double[] coeff1 = {-1.0, 1.0, 1.0};  // 第一组约束条件的系数
            double[] coeff2 = {1.0, -3.0, 1.0};  // 第二组约束条件的系数
            cplex.addLe(cplex.scalProd(x, coeff1), 20.0);  // 定义第一组约束条件的系数,addLe(a,b):a小于等于b
            cplex.addLe(cplex.scalProd(x, coeff2), 30.0);  // 定义第二组约束条件的系数
            
            // cplex.solve():模型求解
            if (cplex.solve()) {
                // cplex.output(),数据输出,功能类似System.out.println();
                cplex.output().println("Solution status = " + cplex.getStatus());  // cplex.getStatus:求解状态,成功则为Optimal
                // cplex.getObjValue():目标函数的最优值
                cplex.output().println("Solution value = " + cplex.getObjValue());
                // cplex.getValues(x):变量x的最优值
                double[] val = cplex.getValues(x);
                for (int j = 0; j < val.length; j++)
                    cplex.output().println("x" + (j+1) + "  = " + val[j]);
            }
            // 退出优化模型
            cplex.end();

        } catch (IloException e) {
            System.err.println("Concert exception caught: " + e);
        }
    }
}

个人理解

(1)以上实例亲测有效,可以作为程序校验的标准,用于检测cplex环境是否已经成功搭建。
(2)几乎针对每一行代码,都增加了详细的注释,对小白们更加友好。
(3)该实例不便于直接改写为大规模优化问题的求解,原因包括:多维变量如何表达,没有提及;cplex.scalProd难以直接扩展使用到复杂的约束条件和目标函数等。
(4)实例中未涉及如何高效调试cplex相关代码,不便于算法开发和维护。

复杂的二维整数规划实例

优化实例

a = [8     7     9     4     5
     8     0     7     4     4
     4     3     3     8     7
     7     0    10     8     7
     1     1     0     2     8]
     
b = [3     5     8    10     9
     7    10     2     6     2
     7     3     5     1     8
     1     6     7     1     2
     1     2     9     2    10]

存在以上两个二维矩阵,要求分别从两个矩阵中的每一行,选出一个元素,使得总的数值最小化,约束条件为a和b中,相同行所选定的元素对应的列,也要相同。

针对以上问题,定义第一组优化变量为
x i , j = 0 , 1 , i = 0 , 1 , 2 , 3 , 4 , j = 0 , 1 , 2 , 3 , 4 x_{i,j}=0,1,i=0,1,2,3,4, j=0,1,2,3,4 xi,j=0,1,i=0,1,2,3,4,j=0,1,2,3,4
其中, x i , j = 1 x_{i,j}=1 xi,j=1表示取a中第 i i i行第 j j j列的值;反之,表示不取。
定义第二组优化变量为
y i , j = 0 , 1 , i = 0 , 1 , 2 , 3 , 4 , j = 0 , 1 , 2 , 3 , 4 y_{i,j}=0,1,i=0,1,2,3,4, j=0,1,2,3,4 yi,j=0,1,i=0,1,2,3,4,j=0,1,2,3,4
其中, y i , j = 1 y_{i,j}=1 yi,j=1表示取b中第 i i i行第 j j j列的值;反之,表示不取。
目标函数可以描述为
m i n ∑ i = 0 4 ∑ j = 0 4 ( a i , j x i , j + b i , j y i , j ) min \sum_{i=0}^4\sum_{j=0}^4(a_{i,j}x_{i,j}+b_{i,j}y_{i,j}) mini=04j=04(ai,jxi,j+bi,jyi,j)
约束条件包括:针对任意 i i i j j j
x i , j = y i , j x_{i,j}=y_{i,j} xi,j=yi,j
针对每一个 i i i
∑ j = 0 4 x i , j = 1 , ∑ j = 0 4 y i , j = 1 \sum_{j=0}^4x_{i,j}=1, \sum_{j=0}^4y_{i,j}=1 j=04xi,j=1j=04yi,j=1

cplex求解

import ilog.concert.IloException;
import ilog.concert.IloIntVar;
import ilog.concert.IloLinearNumExpr;
import ilog.cplex.IloCplex;

public class CplexExamples {

    public static void main(String[] args) {
        int[][] a = {{8, 7, 9, 4, 5}, {8, 0, 7, 4, 4}, {4, 3, 3, 8, 7}, {7, 0, 10, 8, 7}, {1, 1, 0, 2, 8}};
        int[][] b = {{3, 5, 8, 10, 9}, {7, 10, 2, 6, 2}, {7, 3, 5, 1, 8}, {1, 6, 7, 1, 2}, {1, 2, 9, 2, 10}};
        try {
            // 声明cplex优化模型
            IloCplex model = new IloCplex();

            // 定义两个二维优化变量
            IloIntVar[][] x = new IloIntVar[5][5];
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 5; j++) {
                    x[i][j] = model.intVar(0, 4, "x[" + i + "," + j + "]");
                }
            }
            IloIntVar[][] y = new IloIntVar[5][5];
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 5; j++) {
                    y[i][j] = model.intVar(0, 4, "y[" + i + "," + j + "]");
                }
            }

            // 定义目标函数
            IloLinearNumExpr objExpr = model.linearNumExpr();
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 5; j++) {
                    objExpr.addTerm(a[i][j], x[i][j]);
                    objExpr.addTerm(b[i][j], y[i][j]);
                }
            }
            model.addMinimize(objExpr);

            // 定义约束条件
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 5; j++) {
                    // 第一组约束
                    model.addEq(x[i][j], y[i][j]);
                }
                // 第二组约束
                model.addEq(model.sum(x[i]), 1);
                model.addEq(model.sum(y[i]), 1);
            }

            // 优化计算,输出最优解
            if (model.solve()) {
                System.out.println("最优解为:" + model.getObjValue());
                for (int i = 0; i < 5; i++) {
                    for (int j = 0; j < 5; j++) {
                        System.out.println("x[" + i + "," + j + "]: " + model.getValue(x[i][j]));
                    }
                }
            }
            
			// 退出优化模型
            model.end();     
                   
        } catch (IloException e) {
            System.err.println("Concert exception caught: " + e);
        }
    }
}

注意事项

(1)定义优化变量时,使用for循环的方式,更加灵活。
(2)定义目标函数时,采用IloLinearNumExpr的形式,可以处理复杂的表达式。
(3)定义了变量的简称后,在model.solve前打个断点,可以很容易地看到具体的优化模型,便于校验程序,下图给出了目标函数,以及部分的约束条件。
基于java语言,调用cplex求解线性/整数规划问题_第1张图片
(4)优化最终提示无解或者优化解明显有问题时,可以通过控制变量法快速定位到问题问题的位置:逐组删除约束条件,确定是哪一组约束条件导致了错误的结果。

总结

步骤编号 具体步骤 相关命令
1 声明优化模型 IloCplex model = new IloCplex()
2 定义优化变量 目标名称:IIloIntVar [][] x = new IloIntVar[][]
变量范围:x[i][j] = model.intVar(0, 1, “x[” + i + “,” + j + “]”)
3 定义目标函数 最大化:model.addMaximize()
最小化:model.addMinimize()
4 定义约束条件 数值/表达式a,b相等:model.addEq(a,b)
数值/表达式a小于等于b:model.addLe(a,b)
数值/表达式a大于等于b:model.addGe(a,b )
3-4 3,4中常用命令 声明变量表达式:IloLinearNumExpr Expr = model.linearNumExpr()
向量a,b连乘:model.scalProd(a,b)
数值/表达式a,b相加:model.sum(a,b)
数值/表达式a,b相减:model.diff(a,b)
数值/表达式a,b相乘:model.prod(a,b)
表达式c中添加数值a与表达式b的乘积:c.addTerm(a, b)
5 退出优化模型 cplex.end()

你可能感兴趣的:(#,运筹优化,java,算法)