Cplex是求解线性/整数规划问题的常用求解器之一(商用),而Java是应用非常广泛的程序开发语言。本文力争通过两个优化实例,描述清楚在Java语言下,如何调用Cplex高效求解线性/整数规划问题。
算例1:线性规划问题(Cplex解题器手册中一个简单例题LPex1.java)
max x 1 + 2 x 2 + 3 x 3 subject to − x 1 + x 2 + x 3 ≤ 20 x 1 − 3 x 2 + x 3 ≤ 30 0 ≤ x 1 ≤ 40 , x 2 , x 3 ≥ 0 \begin{align} \max \quad & x_1+2x_2+3x_3 \\ \text{subject to} \quad & -x_1+x_2+x_3 \leq 20 \\ \quad & x_1-3x_2+x_3 \leq 30 \\ \quad & 0 \leq x_1 \leq40,x_2,x_3\geq0 \end{align} maxsubject tox1+2x2+3x3−x1+x2+x3≤20x1−3x2+x3≤300≤x1≤40,x2,x3≥0
完整代码如下:
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);
}
}
例题2:整数规划问题
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
]
a=\begin{bmatrix} 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\\ \end{bmatrix}
a=
88471703019731004488254778
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
]
b=\begin{bmatrix} 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\\ \end{bmatrix}
b=
3771151036282579106112928210
存在以上两个二维矩阵,要求分别从两个矩阵中的每一行,选出一个元素,使得总的数值最小化,约束条件为a和b中,相同行所选定的元素对应的列,也要相同。
min ∑ i = 0 4 ( a i j x i j + b i j y i j ) subject to x i j = y i j , ∀ i , j ∑ j = 0 4 x i j = 1 , ∀ i ∑ j = 0 4 y i j = 1 , ∀ i \begin{align} \min \quad & \sum_{i=0}^{4}{(a_{ij}x_{ij}+b_{ij}y_{ij})} \\ \text{subject to} \quad & x_{ij}=y_{ij}, \quad \forall i,j \\ \quad & \sum_{j=0}^4x_{ij}=1 ,\quad \forall i \\ \quad & \sum_{j=0}^4y_{ij}=1 ,\quad \forall i \end{align} minsubject toi=0∑4(aijxij+bijyij)xij=yij,∀i,jj=0∑4xij=1,∀ij=0∑4yij=1,∀i
完整代码如下:
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) {
throw new RuntimeException(e);
}
}