首页 > 编程语言 >CPLEX 初识 -- JAVA实现

CPLEX 初识 -- JAVA实现

时间:2024-05-15 09:45:11浏览次数:25  
标签:JAVA 变量 -- double CPLEX System int model data

CPLEX 初识 -- JAVA实现

本文参考《运筹优化常用模型、算法及案例实战》,同时也是笔者用来记录自己所学知识,如有问题欢迎交流讨论~

1 环境配置&模型建立

需要装配jar包及配置VM options, 如下图所示:

-Djava.library.path="/Applications/CPLEX_Studio2211/java"

一般使用IloCplex model = new IloCplex(); //建立cplex对象新建模型

2 变量

        //变量类型
//        IloNumVarType.Bool;
//        IloNumVarType.Int;
//        IloNumVarType.Float;
        //创建变量
//        model.numVar(lb, ub, type, name); //一般变量创建方法
//        model.intVar(); //创建整数变量
//        model.boolVar(); //创建0-1变量

//        model.numVarArray(); //以数组形式创建一般变量
//        model.intVarArray(); //以数组形式创建整数变量
//        model.boolVarArray(); //以数组形式创建0-1变量

3 表达式

通常由两种方法:

  • 表达式较为简单时,可以使用基本的IloModeler中的方法(例如加、减、乘、数量积等)定义。注:IloCplexs已继承该接口,故可以直接通过IloCplexs对象进行调用。
//常用表达式
//        model.sum();
//        model.prod();
//        model.scalProd(); //数组与数组之间的数量积
//        model.diff();
//        model.negative(); //乘以-1
//        model.square(); //表达式的square
  • 表达式略复杂时,使用IloNumExpr 接口IloLinearNumExpr接口中的方法定义。

4 范围约束

使用IloRange对象表示形如lb <= expression <= ub的约束。

//        IloRange rng1 = model.range(lb, expr, ub, name); //表示lb<=expr<=ub
//        IloRange rng2 = model.le(expr, ub, name); //表示 expr <= ub ~ 也可直接model.addLe();
//        IloRange rng3 = model.ge(expr, lb, name); //表示 expr >= lb ~ 也可直接model.addGe();

5 目标函数

//        IloObjective obj = model.addMaximize(expr); //方式一
//        IloObjective obj = model.add(model.maximize(expr)); //方式二

6 建模方式

该部分通过一个简单的案例,主要介绍两种建模方式:行建模与列建模

案例:在已知各种Food所含Nutrition的前提下,各样Food需买多少,以满足营养需求及各类容量约束。信息见下表:

Food 1 Food 2 Nutrition最小需求量 Nutrition最大需求量
Nutrition 1 $$a_{11}$$ $$a_{12} $$ nutrMin[1] nutrMax[1]
Nutrition 2 $$a_{21}$$ $$a_{22}$$ nutrMin[2] nutrMax[2]
Food最小数量 foodMin[1] foodMax[1]
Food最大数量 foodMin[2] foodMax[2]
Food单位成本 foodCost[1] foodCost[2]

该表使用数据结构的方式编写如下:

private static class Data {
    int nFoods; //Food总种类 ~ 决定了几个决策变量
    int nNutrs; //Nutrition总种类 ~ 决定了m条约束
    int[] foodMin; //各样food的最小数量
    int[] foodMax; //各样food的最大数量
    float[] foodCost; //各样food的成本
    int[] nutrMin; //各样Nutrition的最小需求量
    int[] nutrMax; //各样Nutrition的最大需求量
    int[][] a_ij; //Food j中含有Nutrition i的数量

    // 以下是constructor
    public Data(int[] foodMin, int[] foodMax, float[] foodCost, int[] nutrMin, int[] nutrMax, int[][] a_ij) {
        this.foodMin = foodMin;
        this.foodMax = foodMax;
        this.foodCost = foodCost;
        this.nutrMin = nutrMin;
        this.nutrMax = nutrMax;
        this.a_ij = a_ij;
        this.nFoods = foodMin.length;
        this.nNutrs = nutrMin.length;
    }
}

6.1 行建模

  • 决策变量为:\(buy[j]\)表示\(Food[j]\)买多少,是整数变量。
  • 约束条件:
    • \(Nutrition[j],j\in\{1,2,...,m\}\) 最小满足量和最大满足量要求;即 \(nutrMin[i] \leq\sum_j a_{ij}*buy_j \leq nutrMax[i], \forall i\in\{1,2,...,m\}.\)
    • \(Food[j],j\in\{1,2,...,n\}\)最小数量和最大数量要求。(可以在创建变量时直接添加)
  • 目标函数:成本最低。
