|
Hello,
From a private request, I put my beta version of my code for
conversion of LP to MPS below. Any suggestion and Bug
reporting are welcome. When the code becomes more stable,
I'll submit to FEX.
Thanks,
Bruno
function Contain=BuildMPS(A, b, Aeq, beq, cost, L, U, PbName)
%
% function Contain=BuildMPS(A, b, Aeq, beq, cost, L, U, PbName)
%
% Build MPS string cell that contains linear programming
problem:
%
% Minimizing cost'*c, subject to
% A*x <= b
% Aeq*x = beq
% L <= x <= U
%
% Optional: PbName is a string of problem name [GENERIC]
%
% To learn about mps format, please see:
% http://lpsolve.sourceforge.net/5.5/mps-format.htm
%
http://www-fp.mcs.anl.gov/OTC/Guide/OptWeb/continuous/constrained/linearprog/mps.html
%
% Author: Bruno Luong
% Last update: 17/April/2008
if nargin<8 || isempty(PbName)
PbName='GENERIC';
end
idx1=02:03;
idx2=05:12;
idx3=15:22;
idx4=25:36;
idx5=40:47;
idx6=50:61;
idxlist={idx1 idx2 idx3 idx4 idx5 idx6};
[neq nvar]=size(Aeq);
[nle sizeA2]=size(A);
if neq==0 % Aeq is empty, i.e., no equality constraint
nvar=sizeA2;
Aeq=zeros(0,nvar);
elseif nle==0 % A is empty, i.e., no LE constraint
sizeA2=nvar;
A=zeros(0,nvar);
end
elenames=arrayfun(@elename, (1:nle), 'UniformOutput', false);
eqtnames=arrayfun(@eqtname, (1:neq), 'UniformOutput', false);
varnames=arrayfun(@varname, (1:nvar), 'UniformOutput', false);
if nargin<6 || isempty(L)
L=-inf(1,nvar);
elseif isscalar(L) % extend L if it's a scalar input
Lval=L;
L=zeros(1,nvar);
L(:)=Lval;
end
if nargin<7 || isempty(U)
U=+inf(1,nvar);
elseif isscalar(U) % extend U if it's a scalar input
Uval=U;
U=zeros(1,nvar);
U(:)=Uval;
end
%
% Dimension check
%
if length(beq)~=neq || length(b)~=nle || ...
length(cost)~=nvar || ...
length(L)~=nvar || length(U)~=nvar || ...
sizeA2~=nvar
error('BuildMPS: dimensions do not match');
end
l_name=setfields([],0,'NAME');
l_name=setfields(l_name,3,PbName);
l_rows=setfields([],0,'ROWS');
l_cost=setfields([],1,'N',2,'COST');
l_rows_eq=emptyline(neq);
for m=1:neq
l_rows_eq(m,:)=setfields(l_rows_eq(m,:),1,'E',2,eqtnames{m});
end
l_rows_le=emptyline(nle);
for m=1:nle
l_rows_le(m,:)=setfields(l_rows_le(m,:),1,'L',2,elenames{m});
end
CostAeq = [cost(:)'; Aeq; A];
MustWrite = (CostAeq ~= 0);
NWrite = sum(MustWrite,1);
NLines = sum(ceil(NWrite/2));
l_columns=setfields([],0,'COLUMNS');
l_columnsbody=emptyline(NLines);
c=0;
for n=1:nvar
var=varnames{n};
field=3;
for m=1:1+neq+nle
if ~MustWrite(m,n)
continue
end
if m==1
colname='COST';
val = cost(n);
elseif m<=1+neq
colname=eqtnames{m-1};
val=Aeq(m-1,n);
else
colname=elenames{m-(1+neq)};
val=A(m-(1+neq),n);
end
if field==3
c=c+1;
l_columnsbody(c,:)=setfields(l_columnsbody(c,:),...
2,var,...
field,colname, ...
field+1,val);
field=5;
else % field==5
l_columnsbody(c,:)=setfields(l_columnsbody(c,:),...
field,colname, ...
field+1,val);
field=3;
end
end
end
l_columnsbody(c+1:end,:)=[];
rhs=[beq(:); b(:)];
MustWrite = (rhs ~= 0);
NWrite = sum(MustWrite);
NLines = ceil(NWrite/2);
l_rhs=setfields([],0,'RHS');
l_rhsbody=emptyline(NLines);
c=0;
field=3;
for m=1:neq+nle
if ~MustWrite(m)
continue
end
if m<=neq
colname=eqtnames{m};
val=rhs(m);
else
colname=elenames{m-neq};
val=rhs(m);
end
if field==3
c=c+1;
l_rhsbody(c,:)=setfields(l_rhsbody(c,:),...
2,'RHS',...
field,colname, ...
field+1,val);
field=5;
else
l_rhsbody(c,:)=setfields(l_rhsbody(c,:),...
field,colname, ...
field+1,val);
field=3;
end
end
l_rhsbody(c+1:end,:)=[];
l_bound=setfields([],0,'BOUNDS');
upinf=(U==inf);
loinf=(L==-inf);
lonz=(L~=0) & ~loinf;
BoundType=zeros(size(U));
BoundType(:)=3; % Default, 0<=x:
BoundType(upinf & loinf) = 1; % free variable
BoundType(upinf & lonz) = 2; % lo<=x (lo ~= 0)
BoundType(~upinf & lonz) = 4; % lo<=x<=up
BoundType(~upinf & loinf) = 5; % x<=up
BoundType(~upinf & ~loinf & ~lonz) = 6; % 0<=x<=up
NLines = sum(ismember(BoundType,[1 2 6])) + ...
sum(ismember(BoundType,[4 5]))*2;
l_boundbody=emptyline(NLines);
c=0;
for n=1:nvar
var=varnames{n};
lo=L(n);
up=U(n);
if (up==inf)
if (lo==-inf) % Type1, Free variable, one line
c=c+1;
l_boundbody(c,:)=setfields(l_boundbody(c,:),...
1, 'FR', ...
2, 'BND1', ...
3, var, ...
4, 0);
elseif lo~=0 % Type2, lo<=x, one line
c=c+1;
l_boundbody(c,:)=setfields(l_boundbody(c,:),...
1, 'LO', ...
2, 'BND1', ...
3, var, ...
4, lo);
% else 0<=x<=inf: Type3, nothing to write
end
else % up<inf
if lo>-inf
if lo~=0 % Type 4, lo<=x<=up
c=c+1;
l_boundbody(c,:)=setfields(l_boundbody(c,:),...
1, 'LO', ...
2, 'BND1', ...
3, var, ...
4, lo);
%else % 0<=x<=up % Type 6
end
else % if lo==-inf % Type 5, x<=up
c=c+1;
l_boundbody(c,:)=setfields(l_boundbody(c,:),...
1, 'MI', ...
2, 'BND1', ...
3, var, ...
4, 0);
end
% Common Type 4, 5, or 6
% Type 6 is 0<=x<=up
c=c+1;
l_boundbody(c,:)=setfields(l_boundbody(c,:),...
1, 'UP', ...
2, 'BND1', ...
3, var, ...
4, up);
end
end
l_boundbody(c+1:end,:)=[];
l_end=setfields([],0,'ENDATA');
Contain=[l_name; ...
l_rows; ...
l_cost; ...
l_rows_eq; ...
l_rows_le; ...
l_columns; ...
l_columnsbody; ...
l_rhs; ...
l_rhsbody; ...
l_bound; ...
l_boundbody; ...
l_end];
return
function l=emptyline(n)
if nargin<1 || isempty(n)
n=1;
end
l=char(zeros(n,61));
l(:)=' ';
end
function l=setfield(l,field,var)
if isnumeric(var)
var=num2str(var,'%G');
while length(var)>12
i=strfind(var,'+0');
if ~isempty(i)
var(i+1)=[];
continue
end
idot=find(var=='.',1,'first');
iE=find(var=='E',1,'first');
if ~isempty(idot) && ~isempty(iE)
var(iE-1)=[];
continue
end
error('BuildMPS: there is overflow number');
end
end
if isempty(l)
l=emptyline;
end
if ~isempty(field) && field>0
idx=idxlist{field};
else
idx=1:61;
end
if length(var)>length(idx)
var=var(1:length(idx));
else
idx=idx(1:length(var));
end
l(idx)=var;
end
function l=setfields(l, varargin)
for k=1:2:length(varargin)
l=setfield(l, varargin{k}, varargin{k+1});
end
end
function name=elename(m)
name=['LE' num2str(m)];
end
function name=eqtname(m)
name=['EQ' num2str(m)];
end
function name=varname(n)
name=['X' num2str(n)];
end
end
|