8.6. JAVA API¶
本章节提供MindOpt的JAVA API手册,内容见下文。
8.6.16. Examples¶
8.6.16.1. 定制食谱¶
import java.util.HashMap;
import java.util.Map;
public class ExampleDiet {
public static void main(String[] args) throws MDOException{
// 建立模型
MDOEnv env = new MDOEnv();
MDOModel model = new MDOModel(env);
model.set(MDO.StringAttr.ModelName, "diet");
// 定义所需的营养素的摄入量
Map<String, double[]> requirements = new HashMap<>();
requirements.put("Calories", new double[]{ 2000, MDO.INFINITY });
requirements.put("Carbohydrates", new double[]{ 350, 375 });
requirements.put("Protein", new double[]{ 55, MDO.INFINITY });
requirements.put("VitA", new double[]{ 100, MDO.INFINITY });
requirements.put("VitC", new double[]{ 100, MDO.INFINITY });
requirements.put("Calcium", new double[]{ 100, MDO.INFINITY });
requirements.put("Iron", new double[]{ 100, MDO.INFINITY });
requirements.put("Volume", new double[]{ -MDO.INFINITY,75 });
Map<String, double[]> foods = new HashMap<>();
// 定义摄入的食物的下限,上限,和每单位的价格
foods.put("Cheeseburger", new double[]{ 0, MDO.INFINITY, 1.84 });
foods.put("HamSandwich", new double[]{ 0, MDO.INFINITY, 2.19 });
foods.put("Hamburger", new double[]{ 0, MDO.INFINITY, 1.84 });
foods.put("FishSandwich", new double[]{ 0, MDO.INFINITY, 1.44 });
foods.put("ChickenSandwich", new double[]{ 0, MDO.INFINITY, 2.29 });
foods.put("Fries", new double[]{ 0, MDO.INFINITY, 0.77 });
foods.put("SausageBiscuit", new double[]{ 0, MDO.INFINITY, 1.29 });
foods.put("LowfatMilk", new double[]{ 0, MDO.INFINITY, 0.60 });
foods.put("OrangeJuice", new double[]{ 0, MDO.INFINITY, 0.72 });
// 定义摄入的每单位食物的各种营养素的含量
String[] nutritionNames = new String[]{ "Calories", "Carbohydrates", "Protein",
"VitA", "VitC", "Calcium", "Iron", "Volume" };
int numNutrition = nutritionNames.length;
String[] foodNames = new String[]{ "Cheeseburger", "HamSandwich", "Hamburger", "FishSandwich",
"ChickenSandwich", "Fries", "SausageBiscuit", "LowfatMilk", "OrangeJuice" };
int numFood = foodNames.length;
Map<String, Map<String, Double>> reqValues = new HashMap<>();
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 } };
for (int i = 0; i < foodNames.length; i++) {
reqValues.put(foodNames[i], new HashMap<>());
for (int j = 0; j < nutritionNames.length; j++) {
reqValues.get(foodNames[i]).put(nutritionNames[j], values[i][j]);
}
}
try {
// 添加决策变量
MDOVar[] foodVars = new MDOVar[numFood];
for (int i = 0; i < numFood; ++i) {
double[] foodData = foods.get(foodNames[i]);
foodVars[i] = model.addVar(foodData[0], foodData[1], 0, MDO.CONTINUOUS, foodNames[i]);
}
// 添加约束
// 应满足每日获取的各种营养素在建议的范围内
for (int i = 0; i < numNutrition; i++) {
MDOLinExpr linExpr = new MDOLinExpr();
String nutri = nutritionNames[i];
for (int j = 0; j < numFood; j++) {
String food = foodNames[j];
linExpr.addTerm(reqValues.get(food).get(nutri), foodVars[j]);
}
model.addRange(linExpr, requirements.get(nutritionNames[i])[0], requirements.get(nutritionNames[i])[1], nutritionNames[i]);
}
// 添加目标函数
MDOLinExpr linExpr = new MDOLinExpr();
for (int i = 0; i < numFood; i++) {
linExpr.addTerm(foods.get(foodNames[i])[2], foodVars[i]);
}
model.setObjective(linExpr, MDO.MINIMIZE);
// 开始优化
model.optimize();
model.write("TestJava.mps");
// 打印结果
for (MDOVar foodVar : foodVars) {
System.out.println("You should buy " + foodVar.get(MDO.DoubleAttr.X) + " unit of " + foodVar.get(MDO.StringAttr.VarName));
}
} catch (MDOException e) {
System.out.println(e.getMessage());
} finally {
// 释放Model和Environment的资源
model.dispose();
env.dispose();
}
}
}
8.6.16.2. 设施选址¶
import java.util.*;
// 本例子的目标是为了找到最小成本的仓库建造和运输方案
public class ExampleFacility {
public static void main(String[] args) throws MDOException {
MDOEnv env = new MDOEnv();
MDOModel model = new MDOModel(env);
model.set(MDO.StringAttr.ModelName, "Facility");
// 有两个商场,商场的位置已经确定,分别是(0, 1.7)和(1.4, 2.9), 所需要的货物重量为100单位和200单位
Map<List<Double>, Integer> marketInfo = new HashMap<>();
marketInfo.put(Arrays.asList(0.0, 1.7), 100);
marketInfo.put(Arrays.asList(1.4, 2.9), 200);
List<List<Double>> marketKeys = new ArrayList<>();
marketKeys.add(Arrays.asList(0.0, 1.7));
marketKeys.add(Arrays.asList(1.4, 2.9));
int marketNum = marketInfo.size();
// 仓库位置和建造成本
Map<List<Integer>, Double> facilitiesInfo = new HashMap<>();
facilitiesInfo.put(Arrays.asList(0, 1), 3.0);
facilitiesInfo.put(Arrays.asList(0, 2), 1.0);
facilitiesInfo.put(Arrays.asList(1, 0), 1.5);
facilitiesInfo.put(Arrays.asList(1, 1), 1.3);
facilitiesInfo.put(Arrays.asList(1, 2), 1.8);
facilitiesInfo.put(Arrays.asList(2, 0), 1.6);
facilitiesInfo.put(Arrays.asList(2, 1), 1.1);
facilitiesInfo.put(Arrays.asList(2, 2), 1.9);
List<List<Integer>> facilitiesKeys = new ArrayList<>();
facilitiesKeys.add(Arrays.asList(0, 1));
facilitiesKeys.add(Arrays.asList(0, 2));
facilitiesKeys.add(Arrays.asList(1, 0));
facilitiesKeys.add(Arrays.asList(1, 1));
facilitiesKeys.add(Arrays.asList(1, 2));
facilitiesKeys.add(Arrays.asList(2, 0));
facilitiesKeys.add(Arrays.asList(2, 1));
facilitiesKeys.add(Arrays.asList(2, 2));
int facilitiesNum = facilitiesInfo.size();
double transportFeePerM = 1.23;
try {
// 添加决策变量
MDOVar[] xVars = model.addVars(facilitiesNum, MDO.BINARY);
MDOVar[][] yVars = new MDOVar[marketNum][facilitiesNum];
for (int i = 0; i < marketNum; i++) {
for (int j = 0; j < facilitiesNum; j++) {
yVars[i][j] = model.addVar(0, MDO.INFINITY, 0, MDO.CONTINUOUS, String.valueOf(i) + String.valueOf(j));
}
}
// 增加约束
for (int i = 0; i < marketNum; i++) {
// 约束1 已经决定建造的仓库必须满足所有商场的货物需求
MDOLinExpr linExpr = new MDOLinExpr();
for (int j = 0; j < facilitiesNum; j++) {
linExpr.addTerm(1, yVars[i][j]);
MDOLinExpr lhe = new MDOLinExpr();
lhe.addTerm(1.0 / marketInfo.get(marketKeys.get(i)), yVars[i][j]);
model.addConstr(lhe, MDO.LESS_EQUAL, xVars[j], "is_built[" + i + "," + j + "]");
}
// 约束2 如果不建仓库,则此仓库位置运送给所有商场的货物为0
model.addConstr(linExpr, MDO.EQUAL, marketInfo.get(marketKeys.get(i)), "is_satisfy_" + i);
}
// 增加目标函数: 最小化运输费用和建造仓库的费用的总和
// 假设从a地运往b地的运输费用只和距离有关,和货物重量无关
MDOLinExpr objective = new MDOLinExpr();
for (int j = 0; j < facilitiesNum; j++) {
objective.addTerm(facilitiesInfo.get(facilitiesKeys.get(j)), xVars[j]);
}
for (int j = 0; j < facilitiesNum; j++) {
for (int i = 0; i < marketNum; i++) {
objective.addTerm(calculateTransportationFee(marketKeys.get(i), facilitiesKeys.get(j), transportFeePerM), xVars[j]);
}
}
model.setObjective(objective, MDO.MINIMIZE);
// 开始优化
model.optimize();
// 打印结果
for (int i = 0; i < facilitiesNum; i++) {
MDOVar x = xVars[i];
if (x.get(MDO.DoubleAttr.X) == 1) {
System.out.println("The No." + i + " warehouse should be built at (" + facilitiesKeys.get(i).get(0)
+ ", " + facilitiesKeys.get(i).get(1) + ")");
}
}
model.write("TestFacility.mps");
System.out.println(objective.getValue());
} catch (MDOException e) {
System.out.println(e.getMessage());
}finally {
model.dispose();
env.dispose();
}
}
private static double calculateTransportationFee(List<Double> pos1, List<Integer> pos2, double transportFeePerM) {
double x1 = pos1.get(0) - pos2.get(0);
double x2 = pos1.get(1) - pos2.get(1);
return (x1 * x1 + x2 * x2) * transportFeePerM;
}
}
8.6.16.3. 人力分配¶
import java.util.*;
public class ExampleWorkforce {
public static void main(String[] args) throws MDOException {
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 };
// 每个工人一天的工资
Map<String, Integer> workers = new HashMap<>();
workers.put("Xiaoming", 13);
workers.put("Huahua", 10);
workers.put("HongHong", 11);
workers.put("Dahua", 8);
workers.put("Lihua", 9);
workers.put("Niuniu", 14);
workers.put("Gouzi", 14);
List<String> workers_name = new ArrayList<>(workers.keySet());
// 每个工人可以出勤的时间
List<String[]> availability = new ArrayList<>();
availability.add(new String[]{ "Xiaoming", "Tuesday" });
availability.add(new String[]{ "Xiaoming", "Wednesday" });
availability.add(new String[]{ "Xiaoming", "Friday" });
availability.add(new String[]{ "Xiaoming", "Sunday" });
availability.add(new String[]{ "Huahua", "Monday" });
availability.add(new String[]{ "Huahua", "Tuesday" });
availability.add(new String[]{ "Huahua", "Friday" });
availability.add(new String[]{ "Huahua", "Saturday" });
availability.add(new String[]{ "HongHong", "Wednesday" });
availability.add(new String[]{ "HongHong", "Thursday" });
availability.add(new String[]{ "HongHong", "Friday" });
availability.add(new String[]{ "HongHong", "Sunday" });
availability.add(new String[]{ "Dahua", "Tuesday" });
availability.add(new String[]{ "Dahua", "Wednesday" });
availability.add(new String[]{ "Dahua", "Friday" });
availability.add(new String[]{ "Dahua", "Saturday" });
availability.add(new String[]{ "Lihua", "Monday" });
availability.add(new String[]{ "Lihua", "Tuesday" });
availability.add(new String[]{ "Lihua", "Wednesday" });
availability.add(new String[]{ "Lihua", "Thursday" });
availability.add(new String[]{ "Lihua", "Friday" });
availability.add(new String[]{ "Lihua", "Sunday" });
availability.add(new String[]{ "Niuniu", "Monday" });
availability.add(new String[]{ "Niuniu", "Tuesday" });
availability.add(new String[]{ "Niuniu", "Wednesday" });
availability.add(new String[]{ "Niuniu", "Saturday" });
availability.add(new String[]{ "Gouzi", "Monday" });
availability.add(new String[]{ "Gouzi", "Tuesday" });
availability.add(new String[]{ "Gouzi", "Wednesday" });
availability.add(new String[]{ "Gouzi", "Friday" });
availability.add(new String[]{ "Gouzi", "Saturday" });
availability.add(new String[]{ "Gouzi", "Sunday" });
try {
// 添加决策变量
// x[(worker, day)]这个变量代表该工人是否在当天工作
// 用(worker, day)来初始化决策变量,可以保证每个工人只在他们允许的天内出勤
MDOVar[] x = new MDOVar[availability.size()];
for (int i = 0; i < availability.size(); i++) {
String[] worker_day = availability.get(i);
x[i] = model.addVar(0, 1, 0, MDO.BINARY, "schedule_" + worker_day[0] + "," + worker_day[1]);
}
// 增加约束
// 约束: 满足每天的人力需求
Map<String, MDOLinExpr> day_count = new HashMap<>();
for (String day : dayName) {
MDOLinExpr le = new MDOLinExpr();
day_count.put(day, le);
}
for (int i = 0; i < availability.size(); i++) {
MDOLinExpr expr = new MDOLinExpr();
String[] worker_day = availability.get(i);
day_count.get(worker_day[1]).addTerm(1, x[i]);
}
for (int i = 0; i < dayName.length; i++) {
MDOLinExpr expr = day_count.get(dayName[i]);
model.addConstr(expr, MDO.EQUAL, workersPerDay[i], "c1" + availability.get(i)[1]);
}
// 增加目标函数
MDOLinExpr obj = new MDOLinExpr();
for (int i = 0; i < availability.size(); i++) {
obj.addTerm(workers.get(availability.get(i)[0]), x[i]);
}
model.setObjective(obj, MDO.MINIMIZE);
// 开始优化
model.optimize();
// 打印结果
for (int i = 0; i < availability.size(); i++) {
if (x[i].get(MDO.DoubleAttr.X) > 0) {
System.out.println(availability.get(i)[0] + " should work at " + availability.get(i)[1]);
}
}
System.out.println("The total cost is " + model.get(MDO.DoubleAttr.ObjVal));
} catch (Exception e) {
System.out.println("Exception during optimization");
e.printStackTrace();
} finally {
model.dispose();
env.dispose();
}
}
}