BuildMPS

PURPOSE ^

SYNOPSIS ^

function [Contain OK]=BuildMPS(A, b, Aeq, beq, cost, L, U, PbName, varargin)

DESCRIPTION ^

 function Contain=BuildMPS(A, b, Aeq, beq, cost, L, U, PbName); OR
          Contain=BuildMPS(..., Param1, Value1, ...);

 Build ascii fixed-width MPS matrix string that contains linear
 programming (LP) problem:

 Minimizing (for x in R^n): f(x) = cost'*x, subject to
       A*x <= b        (LE)
       Aeq*x = beq     (EQ)
       L <= x <= U     (BD).

 Also supported is integer/mixte programming problem similar to the above,
 where a subset of components of x is restricted to be integer (N set) or
 binary set {0,1}.

 INPUTS:
   A: (m x n) matrix
   b: (m x 1) matrix
   Aeq: (k x n) matrix
   beq: (k x 1) matrix
   cost: (n x 1) matrix
   L: (1 x n), (n x 1) or (1 x 1)
   U: (1 x n), (n x 1) or (1 x 1)

 Remark: To disable constraint(s) (LE, EQ, BD), please use empty []
         for corresponding input matrix/rhs parameters.

 Optional:
   - PbName is a string of problem name, default value is 'GENERIC'.
 Other Params:
    'EltNames', 'EqtNames', or 'VarNames'
     Cells contain string of respectively
        (LE) equations, (EQ) equations, or variable names
   - 'EltNameFun', 'EqtNameFun', or 'VarNameFun'
     Corresponding Value are function handles that return
     Equation/Variable name from equation/Variable number
       Example: > VarNameFun=@(m) char('x'+(m-1));
     These functions will NOT be used if names of equations/variables
     are defined.
   - Param is 'MPSfilename': output MPS file to be saved
     No saving if MPSfilename is undefined.
   - 'I', 'Int' 'Integer', 'Integers'
       Array that stores the index of the set of integer variables (>=0).
       The indexes must belong to [1,..., n] and correspond to the column
       of A, Aeq.
   - 'B', 'Bin' 'Binary', 'Binaries'
       Array that stores the index of the set of binary variables {0,1}.
       Indexes follow the same convention as with integer case.

 OUTPUT:
   Contain: char matrix of the MPS format description of LP/IP problem.

 RESTRICTION:
   Only single rhs (b and beq) is supported.

 The MPS (Mathematical Programming System) file format was introduced by
 IBM in 1970s, but has also been accepted by most subsequent linear
 programming codes. To learn about MPS format, please see:
   http://lpsolve.sourceforge.net/5.5/mps-format.htm

 See also: SaveMPS

 Usage example:

   A = [1 1 0; -1 0 -1];
   b = [5; -10];
   L = [0; -1; 0];
   U = [4; +1; +inf];
   Aeq = [0 -1 1];
   beq = 7;
   cost = [1 4 9];
   VarNameFun = @(m) (char('x'+(m-1))); % returning varname 'x', 'y' 'z'

   Contain = BuildMPS(A, b, Aeq, beq, cost, L, U, 'Pbtest', ...
                      'VarNameFun', VarNameFun, ...
                      'EqtNames', {'Equality'}, ...
                       'Integer', [1], ... % first variable 'x' is integer
                      'MPSfilename', 'Pbtest.mps');

 Author: Bruno Luong
 update: 15-Jul-2008: sligly improved number formatting
         25-Aug-2009: Improvement in handling sparse matrix
         03-Sep-2009: integer/binary variables

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [Contain OK]=BuildMPS(A, b, Aeq, beq, cost, L, U, PbName, varargin)
0002 %
0003 % function Contain=BuildMPS(A, b, Aeq, beq, cost, L, U, PbName); OR
0004 %          Contain=BuildMPS(..., Param1, Value1, ...);
0005 %
0006 % Build ascii fixed-width MPS matrix string that contains linear
0007 % programming (LP) problem:
0008 %
0009 % Minimizing (for x in R^n): f(x) = cost'*x, subject to
0010 %       A*x <= b        (LE)
0011 %       Aeq*x = beq     (EQ)
0012 %       L <= x <= U     (BD).
0013 %
0014 % Also supported is integer/mixte programming problem similar to the above,
0015 % where a subset of components of x is restricted to be integer (N set) or
0016 % binary set {0,1}.
0017 %
0018 % INPUTS:
0019 %   A: (m x n) matrix
0020 %   b: (m x 1) matrix
0021 %   Aeq: (k x n) matrix
0022 %   beq: (k x 1) matrix
0023 %   cost: (n x 1) matrix
0024 %   L: (1 x n), (n x 1) or (1 x 1)
0025 %   U: (1 x n), (n x 1) or (1 x 1)
0026 %
0027 % Remark: To disable constraint(s) (LE, EQ, BD), please use empty []
0028 %         for corresponding input matrix/rhs parameters.
0029 %
0030 % Optional:
0031 %   - PbName is a string of problem name, default value is 'GENERIC'.
0032 % Other Params:
0033 %    'EltNames', 'EqtNames', or 'VarNames'
0034 %     Cells contain string of respectively
0035 %        (LE) equations, (EQ) equations, or variable names
0036 %   - 'EltNameFun', 'EqtNameFun', or 'VarNameFun'
0037 %     Corresponding Value are function handles that return
0038 %     Equation/Variable name from equation/Variable number
0039 %       Example: > VarNameFun=@(m) char('x'+(m-1));
0040 %     These functions will NOT be used if names of equations/variables
0041 %     are defined.
0042 %   - Param is 'MPSfilename': output MPS file to be saved
0043 %     No saving if MPSfilename is undefined.
0044 %   - 'I', 'Int' 'Integer', 'Integers'
0045 %       Array that stores the index of the set of integer variables (>=0).
0046 %       The indexes must belong to [1,..., n] and correspond to the column
0047 %       of A, Aeq.
0048 %   - 'B', 'Bin' 'Binary', 'Binaries'
0049 %       Array that stores the index of the set of binary variables {0,1}.
0050 %       Indexes follow the same convention as with integer case.
0051 %
0052 % OUTPUT:
0053 %   Contain: char matrix of the MPS format description of LP/IP problem.
0054 %
0055 % RESTRICTION:
0056 %   Only single rhs (b and beq) is supported.
0057 %
0058 % The MPS (Mathematical Programming System) file format was introduced by
0059 % IBM in 1970s, but has also been accepted by most subsequent linear
0060 % programming codes. To learn about MPS format, please see:
0061 %   http://lpsolve.sourceforge.net/5.5/mps-format.htm
0062 %
0063 % See also: SaveMPS
0064 %
0065 % Usage example:
0066 %
0067 %   A = [1 1 0; -1 0 -1];
0068 %   b = [5; -10];
0069 %   L = [0; -1; 0];
0070 %   U = [4; +1; +inf];
0071 %   Aeq = [0 -1 1];
0072 %   beq = 7;
0073 %   cost = [1 4 9];
0074 %   VarNameFun = @(m) (char('x'+(m-1))); % returning varname 'x', 'y' 'z'
0075 %
0076 %   Contain = BuildMPS(A, b, Aeq, beq, cost, L, U, 'Pbtest', ...
0077 %                      'VarNameFun', VarNameFun, ...
0078 %                      'EqtNames', {'Equality'}, ...
0079 %                       'Integer', [1], ... % first variable 'x' is integer
0080 %                      'MPSfilename', 'Pbtest.mps');
0081 %
0082 % Author: Bruno Luong
0083 % update: 15-Jul-2008: sligly improved number formatting
0084 %         25-Aug-2009: Improvement in handling sparse matrix
0085 %         03-Sep-2009: integer/binary variables
0086 
0087 if nargin<8 || isempty(PbName)
0088     PbName='GENERIC';
0089 end
0090 
0091 %
0092 % Columns indices of MPS fields
0093 %
0094 idx1=02:03;
0095 idx2=05:12;
0096 idx3=15:22;
0097 idx4=25:36;
0098 idx5=40:47;
0099 idx6=50:61;
0100 idxlist={idx1 idx2 idx3 idx4 idx5 idx6};
0101 
0102 %
0103 % Default returned value if error occurs
0104 %
0105 Contain=[]; %#ok
0106 OK = 0;  %#ok
0107 
0108 %
0109 % Get the size of the input matrices
0110 %
0111 [neq nvar]=size(Aeq);
0112 [nle sizeA2]=size(A);
0113 
0114 if neq==0 % Aeq is empty, i.e., no equality constraint
0115     nvar=sizeA2;
0116     Aeq=zeros(0,nvar);
0117 elseif nle==0 % A is empty, i.e., no LE constraint
0118     sizeA2=nvar;
0119     A=zeros(0,nvar);
0120 end
0121 
0122 %
0123 % Default values for naming functions (nested functions)
0124 %
0125 elenamefun = @elename;
0126 eqtnamefun = @eqtname;
0127 varnamefun = @varname;
0128 MPSfilename = ''; % MPSfilename
0129 
0130 % default empty integer and binary sets
0131 iset = [];
0132 bset = [];
0133 
0134 %
0135 % Parse options (varargin)
0136 %
0137 parseoptions(varargin{:});
0138 
0139 if ~exist('elenames','var')
0140     elenames=arrayfun(elenamefun, (1:nle), 'UniformOutput', false);
0141 end
0142 if ~exist('eqtnames','var')
0143     eqtnames=arrayfun(eqtnamefun, (1:neq), 'UniformOutput', false);
0144 end
0145 if ~exist('varnames','var')
0146     varnames=arrayfun(varnamefun, (1:nvar), 'UniformOutput', false);
0147 end
0148 
0149 if nargin<6 || isempty(L)
0150     L=-inf(1,nvar);
0151 elseif isscalar(L) % extend L if it's a scalar input
0152     Lval=L;
0153     L=zeros(1,nvar);
0154     L(:)=Lval;
0155 else % BUG corrected, reshape L in row
0156     L = reshape(L,1,[]);
0157 end
0158 if nargin<7 || isempty(U)
0159     U=+inf(1,nvar);
0160 elseif isscalar(U) % extend U if it's a scalar input
0161     Uval=U;
0162     U=zeros(1,nvar);
0163     U(:)=Uval;
0164 else % BUG corrected, reshape U in row
0165     U = reshape(U,1,[]);
0166 end
0167 
0168 %
0169 % Dimension check
0170 %
0171 if length(beq)~=neq || length(b)~=nle || ...
0172    length(cost)~=nvar || ...
0173    length(L)~=nvar || length(U)~=nvar || ...
0174    sizeA2~=nvar
0175     error('BuildMPS:DimensionsUnMatched', ...
0176           'BuildMPS: dimensions do not match');
0177 end
0178 
0179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0180 % Set problem name
0181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0182 l_name=setfields([],0,'NAME');
0183 l_name=setfields(l_name,3,PbName);
0184 
0185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0186 % Set equations in ROWS and COST
0187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0188 l_rows=setfields([],0,'ROWS');
0189 
0190 l_cost=setfields([],1,'N',2,'COST');
0191 
0192 l_rows_eq=emptyline(neq);
0193 for m=1:neq
0194     l_rows_eq(m,:)=setfields(l_rows_eq(m,:),1,'E',2,eqtnames{m});
0195 end
0196 
0197 l_rows_le=emptyline(nle);
0198 for m=1:nle
0199     l_rows_le(m,:)=setfields(l_rows_le(m,:),1,'L',2,elenames{m});
0200 end
0201 
0202 CostAeq = [cost(:)'; Aeq; A]; % CostAeq is sparse if any is sparse
0203 MustWrite = (CostAeq ~= 0);
0204 NWrite = sum(MustWrite,1);
0205 NLines = sum(ceil(NWrite/2));
0206 
0207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0208 % Set coefficients of constraint equations in COLUMNS
0209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0210 l_columns=setfields([],0,'COLUMNS');
0211 l_columnsbody=emptyline(NLines);
0212 
0213 c=0;
0214 for n=1:nvar % Loop over variables
0215     var=varnames{n};
0216     field=3;
0217     eqtn = find(MustWrite(:,n)); % subset of (1:1+neq+nle)
0218     for m=eqtn(:).' % 1:1+neq+nle % Loop over eqt
0219         if m==1
0220             colname='COST';
0221             val = cost(n);
0222         elseif m<=1+neq
0223             colname=eqtnames{m-1};
0224             val=Aeq(m-1,n);
0225         else
0226             colname=elenames{m-(1+neq)};
0227             val=A(m-(1+neq),n);            
0228         end
0229         if field==3
0230             c=c+1;
0231             l_columnsbody(c,:)=setfields(l_columnsbody(c,:),...
0232                 2,var,...
0233                 field,colname, ...
0234                 field+1,val);
0235             field=5;
0236         else % field==5
0237             l_columnsbody(c,:)=setfields(l_columnsbody(c,:),...
0238                 field,colname, ...
0239                 field+1,val);
0240             field=3;
0241         end
0242     end % for-loop eqt
0243 end % for-loop variables
0244 l_columnsbody(c+1:end,:)=[];
0245 
0246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0247 % Set equation RHS
0248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0249 rhs=[beq(:); b(:)];
0250 MustWrite = (rhs ~= 0);
0251 NWrite = sum(MustWrite);
0252 NLines = ceil(NWrite/2);
0253 
0254 l_rhs=setfields([],0,'RHS');
0255 l_rhsbody=emptyline(NLines);
0256 c=0;
0257 field=3;
0258 eqt = find(MustWrite); % subset of (1:neq+nle)
0259 for m=eqt(:).' % 1:neq+nle % Loop over eqt
0260     if m<=neq
0261         colname=eqtnames{m};
0262         val=rhs(m);
0263     else
0264         colname=elenames{m-neq};
0265         val=rhs(m);
0266     end
0267     if field==3
0268         c=c+1;
0269         l_rhsbody(c,:)=setfields(l_rhsbody(c,:),...
0270             2,'RHS',...
0271             field,colname, ...
0272             field+1,val);
0273         field=5;
0274     else
0275         l_rhsbody(c,:)=setfields(l_rhsbody(c,:),...
0276             field,colname, ...
0277             field+1,val);
0278         field=3;
0279     end
0280 end % for-loop eqt
0281 l_rhsbody(c+1:end,:)=[];
0282 
0283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0284 % Set bound constraints
0285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0286 l_bound=setfields([],0,'BOUNDS');
0287 
0288 VarType=zeros(size(U));
0289 %
0290 % Var types (local definition)
0291 %
0292 VarType(:)=0; % real
0293 VarType(iset) = 1; % integer
0294 VarType(bset) = 2; % binary
0295 
0296 % Force lower/upper bound for integer variables to be integer as well
0297 L(iset) = max(ceil(L(iset)),0); % integer lower bound cannot be negative
0298 U(iset) = floor(U(iset));
0299 
0300 % Values not used, but we set for clarity
0301 L(bset) = 0;
0302 U(bset) = 1;
0303 
0304 upinf=(U==inf);
0305 loinf=(L==-inf);
0306 lonz=(L~=0) & ~loinf;
0307 
0308 BoundType=zeros(size(U));
0309 
0310 %
0311 % Bound types (local definition)
0312 %
0313 BoundType(:) = 3; % Default, 0<=x, real variable
0314 BoundType(upinf & loinf) = 1; % free, real
0315 BoundType(upinf & lonz) = 2; % lo<=x (lo ~= 0), real
0316 BoundType(~upinf & lonz) = 4; % lo<=x<=up, integer or real
0317 BoundType(~upinf & loinf) = 5; % x<=up, real
0318 BoundType(~upinf & ~loinf & ~lonz) = 6; % 0<=x<=up, integer or real
0319 BoundType(upinf & VarType==1) = 7; %  lo<=x, integer
0320 BoundType(bset) = 8; % binary, x = 0 or 1
0321 
0322 NLines = sum(ismember(BoundType,[1 2 6 7 8])) + ...
0323          sum(ismember(BoundType,[4 5]))*2;
0324 l_boundbody=emptyline(NLines);
0325 c=0;
0326 for n=1:nvar
0327     var=varnames{n};
0328     lo=L(n);
0329     up=U(n);
0330     vtype = VarType(n);
0331     if (vtype==2) % Type 8, binary variables
0332         c=c+1;
0333         l_boundbody(c,:)=setfields(l_boundbody(c,:),...
0334             1, 'BV', ...
0335             2, 'BND1', ...
0336             3, var, ...
0337             4, 1); % Field 4 must be 1.0 or blank
0338     elseif (up==inf)
0339         if (lo==-inf) % Type 1, Free real variable, one line
0340             c=c+1;
0341             l_boundbody(c,:)=setfields(l_boundbody(c,:),...
0342                 1, 'FR', ...
0343                 2, 'BND1', ...
0344                 3, var, ...
0345                 4, 0);
0346         elseif (lo~=0) || (vtype==1) % Type 2, or Type 7 lo<=x, one line
0347             c = c+1;
0348             if vtype==1 % integer, Type 7
0349                 LOstr = 'LI';
0350             else % real, Type 2
0351                 LOstr = 'LO';
0352             end
0353             l_boundbody(c,:)=setfields(l_boundbody(c,:),...
0354                 1, LOstr, ...
0355                 2, 'BND1', ...
0356                 3, var, ...
0357                 4, lo);
0358         % else 0<=x<=inf: Type3, real variable nothing to write
0359         end
0360     else % up<inf
0361         if lo>-inf
0362             if lo~=0 % Type 4, lo<=x<=up
0363                 c=c+1;
0364                 if vtype==1 % integer
0365                     LOstr = 'LI';
0366                 else % real
0367                     LOstr = 'LO';
0368                 end
0369                 l_boundbody(c,:)=setfields(l_boundbody(c,:),...
0370                     1, LOstr, ...
0371                     2, 'BND1', ...
0372                     3, var, ...
0373                     4, lo);
0374             %else % 0<=x<=up % Type 6
0375             end
0376         else % if lo==-inf % Type 5, x<=up
0377             c=c+1;
0378             l_boundbody(c,:)=setfields(l_boundbody(c,:),...
0379                 1, 'MI', ...
0380                 2, 'BND1', ...
0381                 3, var, ...
0382                 4, 0);
0383         end
0384         % Common Type 4, 5, or 6
0385         % Type 6 is 0<=x<=up
0386         c=c+1;
0387         if vtype==1 % integer
0388             HIstr = 'UI';
0389         else % real
0390             HIstr = 'UP';
0391         end
0392         l_boundbody(c,:)=setfields(l_boundbody(c,:),...
0393             1, HIstr, ...
0394             2, 'BND1', ...
0395             3, var, ...
0396             4, up);
0397     end
0398 end % for-loop on variable
0399 l_boundbody(c+1:end,:)=[];
0400 
0401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0402 % Set the last card
0403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0404 l_end=setfields([],0,'ENDATA');
0405 
0406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0407 % Concatenate together all parts of mps format
0408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0409 Contain=[l_name; ...
0410     l_rows; ...
0411     l_cost; ...
0412     l_rows_eq; ...
0413     l_rows_le; ...
0414     l_columns; ...
0415     l_columnsbody; ...
0416     l_rhs; ...
0417     l_rhsbody; ...
0418     l_bound; ...
0419     l_boundbody; ...
0420     l_end];
0421 
0422 if ~isempty(MPSfilename)
0423     %
0424     % Save the Contain in MPSfilename
0425     %
0426     OK = SaveMPS(MPSfilename, Contain);
0427     if ~OK % Something is wrong during saving
0428         warning('BuildMPS:SavingFailure', ...
0429                 ['BuildMPS: Cannot save ' MPSfilename]);
0430     end
0431 else % Nothing to save
0432     OK = 1;
0433 end
0434 
0435 % return % Uncomment the RETURN statement causes M-lint to crash on 2009A
0436 % There is no instructions from now on, juts nested functions
0437 
0438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0439 % Nested functions: BE AWARE, the functions have access to local
0440 % variables of BuildMPS
0441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0442 
0443    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0444    % Generate n empty lines of MPS data
0445    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0446     function l=emptyline(n)
0447         if nargin<1 || isempty(n)
0448             n=1;
0449         end
0450         l=char(zeros(n,61));
0451         l(:)=' ';
0452     end
0453 
0454    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0455    % Convert to string at the fixed length of 12
0456    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0457     function str=num2fixedlengthstr(num, maxlength, roundingflag)
0458         % function str=num2fixedlengthstr(num); OR
0459         % str=num2fixedlengthstr(..., maxlength, roundingflag);
0460         %
0461         % Convert double NUM to decimal string having MAXLENGTH [12] as maximum
0462         % length. Smart conversion with accurate result despite length constraint.
0463         %
0464         % ROUNDINGFLAG: 0 or [1]
0465         %   0: truncate fracional part (quicker)
0466         %   1: rounding fracional part (more accurate).
0467         %
0468         % Last update: 15/Aug/2008, remove leading "0" when the string starts
0469         %              as "0.xxxx"
0470         %
0471         if nargin<2
0472             maxlength=12;
0473         end
0474 
0475         if nargin<3
0476             roundingflag=1; % rounding by default
0477         end
0478 
0479         if num>=0
0480             fracNDigits=maxlength;
0481         else
0482             fracNDigits=maxlength-1;
0483         end
0484         % "%G" format:
0485         % ANSI specification X3.159-1989: "Programming Language C,"
0486         % ANSI, 1430 Broadway, New York, NY 10018.
0487         str=num2str(num,['%0.' num2str(fracNDigits) 'G']);
0488         %
0489         % Try to compact the string data to fit inside the field length
0490         %
0491         while length(str)>maxlength
0492             if regexp(str,'^0\.') % delete the leading 0 in "0.xxx"
0493                 str(1)=[];
0494                 continue;
0495             end
0496             [istart iend]=regexp(str,'[+-](0)+'); % +/- followed by multiples 0
0497             if ~isempty(istart) % Remove zero in xxxE+000yy or xxxE-000yy
0498                 str(istart+1:iend)=[];
0499                 continue
0500             else
0501                 [istart iend]=regexp(str,'E[+]');
0502                 if ~isempty(istart) % Remove "+" char in xxxE+yyy
0503                     str(iend)=[];
0504                     continue
0505                 end
0506             end
0507             idot=find(str=='.',1,'first');
0508             if ~isempty(idot)
0509                 iE=find(str=='E',1,'first');
0510                 if roundingflag % rounding fraction part
0511                     % Calculate the Length of the fractional part
0512                     % Adjust its number of digits and start over again
0513                     if ~isempty(iE) % before the mantissa
0514                         fracNDigits=maxlength-length(str)+iE-idot-1;
0515                         str=num2str(num,['%0.' num2str(fracNDigits) 'E']);
0516                     else %if idot<=maxlength+1 % no manissa
0517                         fracNDigits=maxlength-idot;
0518                         str=num2str(num,['%0.' num2str(fracNDigits) 'f']);
0519                     end
0520                     roundingflag=0; % won't do rounding again
0521                     continue % second pass with new string
0522                 else
0523                     % truncate the fractional part
0524                     if ~isempty(iE) % before the mantissa
0525                         str(maxlength-length(str)+iE:iE-1)=[];
0526                         return;
0527                     else %if idot<=maxlength+1 % no mantissa
0528                         str(maxlength+1:end)=[];
0529                         return;
0530                     end
0531                 end
0532             end
0533             % it should not never go here, unless BUG
0534             error('BuildMPS: cannot convert %0.12e to string\n',num);
0535         end % while loop
0536 
0537     end
0538 
0539     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0540     % Set the field of an MPS line by value
0541     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0542     function l=setfield(l,field,var)
0543 
0544         if isnumeric(var) % numerical data, convert to string
0545             var=num2fixedlengthstr(var); % convert to 12-length string
0546         end
0547 
0548         if isempty(l)
0549             l=emptyline;
0550         end
0551         if ~isempty(field) && field>0
0552             idx=idxlist{field};
0553         else
0554             idx=1:61;
0555         end
0556         if length(var)>length(idx)
0557             var=var(1:length(idx));
0558         else
0559             idx=idx(1:length(var));
0560         end
0561         l(idx)=var;
0562 
0563     end
0564 
0565     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0566     % Set multiple fields of an MPS line by values
0567     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0568     function l=setfields(l, varargin)
0569         for k=1:2:length(varargin)
0570             l=setfield(l, varargin{k}, varargin{k+1});
0571         end
0572     end
0573 
0574     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0575     % Generate equation name for (LE) constraint
0576     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0577     function name=elename(m)
0578         name=['LE' num2str(m)];
0579     end
0580 
0581     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0582     % Generate equation name for (EQ) constraint
0583     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0584     function name=eqtname(m)
0585         name=['EQ' num2str(m)];
0586     end
0587 
0588     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0589     % Generate variable name
0590     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0591     function name=varname(n)
0592         name=['X' num2str(n)];
0593     end
0594 
0595     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0596     % Parse a pair of Name/Value option
0597     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0598     function parseoption(strname, value)
0599         if ischar(strname)
0600             strname = strtrim(lower(strname));
0601             switch strname
0602                 case 'elenames',                   
0603                     if ~iscell(value) || length(value)~=nle || ...
0604                         ~all(cellfun(@ischar, value))
0605                         error('BuildMPS:IncorrectEleNames', ...
0606                     'BuildMPS: EleNames must be cell of %d strings', nle);
0607                     end
0608                     elenames = value;
0609                 case 'eqtnames',
0610                     if ~iscell(value) || length(value)~=neq || ...
0611                             ~all(cellfun(@ischar, value))
0612                         error('BuildMPS:IncorrectEqtNames', ...
0613                     'BuildMPS: EqtNames must be cell of %d strings', neq);
0614                     end
0615                     eqtnames = value;
0616                 case 'varnames',
0617                     if ~iscell(value) || length(value)~=nvar || ...
0618                             ~all(cellfun(@ischar, value))
0619                         error('BuildMPS:IncorrectVarNames', ...
0620                     'BuildMPS: VarNames must be cell of %d strings', nvar);
0621                     end
0622                     varnames = value;
0623                 case 'varnamefun',
0624                     if ischar(value)
0625                         value=str2func(value);
0626                     end
0627                     if ~isa(value,'function_handle')
0628                         error('BuildMPS:IncorrectVarNameFun', ...
0629                               'BuildMPS: VarNameFun must be a function');
0630                     end
0631                     varnamefun = value;
0632                 case 'eqtnamefun',
0633                     if ischar(value)
0634                         value=str2func(value);
0635                     end
0636                     if ~isa(value,'function_handle')
0637                         error('BuildMPS:IncorrectEqtNameFun', ...
0638                               'BuildMPS: EqtNameFun must be a function');
0639                     end
0640                     eqtnamefun = value;
0641                 case 'elenamefun',
0642                     if ischar(value)
0643                         value=str2func(value);
0644                     end
0645                     if ~isa(value,'function_handle')
0646                         error('BuildMPS:IncorrectEleNameFun', ...
0647                               'BuildMPS: EleNameFun must be a function');
0648                     end
0649                     elenamefun = value;
0650                 case 'mpsfilename',
0651                     if ~ischar(value)
0652                         error('BuildMPS:IncorrectMPSfilename', ...
0653                               'BuildMPS: MPSfilename must be a string');
0654                     end
0655                     MPSfilename = value;
0656                 case  {'i' 'int' 'integer' 'integers'},
0657                     iset = value(:);
0658                     if any(iset<1 | iset>nvar)
0659                         error('Integer set contains invalid index');
0660                     end
0661                 case {'b' 'bin' 'binary', 'binaries'},
0662                     bset = value(:);
0663                     if any(bset<1 | bset>nvar)
0664                         error('Binary set contains invalid index');                        
0665                     end
0666                 otherwise
0667                     warning('BuildMPS:UnknownParams', ...
0668                         ['BuildMPS: Unknown parameter ' strname]);
0669             end
0670         else
0671             error('BuildMPS:IncorrectCall', ...
0672                   'BuildMPS: options must be pair of Name/Value');
0673         end
0674     end
0675 
0676     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0677     % Parse options
0678     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0679     function parseoptions(varargin)
0680         if mod(nargin,2)
0681             error('BuildMPS:IncorrectCall', ...
0682                   'BuildMPS: options must be pair of Name/Value');            
0683         end
0684         %
0685         % Loop over pair of Name/Value option
0686         %
0687         for ivararg=1:2:nargin
0688             parseoption(varargin{ivararg},varargin{ivararg+1});
0689         end
0690     end
0691 
0692 end % BuildMPS

Generated on Thu 21-Jun-2012 15:39:23 by m2html © 2003