C语言如何使用MindOpt建模并求解混合整数线性规划问题

简介: MindOpt是达摩院决策智能实验室研究的一款优化求解器,能帮助做方案设计、生产方案优化、资源合理分配、辅助决策等。可以支持命令行、c、c++、java和python调用,目前求解算法实现了线性规划、混合整数线性规划、二次规划。

下文我们将讲述小编对线性规划的理解以及展示两个算例,和使用 MindOpt C 语言的 API 来建模以及求解 混合整数线性规划示例 中的问题。

(混合整数线性规划定义、算数例题都是与前文python语言的混合整数线性规划问题是一致的,已经阅读了前文可以忽略,直接点击目录进阶算例阅读建模优化代码。)


MindOpt Python、C、C++语言求解LP、MILP、QP问题系列


下载安装

用户可以点这里下载安装MindOpt优化求解器,免费的。找不到安装步骤点这里

(官网https://opt.aliyun.com有更多信息等着您哟!)


混合整数线性规划

我个人认为混合整数线性规划线性规划的区别在于,线性规划求解目标函数最优值的时候,决策变量是连续的,即可以是整数也可以是小数,但混合整数线性规划可能会有一个或者多个变量必须为整数。

比如经典的背包问题:桌子上有一组物品,每个物品有自己的价值和重量,但是包的承重是有限的;我们要装什么物品,在包的重量承受范围内,包里总物品的价值最高?这个里面选择那个物品就是个整数,并不能是小数切开,比如一个吹风机不能切开只带一半走。

数学形式下的混合整数线性规划问题:

image.png

混合整数线性规划很多时候会更难求解。在求解的时候,可以用分支定界法、割平面法等,会切分成子问题调用线性规划(LP)求解模块。MindOpt在今年也发布了混合整数线性规划(MILP)的求解能力。接下来我会举个例子如何使用。



案例

和上篇 线性规划 一样,我们对于混合线性规划问题示例 做一个假设,把它当作一个生活中实际的例子,而不是数学公式这么抽象。

假设工厂有一种原材料,可以生产多种零件毛坯,但每种零件的生产方式也有多种,每种生产零件的方式可以得到不同零件的毛坯数以及每种零件的需要量,但需要其中一种零件生产必需为整数,那么要怎么生产才能达到零件所需要的数量,所花费的原材料又最少。

image.png


数学算例

混合整数线性规划问题示例:

image.png

C语言+MindOpt代码实现

核心使用的几个APIs是:

MDO_CHECK_CALL(Mdo_createMdl(&model))
MDO_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, MDO_YES))
MDO_CHECK_CALL(Mdo_addRow(model, 1.0, MDO_INFINITY, 4, row1_idx, row1_val, "c0"));
MDO_CHECK_CALL(Mdo_addRow(model, 1.0, 1.0,          3, row2_idx, row2_val, "c1"));
MDO_CHECK_CALL(Mdo_solveProb(model));
Mdo_displayResults(model);

#关于更多API的详细使用方式,请参考C 接口函数

下面是完整的例子,可复制存为MdoMiloEx1.c文件。

#include <stdio.h>/*引入头文件*/#include "Mindopt.h"/* 检查返回码的宏 */#define MDO_CHECK_CALL(MDO_CALL)                                    \code = MDO_CALL;                                                \if (code != MDO_OKAY)                                           \{                                                               \Mdo_explainResult(model, code, str);                        \Mdo_freeMdl(&model);                                        \fprintf(stderr, "===================================\n");   \fprintf(stderr, "Error   : code <%d>\n", code);             \fprintf(stderr, "Reason  : %s\n", str);                     \fprintf(stderr, "===================================\n");   \return (int)code;                                           \}intmain(void)
{
/* 变量 */charstr[1024] = { "\0" };
MdoMdl*model=NULL;
MdoResultcode=MDO_OKAY;
MdoStatusstatus=MDO_UNKNOWN;
constintrow1_idx[] = { 0,   1,   2,   3   };
constdoublerow1_val[] = { 1.0, 1.0, 2.0, 3.0 };
constintrow2_idx[] = { 0,    2,   3   };
constdoublerow2_val[] = { 1.0, -1.0, 6.0 };
/*------------------------------------------------------------------*//* Step 1. 创建模型并更改参数。               *//*------------------------------------------------------------------*//* 创建一个空模型。 */MDO_CHECK_CALL(Mdo_createMdl(&model));
/*------------------------------------------------------------------*//* Step 2. 输入模型。                                             *//*------------------------------------------------------------------*//* 改成最小化问题。 *//*通过 Mdo_setIntAttr() 将目标函数设置为 最小化 */MDO_CHECK_CALL(Mdo_setIntAttr(model, MDO_INT_ATTR_MIN_SENSE, MDO_YES));
/* 添加变量。 *//*调用 Mdo_addCol() 来添加四个优化变量,定义其下界、上界、名称和类型*/MDO_CHECK_CALL(Mdo_addCol(model, 0.0, 10.0,         1.0, 0, NULL, NULL, "x0", MDO_YES));
MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x1", MDO_YES));
MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x2", MDO_YES));
MDO_CHECK_CALL(Mdo_addCol(model, 0.0, MDO_INFINITY, 1.0, 0, NULL, NULL, "x3", MDO_NO));
/* 添加约束。* 请注意,这里的非零元素是按行顺序输入的。*调用 Mdo_addRow() 来输入约束*/MDO_CHECK_CALL(Mdo_addRow(model, 1.0, MDO_INFINITY, 4, row1_idx, row1_val, "c0"));
MDO_CHECK_CALL(Mdo_addRow(model, 1.0, 1.0,          3, row2_idx, row2_val, "c1"));
/*------------------------------------------------------------------*//* Step 3. 解决问题并填充结果。               *//*------------------------------------------------------------------*//* 调用 Mdo_solveProb() 求解优化问题,并通过 Mdo_displayResults() 查看优化结果 */MDO_CHECK_CALL(Mdo_solveProb(model));
Mdo_displayResults(model);
/*------------------------------------------------------------------*//* Step 4. 释放模型。                                          *//*------------------------------------------------------------------*//* 调用 Mdo_freeMdl() 来释放内存 */Mdo_freeMdl(&model);
return (int)code;
}

