8.5. C++ API¶
本章节提供MindOpt的C++ API手册,内容见下文。
8.5.17. Examples¶
8.5.17.1. 定制食谱¶
#include <iostream>
#include "MindoptCpp.h"
#include <map>
using namespace std;
// 定义所需的营养素的摄入量
map<string, pair<double, double>> req = {
{"Cal", {2000, MDO_INFINITY } },
{"Carbo", {350, 375 } },
{"Protein", {55, MDO_INFINITY } },
{"VitA", {100, MDO_INFINITY } },
{"VitC", {100, MDO_INFINITY } },
{"Calc", {100, MDO_INFINITY } },
{"Iron", {100, MDO_INFINITY } },
{"Volume", {-MDO_INFINITY, 75 }}
};
// 定义摄入的食物的下限,上限,和每单位的价格
map<string, tuple<double, double, double>> food = {
{"Cheeseburger", {0, MDO_INFINITY, 1.84 } },
{"HamSandwich", {0, MDO_INFINITY, 2.19 } },
{"Hamburger", {0, MDO_INFINITY, 1.84 } },
{"FishSandwich", {0, MDO_INFINITY, 1.44 } },
{"ChickenSandwich", {0, MDO_INFINITY, 2.29 } },
{"Fries", {0, MDO_INFINITY, 0.77 } },
{"SausageBiscuit", {0, MDO_INFINITY, 1.29 } },
{"LowfatMilk", {0, MDO_INFINITY, 0.60 } },
{"OrangeJuice", {0, MDO_INFINITY, 0.72 }}
};
// 定义摄入的每单位食物的各种营养素的含量
map<pair<string, string>, double> req_value = {
{{"Cal", "Cheeseburger" }, 510 },
{{"Cal", "HamSandwich" }, 370 },
{{"Cal", "Hamburger" }, 500 },
{{"Cal", "FishSandwich" }, 370 },
{{"Cal", "ChickenSandwich" }, 400 },
{{"Cal", "Fries" }, 220 },
{{"Cal", "SausageBiscuit" }, 345 },
{{"Cal", "LowfatMilk" }, 110 },
{{"Cal", "OrangeJuice" }, 80 },
{{"Carbo", "Cheeseburger" }, 34 },
{{"Carbo", "HamSandwich" }, 35 },
{{"Carbo", "Hamburger" }, 42 },
{{"Carbo", "FishSandwich" }, 38 },
{{"Carbo", "ChickenSandwich" }, 42 },
{{"Carbo", "Fries" }, 26 },
{{"Carbo", "SausageBiscuit" }, 27 },
{{"Carbo", "LowfatMilk" }, 12 },
{{"Carbo", "OrangeJuice" }, 20 },
{{"Protein", "Cheeseburger" }, 28 },
{{"Protein", "HamSandwich" }, 24 },
{{"Protein", "Hamburger" }, 25 },
{{"Protein", "FishSandwich" }, 14 },
{{"Protein", "ChickenSandwich" }, 31 },
{{"Protein", "Fries" }, 3 },
{{"Protein", "SausageBiscuit" }, 15 },
{{"Protein", "LowfatMilk" }, 9 },
{{"Protein", "OrangeJuice" }, 1 },
{{"VitA", "Cheeseburger" }, 15 },
{{"VitA", "HamSandwich" }, 15 },
{{"VitA", "Hamburger" }, 6 },
{{"VitA", "FishSandwich" }, 2 },
{{"VitA", "ChickenSandwich" }, 8 },
{{"VitA", "Fries" }, 0 },
{{"VitA", "SausageBiscuit" }, 4 },
{{"VitA", "LowfatMilk" }, 10 },
{{"VitA", "OrangeJuice" }, 2 },
{{"VitC", "Cheeseburger" }, 6 },
{{"VitC", "HamSandwich" }, 10 },
{{"VitC", "Hamburger" }, 2 },
{{"VitC", "FishSandwich" }, 0 },
{{"VitC", "ChickenSandwich" }, 15 },
{{"VitC", "Fries" }, 15 },
{{"VitC", "SausageBiscuit" }, 0 },
{{"VitC", "OrangeJuice" }, 4 },
{{"VitC", "LowfatMilk" }, 120 },
{{"Calc", "Cheeseburger" }, 20 },
{{"Calc", "HamSandwich" }, 20 },
{{"Calc", "Hamburger" }, 25 },
{{"Calc", "FishSandwich" }, 15 },
{{"Calc", "ChickenSandwich" }, 15 },
{{"Calc", "Fries" }, 0 },
{{"Calc", "SausageBiscuit" }, 20 },
{{"Calc", "LowfatMilk" }, 30 },
{{"Calc", "OrangeJuice" }, 2 },
{{"Iron", "Cheeseburger" }, 20 },
{{"Iron", "HamSandwich" }, 20 },
{{"Iron", "Hamburger" }, 20 },
{{"Iron", "FishSandwich" }, 10 },
{{"Iron", "ChickenSandwich" }, 8 },
{{"Iron", "Fries" }, 2 },
{{"Iron", "SausageBiscuit" }, 15 },
{{"Iron", "LowfatMilk" }, 0 },
{{"Iron", "OrangeJuice" }, 2 },
{{"Volume", "Cheeseburger" }, 4 },
{{"Volume", "HamSandwich" }, 7.5 },
{{"Volume", "Hamburger" }, 3.5 },
{{"Volume", "FishSandwich" }, 5 },
{{"Volume", "ChickenSandwich" }, 7.3 },
{{"Volume", "Fries" }, 2.6 },
{{"Volume", "SausageBiscuit" }, 4.1 },
{{"Volume", "LowfatMilk" }, 8 },
{{"Volume", "OrangeJuice" }, 12}
};
int main(int argc, char *argv[]) {
try {
// 建立模型
MDOEnv env = MDOEnv();
MDOModel m = MDOModel(env);
// 添加决策变量
map<string, MDOVar> variable;
map<string, tuple<double, double, double>>::iterator food_it;
for (food_it = food.begin(); food_it != food.end(); ++food_it) {
string food_name = food_it->first;
tuple<double, double, double> food_data = food_it->second;
variable[food_name] = m.addVar(get<0>(food_data), get<1>(food_data),
0.0, MDO_CONTINUOUS, food_name);
}
// 添加约束
// 应满足每日获取的各种营养素在建议的范围内
map<string, MDOConstr> cons;
map<string, pair<double, double>>::iterator req_it;
for (req_it = req.begin(); req_it != req.end(); ++req_it) {
string req_name = req_it->first;
pair<double, double> req_data = req_it->second;
MDOLinExpr expr = 0;
for (food_it = food.begin(); food_it != food.end(); ++food_it) {
string food_name = food_it->first;
tuple<double, double, double> food_data = food_it->second;
expr += variable[food_name] * req_value[{req_name, food_name}];
}
cons[req_name] = m.addRange(expr, req_data.first, req_data.second);
}
// 添加目标函数
MDOLinExpr objective = 0;
for (food_it = food.begin(); food_it != food.end(); ++food_it) {
string food_name = food_it->first;
tuple<double, double, double> food_data = food_it->second;
objective += variable[food_name] * get<2>(food_data);
}
m.setObjective(objective, 1);
m.write("Test_cpp.mps");
// 开始优化
m.optimize();
// 打印结果
map<string, MDOVar>::iterator it;
for (it = variable.begin(); it != variable.end(); ++it) {
string food_name = it->first;
MDOVar var = it->second;
cout << "Amount of " << food_name << " intake: " << var.get(MDO_DoubleAttr_X) << endl;
}
cout << "Total meal cost: " << m.get(MDO_DoubleAttr_ObjVal) << endl;
for (req_it = req.begin(); req_it != req.end(); ++req_it) {
string req_name = req_it->first;
pair<double, double> req_data = req_it->second;
MDOLinExpr expr = 0;
for (food_it = food.begin(); food_it != food.end(); ++food_it) {
string food_name = food_it->first;
expr += variable[food_name] * req_value[{req_name, food_name}];
}
}
} catch (MDOException &e) {
cout << "Error code = " << e.getErrorCode() << endl;
cout << e.getMessage() << endl;
} catch (...) {
cout << "Error during optimization." << endl;
}
return 0;
}
8.5.17.2. 设施选址¶
#include <iostream>
#include "MindoptCpp.h"
#include <map>
#include <vector>
using namespace std;
// 本例子的目标是为了找到最小成本的仓库建造和运输方案
// 有两个商场,商场的位置已经确定,分别是(0, 1.7)和(1.4, 2.9), 所需要的货物重量为100单位和200单位
map<vector<double>, int> marketInfo = {
{vector<double>{0.0, 1.7}, 100},
{vector<double>{1.4, 2.9}, 200}
};
vector<vector<double>> marketKeys = vector<vector<double>>{
vector<double>{0.0, 1.7},
vector<double>{1.4, 2.9},
};
size_t marketNum = marketInfo.size();
// 仓库位置和建造成本
map<vector<int>, double> facilitiesInfo = {
{vector<int>{0, 1}, 3.0},
{vector<int>{0, 2}, 1.0},
{vector<int>{1, 0}, 1.5},
{vector<int>{1, 1}, 1.3},
{vector<int>{1, 2}, 1.8},
{vector<int>{2, 0}, 1.6},
{vector<int>{2, 1}, 1.1},
{vector<int>{2, 2}, 1.9},
};
vector<vector<int>> facilitiesKeys = {
vector<int>{0, 1},
vector<int>{0, 2},
vector<int>{1, 0},
vector<int>{1, 1},
vector<int>{1, 2},
vector<int>{2, 0},
vector<int>{2, 1},
vector<int>{2, 2}
};
int facilitiesNum = facilitiesInfo.size();
double transportFeePerM = 1.23;
int main(int argc, char *argv[]) {
// Define requirements
try {
MDOEnv env;
MDOModel model(env);
model.set(MDO_StringAttr_ModelName, "Facility");
// 添加决策变量
vector<MDOVar> xVars(facilitiesNum);
for (int j = 0; j < facilitiesNum; j++) {
xVars[j] = model.addVar(0, MDO_INFINITY, 0, MDO_BINARY, "Facility" + to_string(j));
}
vector<vector<MDOVar>> yVars(marketNum, vector<MDOVar>(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, to_string(i) + to_string(j));
}
}
// 增加约束
for (int i = 0; i < marketNum; i++) {
// 约束1 已经决定建造的仓库必须满足所有商场的货物需求
MDOLinExpr linExpr;
vector<double> coeffs;
vector<MDOVar> vars;
for (int j = 0; j < facilitiesNum; j++) {
coeffs.push_back(1);
vars.push_back(yVars[i][j]);
MDOLinExpr lhe = 1.0 / marketInfo[marketKeys[i]] * yVars[i][j];
model.addConstr(lhe - xVars[j], MDO_LESS_EQUAL, 0,
"is_built[" + to_string(i) + "," + to_string(j) + "]");
}
linExpr.addTerms(coeffs.data(), vars.data(), coeffs.size());
// 约束2 如果不建仓库,则此仓库位置运送给所有商场的货物为0
model.addConstr(linExpr, MDO_EQUAL, marketInfo[marketKeys[i]], "is_satisfy_" + to_string(i));
}
// 增加目标函数: 最小化运输费用和建造仓库的费用的总和
// 假设从a地运往b地的运输费用只和距离有关,和货物重量无关
MDOLinExpr objective;
vector<double> coeffs;
vector<MDOVar> vars;
for (int j = 0; j < facilitiesNum; j++) {
coeffs.push_back(facilitiesInfo[facilitiesKeys[j]]);
vars.push_back(xVars[j]);
}
for (int j = 0; j < facilitiesNum; j++) {
for (int i = 0; i < marketNum; i++) {
double x1 = marketKeys[i][0] - facilitiesKeys[j][0];
double x2 = marketKeys[i][1] - facilitiesKeys[j][1];
coeffs.push_back((x1 * x1 + x2 * x2) * transportFeePerM);
vars.push_back(xVars[j]);
}
}
objective.addTerms(coeffs.data(), vars.data(), coeffs.size());
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) {
cout << "The No." << i << " warehouse should be built at (" << facilitiesKeys[i][0] << ", "
<< facilitiesKeys[i][1] << ")" << endl;
}
}
model.write("TestFacility.mps");
cout << model.get(MDO_DoubleAttr_ObjVal);
} catch (MDOException &e) {
cout << "Error code = " << e.getErrorCode() << endl;
cout << e.getMessage() << endl;
} catch (...) {
cout << "Error during optimization." << endl;
}
return 0;
}
8.5.17.3. 人力分配¶
#include <iostream>
#include "MindoptCpp.h"
#include "map"
using namespace std;
// 每天需要的人力数
map<string, int> workers_per_day = {
{ "Monday", 3 },
{ "Tuesday", 1 },
{ "Wednesday", 4 },
{ "Thursday", 2 },
{ "Friday", 1 },
{ "Saturday", 3 },
{ "Sunday", 3 }
};
// 每个工人一天的工资
map<string, int> pay = {
{ "Xiaoming", 13 },
{ "Huahua", 10 },
{ "HongHong", 11 },
{ "Dahua", 8 },
{ "Lihua", 9 },
{ "Niuniu", 14 },
{ "Gouzi", 14 }
};
// 每个工人可以出勤的时间
vector<tuple<string, string>> availability = {
{ "Xiaoming", "Tuesday" },
{ "Xiaoming", "Wednesday" },
{ "Xiaoming", "Friday" },
{ "Xiaoming", "Sunday" },
{ "Huahua", "Monday" },
{ "Huahua", "Tuesday" },
{ "Huahua", "Friday" },
{ "Huahua", "Saturday" },
{ "HongHong", "Wednesday" },
{ "HongHong", "Thursday" },
{ "HongHong", "Friday" },
{ "HongHong", "Sunday" },
{ "Dahua", "Tuesday" },
{ "Dahua", "Wednesday" },
{ "Dahua", "Friday" },
{ "Dahua", "Saturday" },
{ "Lihua", "Monday" },
{ "Lihua", "Tuesday" },
{ "Lihua", "Wednesday" },
{ "Lihua", "Thursday" },
{ "Lihua", "Friday" },
{ "Lihua", "Sunday" },
{ "Niuniu", "Monday" },
{ "Niuniu", "Tuesday" },
{ "Niuniu", "Wednesday" },
{ "Niuniu", "Saturday" },
{ "Gouzi", "Monday" },
{ "Gouzi", "Tuesday" },
{ "Gouzi", "Wednesday" },
{ "Gouzi", "Friday" },
{ "Gouzi", "Saturday" },
{ "Gouzi", "Sunday" }
};
int main(int argc, char *argv[]) {
try {
MDOEnv env = MDOEnv();
MDOModel model = MDOModel(env);
// 添加决策变量
// x[(worker, day)]这个变量代表该工人是否在当天工作
// 用(worker, day)来初始化决策变量,可以保证每个工人只在他们允许的天内出勤
map<pair<string, string>, MDOVar> x;
vector<tuple<string, string>>::iterator availability_it;
for (availability_it = availability.begin(); availability_it != availability.end(); ++availability_it) {
string worker = get<0>(*availability_it);
string day = get<1>(*availability_it);
x[{ worker, day }] = model.addVar(0.0, 1.0, 0.0, MDO_BINARY, "schedule");
}
// 增加约束
// 约束: 满足每天的人力需求
map<string, int>::iterator workers_per_day_it;
for (workers_per_day_it = workers_per_day.begin(); workers_per_day_it != workers_per_day.end(); ++workers_per_day_it) {
string day = workers_per_day_it->first;
int num_workers = workers_per_day_it->second;
MDOLinExpr expr = 0;
for (availability_it = availability.begin(); availability_it != availability.end(); ++availability_it) {
string worker = get<0>(*availability_it);
string d = get<1>(*availability_it);
if (d == day) {
expr += x[{ worker, day }];
}
}
model.addConstr(expr == num_workers);
}
// 增加目标函数
MDOLinExpr objective = 0;
for (availability_it = availability.begin(); availability_it != availability.end(); ++availability_it) {
string worker = get<0>(*availability_it);
string day = get<1>(*availability_it);
objective += pay[worker] * x[{ worker, day }];
}
model.setObjective(objective, MDO_MINIMIZE);
// 开始优化
model.optimize();
model.write("test_cpp.mps");
// 打印结果
for (availability_it = availability.begin(); availability_it != availability.end(); ++availability_it) {
string worker = get<0>(*availability_it);
string day = get<1>(*availability_it);
if (x[{ worker, day }].get(MDO_DoubleAttr_X) > 0.5) {
cout << worker << " should work at " << day << endl;
}
}
cout << "The total cost is " << model.get(MDO_DoubleAttr_ObjVal) << endl;
} catch (MDOException& e) {
cout << "Error code = " << e.getErrorCode() << endl;
cout << e.getMessage() << endl;
} catch (...) {
cout << "Error during optimization." << endl;
}
return 0;
}