8.9. MATLAB API

本章节提供MindOpt的MATLAB手册,内容见下文。

8.9.3. Examples

定制食谱

有许多种不同的食物,每种食物可以提供不同的营养元素。请问我们该如何做出食物摄入的决策,以使得在满足人体每天所需的各种营养的前提下,能够最小化购买食物所花费的金额?

集合

  • 食物集合 \(F\)

  • 营养集合 \(N\)

参数

  • 每单位1的食物 \(j\) 中关于营养 \(i \in N\) 的含量为 \(a_{ij}\)

  • 获得单位1的食物 \(j\in F\) 的代价为 \(c_j\)

决策变量

  • \(x_j\) 是某人每天对食物 \(j\in F\) 的摄入量

目标函数

  • 最小化食物的总采购金额: \(\text{minimize}~ \sum_{j\in F} c_{j}x_j\)

约束

  • 每人对营养 \(i\in N\) 的需求介于最小值 \(n_{\min,i}\) 和最大值 \(n_{\max,i}\) 之间: \(n_{\min,i} \le \sum_{j\in F} a_{ij} x_j \le n_{\max,i},~~ \forall\, i\in N\)


% 初始化数据
 demand_ub = [inf, 375, inf, inf, inf, inf, inf, 75];
 demand_lb = [2000, 350, 55, 100, 100, 100, 100, -inf];
 nutrition_name = {'Calories', 'Carbohydrates', 'Protein', 'VitA', 'VitC', 'Calcium', 'Iron', 'Volume'};
 food_name = {'Cheeseburger', 'HamSandwich', 'Hamburger', 'FishSandwich', 'ChickenSandwich', 'Fries', 'SausageBiscuit', 'LowfatMilk', 'OrangeJuice'};
 food_price = [1.84, 2.19, 1.84, 1.44, 2.29, 0.77, 1.29, 0.60, 0.72];
 req_value = [510.0, 370.0, 500.0, 370.0, 400.0, 220.0, 345.0, 110.0, 80.0;
             34.0,  35.0,  42.0,  38.0,  42.0,  26.0,  27.0,  12.0,  20.0;
             28.0,  24.0,  25.0,  14.0,  31.0,  3.0,   15.0,  9.0,   1.0;
             15.0,  15.0,  6.0,   2.0,   8.0,   0.0,   4.0,   10.0,  2.0;
             6.0,   10.0,  2.0,   0.0,   15.0,  15.0,  0.0,   120.0, 4.0;
             30.0,  20.0,  25.0,  15.0,  15.0,  0.0,   20.0,  30.0,  2.0;
             20.0,  20.0,  20.0,  10.0,  8.0,   2.0,   15.0,  0.0,   2.0;
             4.0,   7.5,   3.5,   5.0,   7.3,   2.6,   4.1,   8.0,   12.0; ];

% 建立模型
 model.A = sparse(req_value);
 model.obj = food_price;
 model.rhs = demand_ub;
 model.lhsorsense = demand_lb;
 model.modelsense = 'Min';
 model.varnames = food_name;
 model.constrnames = nutrition_name;

% 求解
 result = mindopt(model);

% 打印求解结果
 if strcmp(res.Status,'OPTIMAL')
     fprintf('The total cost is %.3f\n', result.ObjVal);
     for v=1:length(food_name)
         fprintf('You should buy %.3f unit of %s\n', result.X(v), food_name{v});
     end
 else
     fprintf('The optimize status is %s', res.Status);
 end

设施选址

当前有两个商场,商场的位置已经确定。由若干建造仓库的备选位置,已知其坐标和其建造成本。我们假定从仓库到商场的运输成本与货物数量无关但与其之间的距离有关,请找到最小成本的仓库建造和运输方案。

集合

  • 备选仓库 \(F\)

  • 商场 \(M\)

参数

  • 从仓库 \(i\in F\) 向商场 \(j \in M\) 运输的成本为 \(a_{ij}\)

  • 建造仓库 \(i\in F\) 的代价为 \(c_j\)

  • 商场 \(j \in M\) 的需求的货物量为 \(d_{ij}\)

决策变量

  • \(x_i\) 是是否在备选位置 \(i\in F\) 建造仓库。其取值必须为0或1,值为0时表示不建造,值为1时表示建造。

  • \(y_{ij}\) 表示是在从备选位置 \(i\in F\) 的仓库向 \(j \in M\) 的商场运输的距离货物数量。

目标函数

最小化仓库建造和商品运输的成本: \(\text{minimize}~ \sum_{i\in F} c_{i}x_i+\sum_{i\in F,j \in M} a_{ij}y_{ij}\) :

\(\text{minimize}~ \sum_{i\in F} c_{i}x_i + \sum_{i\in F,j \in M} a_{ij}y_{ij}\)

约束

\(\sum_{i\in F} y_{ij} = d_{j}, ~~ \forall j\in M\)

\(x_i d_j - \sum_{k\in M} y_{ik} = 0, ~~ \forall i \in F, j \in M\)


