为什么我从 MILP 问题中得到非整数结果?
Why do I get non integer results from MILP problem?
我有一个用于饮食线性规划问题的 matlab 脚本。我正在尝试将 linearprog 或(intlinprog)的结果与工具箱 CPLEX 为 IBM 的 matlab 提供的 cplexlp(或 cplexmilp)函数的结果进行比较
这是脚本
%% Defining Variables
clear;clc
Pnames = ["BEEF";
"CHK";
"FISH";
"HAM";
"MCH";
"MTL";
"SPG";
"TUR" ];
Packs = optimvar('Packs',Pnames,'Type','integer');
Packs.LowerBound = 2*ones(length(Pnames),1);
Packs.UpperBound = 10*ones(length(Pnames),1);
%% Setting the problem data
CostPerPack = [3.19;2.59;2.29;2.89;1.89;1.99;1.99;2.49];
VitA = [60;8;8;40;15;70;25;60];
VitC = [20;0;10;40;35;30;50;20];
VitB1 = [10;20;15;35;15;15;25;15];
VitB2 = [15;20;10;10;15;15;15;10];
NA = [938;2180;945;278;1182;896;1329;1397];
CAL = [295;770;440;430;315;400;370;450];
% Amount Per package table
TAMT = table(VitA,VitC,VitB1,VitB2,NA,CAL,...
'VariableNames',{'A','C','B1','B2','NA','CAL'},...
'RowNames',Pnames);
%% Objective
TotCost = sum(CostPerPack .* Packs); % Objective
obj = TotCost;
%% Constraints
prob = optimproblem('Objective',obj,'ObjectiveSense','min');
prob.Constraints.c1 = sum(VitA.*Packs) >= 700;
prob.Constraints.c1a = sum(VitA.*Packs) <= 20000;
prob.Constraints.c2 = sum(VitC.*Packs) >= 700;
prob.Constraints.c2a = sum(VitC.*Packs) <= 20000;
prob.Constraints.c3 = sum(VitB1.*Packs) >= 700;
prob.Constraints.c3a = sum(VitB1.*Packs) <= 20000;
prob.Constraints.c4 = sum(VitB2.*Packs) >= 700;
prob.Constraints.c4a = sum(VitB2.*Packs) <= 20000;
prob.Constraints.c5 = sum(NA.*Packs) >= 0;
prob.Constraints.c5a = sum(NA.*Packs) <= 40000;
prob.Constraints.c5 = sum(CAL.*Packs) >= 16000;
prob.Constraints.c5a = sum(CAL.*Packs) <= 24000;
%% Putting the problem together and solving
problem = prob2struct(prob);
% LP
% [sol,fval,exitflag,output1] = linprog(problem);
% [sol2,fval2,exitflag2,output2] = cplexlp(problem);
% MILP problem
[sol,fval,exitflag,output1] = intlinprog(problem);
[sol2,fval2,exitflag2,output2] =cplexmilp(problem);
%% Display
disp('Linear Prog function results')
if (~isempty(sol) )
T1 = table(sol,sol.*VitA,sol.*VitC,sol.*VitB1,sol.*VitB2,sol.*NA,sol.*CAL,sol.*CostPerPack,...
'VariableNames',{'NuofPacks','PerVitA','PerVitC','PerVitB1','PerVitB2','NA','CAL','Cost'},...
'RowNames',Pnames);
sumrow = array2table(sum(T1.Variables),...
'VariableNames',...
{'NuofPacks','PerVitA','PerVitC','PerVitB1','PerVitB2','NA','CAL','Cost'},...
'RowNames',"Sum");
T1 = [T1;sumrow];
disp(T1)
else
disp(['No feasible Solution with exit flag = ' ,num2str(exitflag)])
end
%% Display Cplex
disp('Cplex function results')
if (~isempty(sol2) )
T2 = table(sol2,sol2.*VitA,sol2.*VitC,sol2.*VitB1,sol2.*VitB2,sol2.*NA,sol2.*CAL,sol2.*CostPerPack,...
'VariableNames',{'NuofPacks','PerVitA','PerVitC','PerVitB1','PerVitB2','NA','CAL','Cost'},...
'RowNames',Pnames);
sumrow2 = array2table(sum(T2.Variables),...
'VariableNames',...
{'NuofPacks','PerVitA','PerVitC','PerVitB1','PerVitB2','NA','CAL','Cost'},...
'RowNames',"Sum");
T2 = [T2;sumrow2];
disp(T2)
else
disp(['No feasible Solution with exit flag = ' ,num2str(exitflag2)])
end
这里是 Cplex 函数结果
NuofPacks PerVitA PerVitC PerVitB1 PerVitB2 NA CAL Cost
_________ _______ _______ ________ ________ _____ ______ ______
BEEF 2 120 40 20 30 1876 590 6.38
CHK 10 80 0 200 200 21800 7700 25.9
FISH 2 16 20 30 20 1890 880 4.58
HAM 2 80 80 70 20 556 860 5.78
MCH 10 150 350 150 150 11820 3150 18.9
MTL 10 700 300 150 150 8960 4000 19.9
SPG 7.3333 183.33 366.67 183.33 110 9746 2713.3 14.593
TUR 2 120 40 30 20 2794 900 4.98
Sum 45.333 1449.3 1196.7 833.33 700 59442 20793 101.01
来自 intlinprog 的这个 MILP 的结果似乎不错,但是从 cplexmilp 我得到了 SPG 包的非整数值。
谁能帮我知道这里的问题?
提前致谢
问题如下:当您调用 problem = prob2struct(prob);
时,来自 prob
的完整性信息被转移到 problem.intcon
,但不幸的是它没有转移到 cplex。
这个问题以前出现过,但没有在 cplex 中直接解决,因为有一个简单的解决方法:替换调用
[sol2,fval2,exitflag2,output2] =cplexmilp(problem);
和
[sol2,fval2,exitflag2,output2] = ...
cplexmilp(problem.f, problem.Aineq, problem.bineq, problem.Aeq, ...
problem.beq, [], [], [], problem.lb, problem.ub, ...
intcon_ctype(length(problem.lb),problem.intcon));
其中 intcon_ctype 函数是:
function ctype = intcon_ctype(numvars, intcon)
ctype = char(ones(1, numvars) * 'C');
for i = 1:length(intcon)
ctype(intcon(i)) = 'I'
end
end
请注意,这是一个非常简单的 intcon_ctype
转换函数。您可能需要检查 lb/ub 值并将类型设置为 'B' 如果变量是二进制,则可以指定半连续变量等
我有一个用于饮食线性规划问题的 matlab 脚本。我正在尝试将 linearprog 或(intlinprog)的结果与工具箱 CPLEX 为 IBM 的 matlab 提供的 cplexlp(或 cplexmilp)函数的结果进行比较 这是脚本
%% Defining Variables
clear;clc
Pnames = ["BEEF";
"CHK";
"FISH";
"HAM";
"MCH";
"MTL";
"SPG";
"TUR" ];
Packs = optimvar('Packs',Pnames,'Type','integer');
Packs.LowerBound = 2*ones(length(Pnames),1);
Packs.UpperBound = 10*ones(length(Pnames),1);
%% Setting the problem data
CostPerPack = [3.19;2.59;2.29;2.89;1.89;1.99;1.99;2.49];
VitA = [60;8;8;40;15;70;25;60];
VitC = [20;0;10;40;35;30;50;20];
VitB1 = [10;20;15;35;15;15;25;15];
VitB2 = [15;20;10;10;15;15;15;10];
NA = [938;2180;945;278;1182;896;1329;1397];
CAL = [295;770;440;430;315;400;370;450];
% Amount Per package table
TAMT = table(VitA,VitC,VitB1,VitB2,NA,CAL,...
'VariableNames',{'A','C','B1','B2','NA','CAL'},...
'RowNames',Pnames);
%% Objective
TotCost = sum(CostPerPack .* Packs); % Objective
obj = TotCost;
%% Constraints
prob = optimproblem('Objective',obj,'ObjectiveSense','min');
prob.Constraints.c1 = sum(VitA.*Packs) >= 700;
prob.Constraints.c1a = sum(VitA.*Packs) <= 20000;
prob.Constraints.c2 = sum(VitC.*Packs) >= 700;
prob.Constraints.c2a = sum(VitC.*Packs) <= 20000;
prob.Constraints.c3 = sum(VitB1.*Packs) >= 700;
prob.Constraints.c3a = sum(VitB1.*Packs) <= 20000;
prob.Constraints.c4 = sum(VitB2.*Packs) >= 700;
prob.Constraints.c4a = sum(VitB2.*Packs) <= 20000;
prob.Constraints.c5 = sum(NA.*Packs) >= 0;
prob.Constraints.c5a = sum(NA.*Packs) <= 40000;
prob.Constraints.c5 = sum(CAL.*Packs) >= 16000;
prob.Constraints.c5a = sum(CAL.*Packs) <= 24000;
%% Putting the problem together and solving
problem = prob2struct(prob);
% LP
% [sol,fval,exitflag,output1] = linprog(problem);
% [sol2,fval2,exitflag2,output2] = cplexlp(problem);
% MILP problem
[sol,fval,exitflag,output1] = intlinprog(problem);
[sol2,fval2,exitflag2,output2] =cplexmilp(problem);
%% Display
disp('Linear Prog function results')
if (~isempty(sol) )
T1 = table(sol,sol.*VitA,sol.*VitC,sol.*VitB1,sol.*VitB2,sol.*NA,sol.*CAL,sol.*CostPerPack,...
'VariableNames',{'NuofPacks','PerVitA','PerVitC','PerVitB1','PerVitB2','NA','CAL','Cost'},...
'RowNames',Pnames);
sumrow = array2table(sum(T1.Variables),...
'VariableNames',...
{'NuofPacks','PerVitA','PerVitC','PerVitB1','PerVitB2','NA','CAL','Cost'},...
'RowNames',"Sum");
T1 = [T1;sumrow];
disp(T1)
else
disp(['No feasible Solution with exit flag = ' ,num2str(exitflag)])
end
%% Display Cplex
disp('Cplex function results')
if (~isempty(sol2) )
T2 = table(sol2,sol2.*VitA,sol2.*VitC,sol2.*VitB1,sol2.*VitB2,sol2.*NA,sol2.*CAL,sol2.*CostPerPack,...
'VariableNames',{'NuofPacks','PerVitA','PerVitC','PerVitB1','PerVitB2','NA','CAL','Cost'},...
'RowNames',Pnames);
sumrow2 = array2table(sum(T2.Variables),...
'VariableNames',...
{'NuofPacks','PerVitA','PerVitC','PerVitB1','PerVitB2','NA','CAL','Cost'},...
'RowNames',"Sum");
T2 = [T2;sumrow2];
disp(T2)
else
disp(['No feasible Solution with exit flag = ' ,num2str(exitflag2)])
end
这里是 Cplex 函数结果
NuofPacks PerVitA PerVitC PerVitB1 PerVitB2 NA CAL Cost
_________ _______ _______ ________ ________ _____ ______ ______
BEEF 2 120 40 20 30 1876 590 6.38
CHK 10 80 0 200 200 21800 7700 25.9
FISH 2 16 20 30 20 1890 880 4.58
HAM 2 80 80 70 20 556 860 5.78
MCH 10 150 350 150 150 11820 3150 18.9
MTL 10 700 300 150 150 8960 4000 19.9
SPG 7.3333 183.33 366.67 183.33 110 9746 2713.3 14.593
TUR 2 120 40 30 20 2794 900 4.98
Sum 45.333 1449.3 1196.7 833.33 700 59442 20793 101.01
来自 intlinprog 的这个 MILP 的结果似乎不错,但是从 cplexmilp 我得到了 SPG 包的非整数值。 谁能帮我知道这里的问题? 提前致谢
问题如下:当您调用 problem = prob2struct(prob);
时,来自 prob
的完整性信息被转移到 problem.intcon
,但不幸的是它没有转移到 cplex。
这个问题以前出现过,但没有在 cplex 中直接解决,因为有一个简单的解决方法:替换调用
[sol2,fval2,exitflag2,output2] =cplexmilp(problem);
和
[sol2,fval2,exitflag2,output2] = ...
cplexmilp(problem.f, problem.Aineq, problem.bineq, problem.Aeq, ...
problem.beq, [], [], [], problem.lb, problem.ub, ...
intcon_ctype(length(problem.lb),problem.intcon));
其中 intcon_ctype 函数是:
function ctype = intcon_ctype(numvars, intcon)
ctype = char(ones(1, numvars) * 'C');
for i = 1:length(intcon)
ctype(intcon(i)) = 'I'
end
end
请注意,这是一个非常简单的 intcon_ctype
转换函数。您可能需要检查 lb/ub 值并将类型设置为 'B' 如果变量是二进制,则可以指定半连续变量等