MindOpt求解的结果

如何编译及运行MdoMiloEx1.c文件

#运行方式与前文线性规划一致,只需要修改文件就好;把MdoLoEx1.c换成MdoMiloEx1.c

windows系统本例是在Visual Studio上运行,版本为2019

c语言 windows系统运行mindopt.gif

/*linux和mac系统直接在命令行输入*/
cd <MDOHOME>/<VERSION>/examples/C
make -f Makefile all
./MdoMiloEx1

然后运行MdoMiloEx1.c 文件后,得到求解的结果如下所示,/**/号里面是我添加的注释。

Modelsummary.         /*模型摘要*/-Num. variables     : 4-Num. constraints   : 2-Num. nonzeros      : 7-Num. integervars. : 3-Boundrange        : [1.0e+00,1.0e+01]
-Objectiverange    : [1.0e+00,1.0e+00]
Branch-and-cutmethodstarted.       /*分支切割方法*/Originalmodel: nrow=2ncol=4nnz=7Tolerance: primal=1e-06int=1e-05mipgap=0.0001mipgapAbs=1e-06Parallelism: root=1, tree=2treeid0node0acceptanewsol: obj1 (heur) bndvio0intvio0mipgap1e+100Modelsummary.
-Num. variables     : 4-Num. constraints   : 2-Num. nonzeros      : 7-Boundrange        : [1.0e+00,1.0e+01]
-Objectiverange    : [1.0e+00,1.0e+00]
-Matrixrange       : [1.0e+00,6.0e+00]
Presolverstarted.
Presolverterminated. Time : 0.003sSimplexmethodstarted.        /*单纯形法*/IterationObjectiveDualInf.     PrimalInf.     Time00.00000e+000.0000e+002.0000e+000.02s25.55556e-010.0000e+000.0000e+000.02sPostsolverstarted.
Simplexmethodterminated. Time : 0.014s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03s05.55556e-010.0000e+000.0000e+000.03sBranch-and-cutmethodterminated. Time : 0.062sOptimizersummary.   /*求解器最终选择的优化方法以及求解消耗的时间*/-Optimizerused     : Branch-and-cutmethod/*分支和切割方法*/-Optimizerstatus   : OPTIMAL-Totaltime         : 0.087sSolutionsummary.
-Primalobjective   : 1.0000000000e+00/*目标函数最优解*/-Dualbound         : 5.5555555556e-01

联系我们

钉钉群号:32451444

邮箱地址:solver.damo@list.alibaba-inc.com

更多更新通知:https://solver.damo.alibaba.com

相关文章
|
1月前
|
编译器 C语言
C语言中整数如何自动转换为浮点数
C语言中整数如何自动转换为浮点数
66 0
|
1月前
|
存储 C语言
C语言中如何选择合适的方式将整数转换为浮点数
C语言中如何选择合适的方式将整数转换为浮点数
121 0
|
3月前
|
C语言
C语言写整数类(Integer)
C语言写整数类(Integer)
24 0
|
3月前
|
C语言
C语言程序编写:编写程序数一下 1到 100 的所有整数中出现多少个数字9
C语言程序编写:编写程序数一下 1到 100 的所有整数中出现多少个数字9
26 0
|
4月前
|
人工智能 自然语言处理 达摩院
MindOpt 云上建模求解平台:多求解器协同优化
数学规划是一种数学优化方法,主要是寻找变量的取值在特定的约束情况下,使我们的决策目标得到一个最大或者最小值的决策。
|
4月前
|
C语言
c语言编程练习题:7-37 输出整数各位数字
c语言编程练习题:7-37 输出整数各位数字
27 1
|
4月前
|
C语言
c语言编程练习题:7-28 求整数的位数及各位数字之和
c语言编程练习题:7-28 求整数的位数及各位数字之和
27 0
|
1月前
|
C语言
C语言刷题:整数加逗号、删除公共字符、求最小公倍数和将字符串倒置
C语言刷题:整数加逗号、删除公共字符、求最小公倍数和将字符串倒置
28 0
|
1月前
|
存储 C语言
在C语言中编写,用于从键盘接收输入的整数并判断该数是否能被3整除
在C语言中编写,用于从键盘接收输入的整数并判断该数是否能被3整除
23 0
|
2月前
|
算法 搜索推荐 程序员
C语言第二十六练 实现罗马数字转整数
C语言第二十六练 实现罗马数字转整数
29 0