% 有两个商场,商场的位置已经确定,分别是(0, 1.7)和(1.4, 2.9), 所需要的货物重量为100单位和200单位
market_location = [0.0, 1.7 ; 1.4, 2.9];
market_demand = [100, 200];
market_num = length(market_demand);

% 仓库位置和建造成本
facility_location = [
    0, 1;
    0, 2;
    1, 0;
    1, 1;
    1, 2;
    2, 0;
    2, 1;
    2, 2
];
facility_num = length(facility_location);
transport_fee_per_m = 1.23;
n = market_num * facility_num;

% 建造成本
facility_expense = [3.0, 1.0, 1.5, 1.3, 1.8, 1.6, 1.1, 1.9];

% 运输成本
transport_expense = [zeros(1, facility_num * market_num)];
for i = 1:facility_num
    for j = 1:market_num
        transport_expense((i - 1) * market_num + j) = norm(market_location(j, :) - facility_location(i, :)) * transport_fee_per_m;
    end
end

% 创建约束矩阵
A = [zeros(market_num,facility_num), [eye(market_num),eye(market_num),eye(market_num),eye(market_num),eye(market_num),eye(market_num),eye(market_num),eye(market_num)]];
B = eye(market_num * facility_num);
even_rows = 2:2:n;
odd_rows = 1:2:n-1;
new_order = [odd_rows, even_rows];
B = B(new_order, :);
% B = [zeros(market_num * facility_num, facility_num), B];
A = [A; [market_demand(1) * -eye(facility_num), B(1:facility_num, :)]];
A = [A; [market_demand(2) * -eye(facility_num), B(facility_num + 1: facility_num * market_num, :)]];

% 建立模型
model.A = sparse(A);
model.obj = [facility_expense,zeros(1,market_num * facility_num);];
model.rhs = [market_demand, zeros(1, facility_num), zeros(1, facility_num)];
model.lhsorsense = '=';
model.modelsense = 'Min';
model.vtype = [repmat('B',1, facility_num),repmat('C',1, facility_num*2)];
res = mindopt(model);

% 打印求解结果
if strcmp(res.Status,'OPTIMAL')
    fprintf('The total cost is %.3f\n', res.ObjVal);
    for v = 1:facility_num
        if res.X(v) == 1
            fprintf('The No. %d warehouse should be built.\n', v);
        end
    end
else
    fprintf('The optimize status is %s', res.Status);
end

人力分配

在一周中,工厂每天需要的工人数目不同。现在已知每个工人的日工资及其在一周中可以出勤的日期。需要计算如何安排工人,才能在满足工厂运行要求的情况下做到工资成本最低。

集合

  • 一周日期 \(D = 1,2,3...,7\)

  • 工厂需要的工人数目 \(N\)

  • 工人 \(S\)

参数

  • 工厂第 \(i \in D\) 天所需的工人数目为 \(n_i\)

  • 工人 \(j\in S\) 的日工资为 \(s_j\)

  • 表示工人可工作时间的序列,共有 \(T\) 组工人-工作时间数对 \((d_i,t_i)\) ,其中 \(d_i\in S,t_i \in D, i = 1,2,3...T\)

目标函数

最小化支付的工资: \(\text{minimize}~ \sum_{i=1,2,3...T} x_is_{d_i}\)

决策变量

  • \(x_i( i = 1,2,3...T)\) 表示可工作时间序列中,当日改工人是否上班。其取值必须为0或1,值为0时表示不上班,值为1时表示上班。

约束

\(\sum_{d_i=r} x_i = n_{r}, ~~\forall r\in D\)


 % 每日所需的工人数
  day_name = {'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'};
  workers_per_day = [3, 1, 4, 2, 1, 3, 3];

 % 工人每日工资
  workers_name = {'Xiaoming', 'Huahua', 'HongHong', 'Dahua', 'Lihua', 'Niuniu', 'Gouzi'};
  workers_pay = [13, 10, 11, 8, 9, 14, 14];

% 工人可工作的时间
  day_id = [2; 3; 5; 7; 1; 2; 5; 6; 3; 4; 5; 7; 2; 3; 5; 6; 1; 2; 3; 4; 5; 7; 1; 2; 3; 6; 1; 2; 3; 5; 6; 7;];
  worker_id = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7];

  obj = zeros(1,length(day_id));
  for i = 1:length(obj)
      obj(i) = workers_pay(worker_id(i));
  end

  A = spconvert([day_id,(1:length(obj))',ones(1,length(obj))']);

 % 建立模型
  model.A = A;
  model.obj = obj;
  model.modelsense = 'Min';
  model.vtype = repmat('B', 1, length(obj));
  model.lhsorsense = workers_per_day;
  model.rhs = workers_per_day;
  res = mindopt(model);

 % 打印求解结果
  if strcmp(res.Status,'OPTIMAL')
      fprintf("The total cost is %f \n", res.ObjVal);
      for i = 1:length(res.X)
          if res.X(i) == 1
              name = workers_name{worker_id(i)};
              day = day_name{day_id(i)};
              fprintf('%s should work at %s\n', name, day);
          end
      end
  else
      fprintf('The optimize status is %s', res.Status);
  end