阿里达摩院MindOpt求解器V1.1新增C#接口

简介: 阿里达摩院MindOpt求解器发布最新版本V1.1,增加了C#相关API和文档。优化求解器产品是求解优化问题的专业计算软件,可广泛各个行业。阿里达摩院从2019年投入自研MindOpt优化求解器,截止目前经历27个版本的迭代,取得了多项国内和国际第一的成绩。就在上个月,2023年12月,在工信部产业发展促进中心等单位主办的首届能源电子产业创新大赛上,MindOpt获得电力用国产求解器第一名。本文将为C#开发者讲述如何下载安装MindOpt和C#案例源代码。

MindOpt V1.1 新增C#接口

C#的开发者好消息:阿里达摩院MindOpt求解器最新版本V1.1,增加了C#相关API和文档。

image.png


什么是优化求解器

优化求解器产品是求解优化问题的专业计算软件。可广泛应用于云计算、电力能源、工业制造、交通物流、零售、金融等领域,能帮助做方案设计、生产方案优化、资源合理分配、辅助决策等,是深埋于智能决策场景底层的“降本增效”的好工具,工业设计软件之芯。


优化求解器作为底层计算软件,因其技术壁垒高、研发难度大,几十年来,商用求解器一直被少数国外厂商垄断。阿里达摩院从2019年投入自研MindOpt优化求解器,截止目前经历27个版本的迭代,取得了多项国内和国际第一的成绩。就在上个月,2023年12月,在工信部产业发展促进中心等单位主办的首届能源电子产业创新大赛上,MindOpt获得电力用国产求解器第一名