// (1)行建模
static void buildModelByRow(Data data) throws IloException {
    // 新建模型
    IloCplex model = new IloCplex();
    // 变量: buy[j] j \in {1,2,...,nFoods}
    int nFoods = data.nFoods; //变量个数
    IloNumVar[] buy = new IloNumVar[nFoods]; //创建变量数组,下对变量进行具体创建
    for (int j = 0; j < nFoods; j++) {
        buy[j] = model.numVar(data.foodMin[j], data.foodMax[j], IloNumVarType.Int, "buy_j");
    }

    // 约束条件
    int nNutrs = data.nNutrs;
    for (int i = 0; i < nNutrs; i++) {
        IloLinearNumExpr expr = model.scalProd(data.a_ij[i], buy); //\sum_j a_ij*buy_j
        model.addRange(data.nutrMin[i],expr,data.nutrMax[i]);
    }

    // 目标函数
    model.addMinimize(model.scalProd(data.foodCost,buy));
}

6.2 列建模

​ 按列添加本质上是添加变量,在添加的过程中需要考虑:1. 对目标函数的影响。2. 对约束的影响。实现过程如下:

  1. 使用model.column(IloObjective,coefficient)向该列添加对应的目标函数系数,返回一个列对象col1
  2. 使用model.column(IloRange constraint[i],double val)向该列添加对应的约束的系数,同样返回一个列对象col2
  3. 之后通过col = col1.and(col2)将两列对象进行”连接“,完成对目标函数和约束的更新。
  4. 使用model.numVar(IloColunmn col, double lb, double ub, IloNumVarType type)为以上创建的列col设置对应的变量(其中需要输入上下界及变量类型)。
// (2)列建模
static void buildModelByColumn(Data data) throws IloException {
    // 新建模型
    IloCplex model = new IloCplex();
    // 创建m条约束 和 n个变量
    int nNutrs = data.nNutrs;
    IloRange[] constraints = new IloRange[nNutrs]; // m条约束
    IloNumVar[] buys = new IloNumVar[data.nFoods]; // n个变量
    for (int i = 0; i < nNutrs; i++) { // 对约束设置上下界
        constraints[i] = model.addRange(data.nutrMin[i],data.nutrMax[i]);
    }

    // 向约束和目标函数中加入对应的系数,并创建变量
    IloObjective cost = model.addObjective(null);
    for (int j = 0; j < data.nFoods; j++) { //加n条列
        IloColumn col_j = model.column(null); //j对应的列对象,后需要由obj+cons合成
        IloColumn col_obj = model.column(cost, data.foodCost[j]);
        for (int i = 0; i < nNutrs; i++) {
            IloColumn col_constaints_i = model.column(constraints[i], data.a_ij[i][j]);
            col_j = col_obj.and(col_constaints_i);
        }
        // 对新加的列 创建变量
        buys[j] = model.numVar(col_j, data.foodMin[j], data.foodMax[j]);
    }
}

6.3 案例练习

编译实现如下线性规划:

\[\begin{alignat}{2} \max \quad &x_1+2x_2+3x_3 \tag{1} \\ \mbox{s.t.}\quad &-x_1+x_2+x_3\leq 20 \tag{2}\\ &x_1-3x_2+x_3\leq30 \tag{3} \\ &0\leq x_1\leq40, x_2,x_3\geq 0. \tag{4} \end{alignat} \]

代码如下:

//3 案例练习
static void practice() throws IloException {
    // 创建模型, 输入系数
    IloCplex model = new IloCplex();
    double[] obj_coeffs = {1.0, 2.0, 3.0};
    double[] v_lb = {0.0, 0.0, 0,0};
    double[] v_ub = {40.0, Double.MAX_VALUE, Double.MAX_VALUE};

    // Step1 变量
    String[] x_name = {"x_1","x_2","x_3"};
    IloNumVar[] x = model.numVarArray(3, v_lb, v_ub,x_name);

    // Step2 约束
    int m = 2; //两条约束
    double[][] a = {{-1, 1, 1}, {1, -3, 1}}; //变量前系数 A = [a_ij]
    double[] b = {20,30};
    for (int i = 0; i < m; i++) {
        model.addLe(model.scalProd(a[i],x),b[i]);
    }
    // Step3 目标函数
    model.addMaximize(model.scalProd(obj_coeffs,x));
}

7 模型求解及输出

7.1 求解

model.solve()

7.2 解状态

IloCplex.Status status = model.getStatus();
System.out.println(status);

解类型如下:

  • Bounded
  • Unbounded
  • Feasible
  • Infeasible
  • InfeasibleOrUnbounded
  • Error
  • Unknown
  • Optimal

7.3 获取obj、变量、约束相关信息

(1)获取obj_value

double objValue = model.getObjValue();
System.out.println("obj_value = " + objValue);

(2)获取变量值:单个/多个

double x_0_value = model.getValue(x[0]);//获取单个变量值
System.out.println("x_0 = " + x_0_value);

double[] x_values = model.getValues(x);//获取多个变量值
        for (int i = 0; i < x_values.length; i++) {
            System.out.println("x_" + i + " = " + x_values[i]);
        }

