阿里达摩院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();
            }
        }
    }
}
目录
相关文章
|
4月前
|
达摩院 供应链 安全
光储荷经济性调度问题【数学规划的应用(含代码)】阿里达摩院MindOpt
本文介绍使用MindOpt工具优化光储荷经济性调度的数学规划问题。光储荷经济性调度技术旨在最大化能源利用率和经济效益,应用场景包括分布式光伏微网、家庭能源管理系统、商业及工业用电、电力市场参与者等。文章详细阐述了如何通过数学规划方法解决虚拟电厂中的不确定性与多目标优化难题,并借助MindOpt云建模平台、MindOpt APL建模语言及MindOpt优化求解器实现问题建模与求解。最终案例展示了如何通过合理充放电策略减少37%的电费支出,实现经济与环保双重效益。读者可通过提供的链接获取完整源代码。
|
4月前
|
达摩院 BI 索引
切割问题【数学规划的应用(含代码)】阿里达摩院MindOpt
本文主要讲述了使用MindOpt工具对切割问题进行优化的过程与实践。切割问题是指从一维原材料(如木材、钢材等)中切割出特定长度的零件以满足不同需求,同时尽可能减少浪费的成本。文章通过实例详细介绍了如何使用MindOpt云上建模求解平台及其配套的MindOpt APL建模语言来解决此类问题,包括数学建模、代码实现、求解过程及结果分析等内容。此外,还讨论了一维切割问题的应用场景,并对其进行了扩展,探讨了更复杂的二维和三维切割问题。通过本文的学习,读者能够掌握利用MindOpt工具解决实际切割问题的方法和技术。
|
4月前
|
达摩院 算法 安全
智慧楼宇多目标调度问题【数学规划的应用(含代码)】阿里达摩院MindOpt
本文探讨了使用MindOpt工具优化智慧楼宇的多目标调度问题,特别是在虚拟电厂场景下的应用。智慧楼宇通过智能化技术综合考虑能耗、舒适度等多目标,实现楼宇设备的有效管理和调度。虚拟电厂作为多能源聚合体,能够参与电力市场,提供调峰、调频等辅助服务。文章介绍了如何使用MindOpt云上建模求解平台及MindOpt APL建模语言对楼宇多目标调度问题进行数学建模和求解,旨在通过优化储能设备的充放电操作来最小化用电成本、碳排放成本和功率变化成本,从而实现经济、环保和电网稳定的综合目标。最终结果显示,在使用储能设备的情况下,相比不使用储能设备的情形,成本节约达到了约48%。
|
4月前
|
达摩院 供应链 JavaScript
网络流问题--仓储物流调度【数学规划的应用(含代码)】阿里达摩院MindOpt
本文通过使用MindOpt工具优化仓储物流调度问题,旨在提高物流效率并降低成本。首先,通过考虑供需匹配、运输时间与距离、车辆容量、仓库储存能力等因素构建案例场景。接着,利用数学规划方法,包括线性规划和网络流问题,来建立模型。在网络流问题中,通过定义节点(资源)和边(资源间的关系),确保流量守恒和容量限制条件下找到最优解。文中还详细介绍了MindOpt Studio云建模平台和MindOpt APL建模语言的应用,并通过实例展示了如何声明集合、参数、变量、目标函数及约束条件,并最终解析了求解结果。通过这些步骤,实现了在满足各仓库需求的同时最小化运输成本的目标。
|
7月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
216 3
|
7月前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
207 3
|
1月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
35 3
|
2天前
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
31 12
|
1月前
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
51 4
|
3月前
|
API C#
C# 一分钟浅谈:文件系统编程
在软件开发中,文件系统操作至关重要。本文将带你快速掌握C#中文件系统编程的基础知识,涵盖基本概念、常见问题及解决方法。文章详细介绍了`System.IO`命名空间下的关键类库,并通过示例代码展示了路径处理、异常处理、并发访问等技巧,还提供了异步API和流压缩等高级技巧,帮助你写出更健壮的代码。
51 2