对优化求解器有更多好奇心的初学者,可查阅小编之前的文章《什么是优化技术?给算法小白同学的快速讲解和上手文》(或公众号精排版


MindOpt C#接口-使用说明


本次MindOpt更新的V1.1版本,除了在性能上进一步提升,还增加了C#的接口。


加上之前已经支持的,当前MindOpt支持

  • 主流操作系统:Windows、MacOS、Linux的X86和ARM芯片版本,
  • 调用方式支持:
  • 命令行运行;
  • 通用编程语言 C、C++、C#、Java、Python,部分Julia;
  • 优化领域的建模语言 AMPL、Pyomo、PuLP、GAMS以及达摩院自研的MAPL(MindOpt APL)。


步骤1:下载MindOpt和配置License


自2021年起,MindOpt坚持做软件包开放下载,通过阿里云平台,方便用户自助获取商用级别的优化求解器软件,长期有免费额度,企业用户和教育用户均可自助0元购买后使用。


下载安装包https://opt.aliyun.com/portal/docs/htmldoc/solverDownLoad

此地址索引了阿里云的文档窗口,方便用户记住地址 opt.aliyun.com 和快速找到MindOpt的其他文档和资源。也可以点击右边的“打开原始文档”,在原阿里云网站中打开。

image.png


安装软件:


  • Windows双击安装包
  • Linux和macOS命令行运行bash mindopt-install-xxx-1.1.0.sh指令安装

安装后即可在命令行中运行mindopt来检查是否安装成功。


如果有在云计算环境运行的,如docker、maxCompute、Flink等环境,也可把本软件当作一个lib库来用,从安装后目录里面拿对应的文件。


配置License:


当前MindOpt供用户自助获取的License是联网云鉴权License,只传鉴权信息(阿里云账号和LIcenseKey码等),不传递用户的建模等数据,可放心使用。


导航栏上点击 产品-优化求解器,将进入阿里云的商品购买介绍页,根据指引点购买进入控制台来购买。可参考文档:https://help.aliyun.com/zh/optimization-solver/getting-started/activate-and-use-the-service

image.png

购买后,在已购服务列表中会看到LicenseKey,然后配置fl_client.ini文件,放置在mindopt文件夹,如下:

image.png

配置了后,可命令行执行mindopt -c,会遍历所有的License方式,最后看求解任务成功执行,命令行中如果有如下信息,即可认为此fl_client.ini文件配置成功。

[INFO ] Using floating license configuration in '/Users/xxxx/mindopt'

[INFO ] Completed validation with floating license configuration.


步骤2:试运行MindOpt安装目录的C# examples

进入到安装目录examples文件夹,有提供各种编程语言、建模语言和数据的实例,可参考运行。

image.png

Example.csproj是一个示例项目,配置中如下方式引用了MindOpt库(不同操作系统地址不同):

<ItemGroup><ReferenceInclude="mindoptcs.dll"><HintPath>$(MINDOPT_HOME)/osx64-aarch/lib/mindoptcs.dll</HintPath></Reference></ItemGroup>


.NET 编译和运行:


这里以命令行运行为例讲解如何运行,如在Linux或mac机器上,安装了.NET SDK 8.x ,将.cs代码文件拷贝入csproject文件夹中,运行如下指令编译和运行:

  • 示例1:拷贝不需要依赖外部数据的ExampleDiet.cs进入csproject文件夹
cd csproject
cp ../ExampleDiet.cs .
dotnet build
dotnet run  --framework netcoreapp8.0


如下图示意,会执行求解和输出

image.png


  • 示例2:拷贝需要依赖外部数据的ReadMps.cs进入csproject文件夹。其中第四行引用的数据地址也是MindOpt的安装目录examples文件夹中提供的示例数据。
cd csproject
cp ../ReadMps.cs .
dotnet build
dotnet run ../../data/afiro.mps --framework netcoreapp8.0


C#源代码:如何使用MindOpt解决建模和求解优化问题


建模数学原理的讲解,可参考MindOpt平台上的资源-案例广场https://opt.aliyun.com/platform/case。以下仅给出代码供参考如何调用。


1. 定制食谱

usingMindopt;
namespaceExample{
publicclassExampleDiet    {
publicstaticvoidMain(string[] args)
        {
MDOEnvenv=newMDOEnv();
MDOModelmodel=newMDOModel(env);
model.Set(MDO.StringAttr.ModelName, "diet");
Dictionary<string, double[]>requirements=new()
            {
                {"Calories",    newdouble[]{ 2000, MDO.INFINITY }},
                {"Carbohydrates",         newdouble[]{ 350, 375 }},
                {"Protein",       newdouble[]{ 55, MDO.INFINITY }},
                {"VitA",         newdouble[]{ 100, MDO.INFINITY }},
                {"VitC",         newdouble[]{ 100, MDO.INFINITY }},
                {"Calcium",      newdouble[]{ 100, MDO.INFINITY }},
                {"Iron",         newdouble[]{ 100, MDO.INFINITY }},
                {"Volume",        newdouble[]{ -MDO.INFINITY,75 }}
            };
Dictionary<string, double[]>foods=new()
            {
                {"Cheeseburger",    newdouble[]{ 0, MDO.INFINITY, 1.84 }},
                {"HamSandwich",     newdouble[]{ 0, MDO.INFINITY, 2.19 }},
                {"Hamburger",       newdouble[]{ 0, MDO.INFINITY, 1.84 }},
                {"FishSandwich",    newdouble[]{ 0, MDO.INFINITY, 1.44 }},
                {"ChickenSandwich", newdouble[]{ 0, MDO.INFINITY, 2.29 }},
                {"Fries",           newdouble[]{ 0, MDO.INFINITY, 0.77 }},
                {"SausageBiscuit",  newdouble[]{ 0, MDO.INFINITY, 1.29 }},
                {"LowfatMilk",      newdouble[]{ 0, MDO.INFINITY, 0.60 }},
                {"OrangeJuice",     newdouble[]{ 0, MDO.INFINITY, 0.72 }}
            };
double[,] values=newdouble[,]
            {
                { 510.0, 34.0, 28.0, 15.0,   6.0, 30.0, 20.0,  4.0 },
                { 370.0, 35.0, 24.0, 15.0,  10.0, 20.0, 20.0,  7.5 },
                { 500.0, 42.0, 25.0,  6.0,   2.0, 25.0, 20.0,  3.5 },
                { 370.0, 38.0, 14.0,  2.0,   0.0, 15.0, 10.0,  5.0 },
                { 400.0, 42.0, 31.0,  8.0,  15.0, 15.0,  8.0,  7.3 },
                { 220.0, 26.0,  3.0,  0.0,  15.0,  0.0,  2.0,  2.6 },
                { 345.0, 27.0, 15.0,  4.0,   0.0, 20.0, 15.0,  4.1 },
                { 110.0, 12.0,  9.0, 10.0, 120.0, 30.0,  0.0,  8.0 },
                {  80.0, 20.0,  1.0,  2.0,   4.0,  2.0,  2.0, 12.0 }
            };
string[] nutritionNames=requirements.Keys.Cast<string>().ToArray();
intnumNutrition=nutritionNames.Length;
string[] foodNames=foods.Keys.Cast<string>().ToArray();
intnumFood=foodNames.Length;
Dictionary<string, Dictionary<string, double>>reqValues=new();
for (inti=0; i<foodNames.Length; i++)
            {
reqValues[foodNames[i]] =newDictionary<string, double>();
for (intj=0; j<nutritionNames.Length; j++)
reqValues[foodNames[i]][nutritionNames[j]] =values[i, j];
            }
try            {
MDOVar[] foodVars=newMDOVar[numFood];
for (inti=0; i<numFood; ++i)
                {
double[] foodData=foods[foodNames[i]];
foodVars[i] =model.AddVar(foodData[0], foodData[1], 0, MDO.CONTINUOUS, foodNames[i]);
                }
// 添加约束for (inti=0; i<numNutrition; i++)
                {
MDOLinExprlin=newMDOLinExpr();
stringnutri=nutritionNames[i];
for (intj=0; j<numFood; j++)
                    {
stringfood=foodNames[j];
lin.AddTerm(reqValues[food][nutri], foodVars[j]);
                    }
model.AddRange(lin, requirements[nutritionNames[i]][0], requirements[nutritionNames[i]][1], nutritionNames[i]);
                }
// 添加目标函数MDOLinExprlinExpr=newMDOLinExpr();
for (inti=0; i<numFood; i++)
linExpr.AddTerm(foods[foodNames[i]][2], foodVars[i]);
model.SetObjective(linExpr, MDO.MINIMIZE);
model.Optimize();
model.Write("ExmapleDiet.mps");
// 打印结果foreach (MDOVarfoodVarinfoodVars)
Console.WriteLine($"You should buy {foodVar.Get(MDO.DoubleAttr.X)} unit of {foodVar.Get(MDO.StringAttr.VarName)}");
            }
catch (MDOExceptione)
            {
Console.WriteLine(e.Message);
            }
finally            {
model.Dispose();
env.Dispose();
            }
        }
    }
}

2. 设施选址

usingMindopt;
namespaceExample{
publicclassExampleFacility    {
publicstaticvoidMain(string[] args)
        {
MDOEnvenv=newMDOEnv();
MDOModelmodel=newMDOModel(env);
model.Set(MDO.StringAttr.ModelName, "Facility");
Dictionary<Tuple<double, double>, int>marketInfo=new()
            {
                {Tuple.Create(0.0, 1.7), 100},
                {Tuple.Create(1.4, 2.9), 200},
            };
Dictionary<Tuple<int, int>, double>facilitiesInfo=new()
            {
                {Tuple.Create(0, 1), 3.0},
                {Tuple.Create(0, 2), 1.0},
                {Tuple.Create(1, 0), 1.5},
                {Tuple.Create(1, 1), 1.3},
                {Tuple.Create(1, 2), 1.8},
                {Tuple.Create(2, 0), 1.6},
                {Tuple.Create(2, 1), 1.1},
                {Tuple.Create(2, 2), 1.9}
            };
doubletransportFeePerM=1.23;
try            {
inti=0;
intj=0;
MDOVar[] xVars=model.AddVars(facilitiesInfo.Count, MDO.BINARY);
MDOVar[,] yVars=newMDOVar[marketInfo.Count, facilitiesInfo.Count];
for (i=0; i<marketInfo.Count; i++)
                {
for (j=0; j<facilitiesInfo.Count; j++)
yVars[i, j] =model.AddVar(0, MDO.INFINITY, 0, MDO.CONTINUOUS, $"{i}{j}");
                }
i=0;
foreach (KeyValuePair<Tuple<double, double>, int>marketPairinmarketInfo)
                {
MDOLinExprlinExpr=newMDOLinExpr();
for (j=0; j<facilitiesInfo.Count; j++)
                    {
linExpr.AddTerm(1, yVars[i, j]);
MDOLinExprlhe=newMDOLinExpr();
lhe.AddTerm(1.0/marketPair.Value, yVars[i, j]);
model.AddConstr(lhe, MDO.LESS_EQUAL, xVars[j], $"is_built[{i}, {j}]");
                    }
model.AddConstr(linExpr, MDO.EQUAL, marketPair.Value, $"is_satisify[{i}, {j}]");
i++;
                }
MDOLinExprobjective=newMDOLinExpr();
j=0;
foreach (KeyValuePair<Tuple<int, int>, double>facPairinfacilitiesInfo)
                {
objective.AddTerm(facPair.Value, xVars[j]);
i=0;
foreach (Tuple<double, double>marketPosinmarketInfo.Keys)
                    {
objective.AddTerm(calcTransFee(marketPos, facPair.Key, transportFeePerM), xVars[j]);
i++;
                    }
j++;
                }
model.SetObjective(objective, MDO.MINIMIZE);
model.Optimize();
model.Write("ExampleFacility.mps");
i=0;
foreach (Tuple<int, int>posinfacilitiesInfo.Keys)
                {
MDOVarx=xVars[i];
if (x.Get(MDO.DoubleAttr.X) ==1) {
Console.Write($"The No.{i} warehouse should be built at ");
Console.WriteLine($"({pos.Item1}, {pos.Item2})");
                    }
i++;
                }
Console.WriteLine($"Trnasport fee is: {objective.Value} ");
            }
catch (MDOExceptione)
            {
Console.WriteLine(e.Message);
            }
finally            {
model.Dispose();
env.Dispose();
            }
        }
privatestaticdoublecalcTransFee(Tuple<double, double>pos1, Tuple<int, int>pos2, doubleunitPrice)
        {
doublex1=pos1.Item1-pos2.Item1;
doublex2=pos1.Item2-pos2.Item2;
return (x1*x1+x2*x2) *unitPrice;
        }
    }
}

3. 人力分配

usingMindopt;
namespaceExample{
publicclassExampleWorkforce    {
publicstaticvoidMain(string[] args)
        {
// 创建MindOpt模型MDOEnvenv=newMDOEnv();
MDOModelmodel=newMDOModel(env);
// 每天需要的工日数目string[] dayName= { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
int[] workersPerDay= {  3, 1, 4, 2, 1, 3, 3 };
// 对应工人的工资Dictionary<string, int>workers=new()
            {
                {"Xiaoming", 13},
                {"Huahua",   10},
                {"HongHong", 11},
                {"Dahua",     8},
                {"Lihua",     9},
                {"Niuniu",   14},
                {"Gouzi",    14}
            };
List<string>workers_name=newList<string>(workers.Keys);
// 定义可用集合List<Tuple<string, string>>availability=new()
            {
Tuple.Create( "Xiaoming",     "Tuesday" ),
Tuple.Create( "Xiaoming",   "Wednesday" ),
Tuple.Create( "Xiaoming",      "Friday" ),
Tuple.Create( "Xiaoming",      "Sunday" ),
Tuple.Create( "Huahua",        "Monday" ),
Tuple.Create( "Huahua",       "Tuesday" ),
Tuple.Create( "Huahua",        "Friday" ),
Tuple.Create( "Huahua",      "Saturday" ),
Tuple.Create( "HongHong",   "Wednesday" ),
Tuple.Create( "HongHong",    "Thursday" ),
Tuple.Create( "HongHong",      "Friday" ),
Tuple.Create( "HongHong",      "Sunday" ),
Tuple.Create( "Dahua",        "Tuesday" ),
Tuple.Create( "Dahua",      "Wednesday" ),
Tuple.Create( "Dahua",         "Friday" ),
Tuple.Create( "Dahua",       "Saturday" ),
Tuple.Create( "Lihua",         "Monday" ),
Tuple.Create( "Lihua",        "Tuesday" ),
Tuple.Create( "Lihua",      "Wednesday" ),
Tuple.Create( "Lihua",       "Thursday" ),
Tuple.Create( "Lihua",         "Friday" ),
Tuple.Create( "Lihua",         "Sunday" ),
Tuple.Create( "Niuniu",        "Monday" ),
Tuple.Create( "Niuniu",       "Tuesday" ),
Tuple.Create( "Niuniu",     "Wednesday" ),
Tuple.Create( "Niuniu",      "Saturday" ),
Tuple.Create( "Gouzi",         "Monday" ),
Tuple.Create( "Gouzi",        "Tuesday" ),
Tuple.Create( "Gouzi",      "Wednesday" ),
Tuple.Create( "Gouzi",         "Friday" ),
Tuple.Create( "Gouzi",       "Saturday" ),
Tuple.Create( "Gouzi",         "Sunday" )
            };
try            {
MDOVar[] x=newMDOVar[availability.Count];
for (inti=0; i<x.Length; i++)
                {
Tuple<string, string>workerDay=availability[i];
x[i] =model.AddVar(0, 1, 0, MDO.BINARY, $"sched({workerDay.Item1}, {workerDay.Item2})");
                }
Dictionary<string, MDOLinExpr>dayCount=new();
foreach (stringdayindayName) dayCount[day] =newMDOLinExpr();
for (inti=0; i<availability.Count; i++)
                {
MDOLinExprexpr=newMDOLinExpr();
Tuple<string, string>workerDay=availability[i];
dayCount[workerDay.Item2].AddTerm(1, x[i]);
                }
for (inti=0; i<dayName.Length; i++)
                {
MDOLinExprexpr=dayCount[dayName[i]];
model.AddConstr(expr, MDO.EQUAL, workersPerDay[i], "c1_"+availability[i].Item2);
                }
MDOLinExprobj=newMDOLinExpr();
for (inti=0; i<availability.Count; i++)
obj.AddTerm(workers[availability[i].Item1], x[i]);
model.SetObjective(obj, MDO.MINIMIZE);
model.Optimize();
for (inti=0; i<availability.Count; i++)
                {
if (x[i].Get(MDO.DoubleAttr.X) >0)
Console.WriteLine($"{availability[i].Item1} should work at {availability[i].Item2}");
                }
Console.WriteLine($"The total cost is { + model.Get(MDO.DoubleAttr.ObjVal)}");
            }
catch (MDOExceptione)
            {
Console.WriteLine(e.Message);
            }
finally            {
model.Dispose();
env.Dispose();
            }
        }
    }
}
目录
相关文章
|
25天前
|
达摩院 Linux 决策智能
阿里达摩院MindOpt优化求解器-月刊(2024年3月)
### MindOpt 优化求解器月刊(2024年3月) - 发布亮点:MAPL建模语言升级至V2.4,支持云上无安装使用和向量化建模语法。 - 新增功能:Linux用户可本地安装`maplpy`,并支持Python与MAPL混编。 - 实例分享:介绍背包问题的组合优化,展示如何在限定容量下最大化收益。 - 用户投稿:探讨机票超售时的最优调派策略,以最小化赔付成本。 - 加入互动:官方钉钉群32451444,更多资源及。 [查看详细内容](https://opt.aliyun.com/)
51 0
阿里达摩院MindOpt优化求解器-月刊(2024年3月)
|
2月前
|
达摩院 决策智能
阿里达摩院MindOpt优化求解器-月刊(2024年2月)
新增2个整数规划的应用案例《人员排班:小美的春节相亲大计划》和《组合优化问题:装箱问题》。B站的视频专题已有9篇讲解如何用数学规划去解决生活和工作中的问题,包含如何建立数学模型、编代码、运行代码和结果理解。使用了达摩院 MindOpt 的建模语言和云平台,可复制项目跟随视频练习。还可参与活动领奖品!
94 1
|
3月前
|
达摩院 API C#
阿里达摩院MindOpt优化求解器-月刊(2024年1月)
MindOpt优化求解器 V1.1.0 发布,LP和MILP性能提升,新增C# API等多功能,详解如何使用这些新功能。新增旅行商TSP问题案例,假期如何旅游省路费, 主交通费¥900 内,就可跨5省游10城!TSP问题中MTZ消除子环的方法详解。公众号博文《四年求一解,一群达摩院数学家的极限挑战》讲解MindOpt团队成员的成长故事。
88 0
阿里达摩院MindOpt优化求解器-月刊(2024年1月)
|
3月前
|
达摩院 开发者 容器
「达摩院MindOpt」优化形状切割问题(MILP)
在制造业,高效地利用材料不仅是节约成本的重要环节,也是可持续发展的关键因素。无论是在金属加工、家具制造还是纺织品生产中,原材料的有效利用都直接影响了整体效率和环境影响。
「达摩院MindOpt」优化形状切割问题(MILP)
|
4月前
|
人工智能 自然语言处理 达摩院
MindOpt 云上建模求解平台:多求解器协同优化
数学规划是一种数学优化方法,主要是寻找变量的取值在特定的约束情况下,使我们的决策目标得到一个最大或者最小值的决策。
|
3月前
|
存储 达摩院 调度
「达摩院MindOpt」优化FlowShop流水线作业排班问题
在企业在面临大量多样化的生产任务时,如何合理地安排流水线作业以提高生产效率及确保交货期成为了一个重要的问题。
「达摩院MindOpt」优化FlowShop流水线作业排班问题
|
9月前
|
达摩院 调度
使用达摩院MindOpt优化交通调度_最大化通行量—线性规划问题
在数学规划中,网络流问题是指一类基于网络模型的流量分配问题。网络流问题的目标是在网络中分配资源,使得网络的流量满足一定的限制条件,并且使得某些目标函数最小或最大化。网络流问题通常涉及一个有向图,图中每个节点表示一个资源,每条边表示资源之间的关系。边上有一个容量值,表示该边上最多可以流动的资源数量。流量从源节点开始流出,经过一系列中间节点,最终到达汇节点。在这个过程中,需要遵守一定的流量守恒和容量限制条件。
|
5月前
|
API Python
MindOpt V1.0优化种植计划问题,新的建模方法
种植计划是指农业生产中针对不同农作物的种植时间、面积和种植方式等方面的规划安排。根据具体情况进行合理的规划和安排,以实现农作物的高产、优质和可持续发展。
MindOpt V1.0优化种植计划问题,新的建模方法
|
9月前
|
达摩院 供应链 JavaScript
网络流:优化仓储物流调度问题-达摩院MindOpt
仓储物流调度是指在物流供应链中,对仓储和运输(运输路线、成本)进行协调和安排的过程。主要包含物流计划、运输调度、运发管理、库存管理等重要环节。随着网络、电商行业的迅速发展,仓储物流调度对于企业来说也非常重要,优秀的调度方案可以帮助降低库存成本、物流配送的效率、成本等等等,从而给企业带来降本增效。
网络流:优化仓储物流调度问题-达摩院MindOpt
|
9月前
|
数据可视化
MindOpt优化如何分散化风险并实现收益与风险最优配比问题
资产配置,投资组合是指通过分散投资资金的方式来规避投资过程中的风险。在实际的投资过程中,如何决定投资哪些产品来实现收益最大化和风险最小化是一个关键的问题。
MindOpt优化如何分散化风险并实现收益与风险最优配比问题