(3)获取变量对应的reduced cost

double[] reducedCosts = model.getReducedCosts(x);
System.out.print("Reduced Costs = ");
for (double r_c: reducedCosts) {
    System.out.print(r_c + "  ");
}
System.out.println();

(4)获取约束对应的松弛变量

double[] slacks = model.getSlacks(consts);
System.out.print("Slack Variables = ");
for (double s : slacks) {
    System.out.print(s + "  ");
}
System.out.println();

(5)获取约束对应的对偶变量

double[] duals = model.getDuals(consts);
System.out.print("Dual Variables = ");
for (double d : duals) {
    System.out.print(d + "  ");
}
System.out.println();

(6)获取模型/对偶模型的极射线

//        model.getRay();
//        model.dualFarkas();

(7)模型导出导入

model.exportModel("practice.lp"); //导出
model.importModel("practice.lp"); //导入

运行结果如下:

模型导出结果:

8 参数

官方介绍:https://www.ibm.com/docs/zh/icos/12.10.0?topic=cplex-list-parameters

此处待补充具体常用参数。(后续补充)

写在最后

Like a city that is broken down and without walls is a man whose spirit is without restraint.

标签:JAVA,变量,--,double,CPLEX,System,int,model,data
From: https://www.cnblogs.com/shalom-/p/18192768

相关文章

  • ts中的type 和 interface 区别
    type可以用来给一个类型起个新名字,当命名基本类型或联合类型等非对象类型时非常有用,而接口不行typeMyNumber=number;typeStringOrNumber=string|number;typeText=string|string[];2类型别名通过&(交叉运算符)来扩展,而接口通过extends的方式来扩展。都可以......
  • D. Powerful array
    https://codeforces.com/contest/86/problem/D题意:n个数,m个查询。每个查询给出一个区间,查询的结果是区间内每个数出现次数的平方*该数的总和。思路:莫队算法。分块,查询排序,输出。总结:莫队算法适用于离线的情况,他的原理是将查询按左端点分块,块的大小是数量的开平方。然后对查询进......
  • asp.net core 跨域
    missingalloworiginheaderasp.netcore在ASP.NETCore中,出现"missingalloworiginheader"错误通常是由于跨域资源共享(CORS)未正确配置所致。该错误的原因是客户端(如浏览器)尝试从不同的域或端口请求资源,而这些资源的访问被服务器限制。为了解决这个问题,你可以使......
  • 腾讯面试:什么锁比读写锁性能更高?
    在并发编程中,读写锁ReentrantReadWriteLock的性能已经算是比较高的了,因为它将悲观锁的粒度分的更细,在它里面有读锁和写锁,当所有操作为读操作时,并发线程是可以共享读锁同时运行的,这样就无需排队执行了,所以执行效率也就更高。那么问题来了,有没有比读写锁ReentrantReadWriteLock......
  • “事后诸葛亮”分析
    我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述?我们的软件是设计一个图书管理系统软件,解决整个图书馆的书籍管理和用户借阅书籍等问题。我们软件的用户群体是学校的全体师生,数据是图书馆的书籍、用户和管理员的信息,对于软件的定位十分明确。......
  • 使用Git命令从本地上传到码云
    Gitee创建仓库内没有内容本地:初始化Git仓库:gitinit提交文件到暂存区:gitadd.//.表示提交所有文件提交文件到工作区:gitcommit-m"此次提交的描述,简介明了的描述"关联码云仓库:gitremoteaddoriginhttps://gitee.com/xxxx/xxxxx.git推送到远程仓库:gitpush-uorigin......
  • openGauss\postgreSQL数据库性能查看
    1.查看系统CPU使用率sar-u-f/var/log/sa/sa27(sa27根据时间变化,sa27是27号信息的记录)结果输出:15时52分01秒CPU%user%nice%system%iowait%steal%idle15时53分01秒all0.320.000.690.000.0098.9915时54分01秒all0.300.000.680.000.0099.0215时55......
  • next-元数据创建、更新 SEO 优化
    在创建Next.js项目时,根页面会自动生成一个metadata对象,其中包含标题和描述等关键信息。每当页面被访问时,这个metadata对象会被读取并应用到HTML的默认配置中,确保页面的基本信息得以正确展示。在存在单独页面需要采用独特的标题或描述时,这些特定页面的元数据将优先于根元素所设定的......
  • Alpha阶段复审改进
    这个课程属于哪个课程软件工程2024-双学位这个作业要求在哪里团队作业6————复审与事后分析这个作业的目标完成项目的复审和事后分析其他参考文献无Alpha阶段复审小组的名字和连接优点缺点,bug报告最终名次梅中一团队完成了移动端的一些页面......
  • JAVA爬虫使用Selenium自动翻页
    关于Maven<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.15.3</version></dependency><dependency><groupId>org.seleniumhq.selenium</groupId>......