8.8. C# API¶
本章节提供MindOpt的C# API手册,内容见下文。
8.8.16. Examples¶
8.8.16.1. 定制食谱¶
using Mindopt;
namespace Example
{
public class ExampleDiet
{
public static void Main(string[] args)
{
MDOEnv env = new MDOEnv();
MDOModel model = new MDOModel(env);
model.Set(MDO.StringAttr.ModelName, "diet");
Dictionary<string, double[]> requirements = new()
{
{"Calories", new double[]{ 2000, MDO.INFINITY }},
{"Carbohydrates", new double[]{ 350, 375 }},
{"Protein", new double[]{ 55, MDO.INFINITY }},
{"VitA", new double[]{ 100, MDO.INFINITY }},
{"VitC", new double[]{ 100, MDO.INFINITY }},
{"Calcium", new double[]{ 100, MDO.INFINITY }},
{"Iron", new double[]{ 100, MDO.INFINITY }},
{"Volume", new double[]{ -MDO.INFINITY,75 }}
};
Dictionary<string, double[]> foods = new()
{
{"Cheeseburger", new double[]{ 0, MDO.INFINITY, 1.84 }},
{"HamSandwich", new double[]{ 0, MDO.INFINITY, 2.19 }},
{"Hamburger", new double[]{ 0, MDO.INFINITY, 1.84 }},
{"FishSandwich", new double[]{ 0, MDO.INFINITY, 1.44 }},
{"ChickenSandwich", new double[]{ 0, MDO.INFINITY, 2.29 }},
{"Fries", new double[]{ 0, MDO.INFINITY, 0.77 }},
{"SausageBiscuit", new double[]{ 0, MDO.INFINITY, 1.29 }},
{"LowfatMilk", new double[]{ 0, MDO.INFINITY, 0.60 }},
{"OrangeJuice", new double[]{ 0, MDO.INFINITY, 0.72 }}
};
double[,] values = new double[,]
{
{ 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();
int numNutrition = nutritionNames.Length;
string[] foodNames = foods.Keys.Cast<string>().ToArray();
int numFood = foodNames.Length;
Dictionary<string, Dictionary<string, double>> reqValues = new();
for (int i = 0; i < foodNames.Length; i++)
{
reqValues[foodNames[i]] = new Dictionary<string, double>();
for (int j = 0; j < nutritionNames.Length; j++)
reqValues[foodNames[i]][nutritionNames[j]] = values[i, j];
}
try
{
MDOVar[] foodVars = new MDOVar[numFood];
for (int i = 0; i < numFood; ++i)
{
double[] foodData = foods[foodNames[i]];
foodVars[i] = model.AddVar(foodData[0], foodData[1], 0, MDO.CONTINUOUS, foodNames[i]);
}
// 添加约束
for (int i = 0; i < numNutrition; i++)
{
MDOLinExpr lin = new MDOLinExpr();
string nutri = nutritionNames[i];
for (int j = 0; j < numFood; j++)
{
string food = foodNames[j];
lin.AddTerm(reqValues[food][nutri], foodVars[j]);
}
model.AddRange(lin, requirements[nutritionNames[i]][0], requirements[nutritionNames[i]][1], nutritionNames[i]);
}
// 添加目标函数
MDOLinExpr linExpr = new MDOLinExpr();
for (int i = 0; i < numFood; i++)
linExpr.AddTerm(foods[foodNames[i]][2], foodVars[i]);
model.SetObjective(linExpr, MDO.MINIMIZE);
model.Optimize();
model.Write("ExmapleDiet.mps");
// 打印结果
foreach (MDOVar foodVar in foodVars)
Console.WriteLine($"You should buy {foodVar.Get(MDO.DoubleAttr.X)} unit of {foodVar.Get(MDO.StringAttr.VarName)}");
}
catch (MDOException e)
{
Console.WriteLine(e.Message);
}
finally
{
model.Dispose();
env.Dispose();
}
}
}
}
8.8.16.2. 设施选址¶
using Mindopt;
namespace Example
{
public class ExampleFacility
{
public static void Main(string[] args)
{
MDOEnv env = new MDOEnv();
MDOModel model = new MDOModel(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}
};
double transportFeePerM = 1.23;
try
{
int i = 0;
int j = 0;
MDOVar[] xVars = model.AddVars(facilitiesInfo.Count, MDO.BINARY);
MDOVar[,] yVars = new MDOVar[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> marketPair in marketInfo)
{
MDOLinExpr linExpr = new MDOLinExpr();
for (j = 0; j < facilitiesInfo.Count; j++)
{
linExpr.AddTerm(1, yVars[i, j]);
MDOLinExpr lhe = new MDOLinExpr();
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++;
}
MDOLinExpr objective = new MDOLinExpr();
j = 0;
foreach (KeyValuePair<Tuple<int, int>, double> facPair in facilitiesInfo)
{
objective.AddTerm(facPair.Value, xVars[j]);
i = 0;
foreach (Tuple<double, double> marketPos in marketInfo.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> pos in facilitiesInfo.Keys)
{
MDOVar x = 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 (MDOException e)
{
Console.WriteLine(e.Message);
}
finally
{
model.Dispose();
env.Dispose();
}
}
private static double calcTransFee(Tuple<double, double> pos1, Tuple<int, int> pos2, double unitPrice)
{
double x1 = pos1.Item1 - pos2.Item1;
double x2 = pos1.Item2 - pos2.Item2;
return (x1 * x1 + x2 * x2) * unitPrice;
}
}
}
8.8.16.3. 人力分配¶
using Mindopt;
namespace Example
{
public class ExampleWorkforce
{
public static void Main(string[] args)
{
// 创建MindOpt模型
MDOEnv env = new MDOEnv();
MDOModel model = new MDOModel(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 = new List<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 = new MDOVar[availability.Count];
for (int i = 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 (string day in dayName) dayCount[day] = new MDOLinExpr();
for (int i = 0; i < availability.Count; i++)
{
MDOLinExpr expr = new MDOLinExpr();
Tuple<string, string> workerDay = availability[i];
dayCount[workerDay.Item2].AddTerm(1, x[i]);
}
for (int i = 0; i < dayName.Length; i++)
{
MDOLinExpr expr = dayCount[dayName[i]];
model.AddConstr(expr, MDO.EQUAL, workersPerDay[i], "c1_" + availability[i].Item2);
}
MDOLinExpr obj = new MDOLinExpr();
for (int i = 0; i < availability.Count; i++)
obj.AddTerm(workers[availability[i].Item1], x[i]);
model.SetObjective(obj, MDO.MINIMIZE);
model.Optimize();
for (int i = 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 (MDOException e)
{
Console.WriteLine(e.Message);
}
finally
{
model.Dispose();
env.Dispose();
}
}
}
}