This file contains the following: 1. An awk script (M2A) converting MPS to AMPL data for mps.mod or mps1.mod 2. mps.mod: model for use with M2A and MPS data: short, but may change row order 3. mps1.mod: model for use with M2A and MPS data: preserves row order ============= 1. THE AWK SCRIPT (M2A): #!/bin/sh # Convert MPS to an AMPL data file. # usage: m2a [<]mps.format >ampl.format awk 'BEGIN { printf "data;\nparam :Aij: A :=\n" HUGE = 1.7014118e+38 m = 0 Wrongno = "Wrong number of fields in BOUNDS section!" } function fsplit() { if (NF >= 4) { if (NF == 5) { D1 = $1 D2 = $2 D3 = $3 D4 = $4 D5 = $5 } else { D1 = "\t" D2 = $1 D3 = $2 D4 = $3 D5 = $4 } } else if (NF >= 2) { if (NF == 3) { D1 = $1 D2 = $2 D3 = $3 } else { D1 = "\t" D2 = $1 D3 = $2 } } else { printf "Line %d: got %d fields; expected 2, 3, 4, or 5\n", NR, NF exit 1 } } /^\*/ { next } /^ROWS/ { sc = 1; next } /^COLUMNS/ { sc = 2; next } /^RHS/ { sc = 3; printf ";\nparam b :=\n"; rhsname = ""; next } /^RANGES/ { sc = 4; printf ";\nparam db :=\n"; rngname = ""; next } /^BOUNDS/ { sc = 5; printf ";\nparam ub :=\n" bndname = ""; next } /^ENDATA/ { print ";" printf "param lb :=\n" for(i in lb) printf "\t\"%s\"\t%s\n", i, lb[i] print ";" print "param :I1: ctype :=" for(i = 0; i < m; i++) printf "\t\"%s\"\t%s\n", rn[i], rt[rn[i]] print ";\nend;" exit } {if (sc == 1) { rt[$2] = $1; rn[m++] = $2; next } if (sc == 2) { printf "\t\"%s\"\t\"%s\"\t%s\n", $2, $1, $3 if (NF == 5) printf "\t\"%s\"\t\"%s\"\t%s\n", $4, $1, $5 next } if (sc == 3) { fsplit() if (rhsname == "") rhsname = D1 else if (rhsname != D1) next printf "\t\"%s\"\t%s\n", D2, D3 if (NF >= 4) printf "\t\"%s\"\t%s\n", D4, D5 next } if (sc == 4) { fsplit() if (rngname == "") rngname = D1 else if (rngname != D1) next v = D3 + 0. if (rt[D2] == "E") { if (v > 0.) rt[D2] = "GR" else if (v < 0.) { rt[D2] = "LR"; v = -v; } } else { if (v < 0.) v = -v else if (v == 0.) next if (rt[D2] == "L") rt[D2] = "LR" else if (rt[D2] == "G") rt[D2] = "GR" } if (v != 0) printf "\t\"%s\"\t%.12g\n", D2, v if (NF < 5) next v = D5 + 0. if (rt[D4] == "E") { if (v > 0.) rt[D4] = "GR" else if (v < 0.) { rt[D4] = "LR"; v = -v; } else next } else { if (v < 0.) v = -v else if (v == 0.) next if (rt[D4] == "L") rt[D4] = "LR" else if (rt[D4] == "G") rt[D4] = "GR" } printf "\t\"%s\"\t%.12g\n", D4, v } if (sc == 5) { if ($1 == "FR" || $1 == "MI") { if (NF == 2 || NF == 3) { lb[$NF] = -HUGE next } print Wrongno printf "Input line %d = \"%s\"\n", NR, $0 exit } if (NF == 4) { if (bndname == "") bndname = $2 else if (bndname != $2) next vname = $3 bval = $4 } else if (NF == 3) { # blank BOUND set name if (bndname == "") bndname = "\t" else if (bndname != "\t") next vname = $2 bval = $3 } else { print Wrongno printf "Input line %d = \"%s\"\n", NR, $0 exit } if ($1 == "LO") { lb[vname] = bval; next } if ($1 == "UP") { printf "\t\"%s\"\t%s\n", vname, bval; next } if ($1 == "FX") { lb[vname] = bval printf "\t\"%s\"\t%s\n", vname, bval; next } if ($1 == "PL") { next } printf "unexpected type %s in bounds section\n", $1 | "cat 1>&2" exit } }' $* ====================== 2. MPS.MOD # AMPL model for an MPS file: this is short, but it may # change the row order (which could affect pivot choice # by simplex-based solvers). # Use the awk script "m2a" to turn an MPS file into suitable data. set Aij dimen 2; #constraint matrix indices set I1; # to allow empty rows set J := setof{(i,j) in Aij} j; #columns param A{Aij}; #constraint matrix nonzeros param b{I1} default 0; #right-hand side param db{I1}; #for ranges set ctypes := {'N', 'L', 'E', 'G', 'LR', 'GR'}; param ctype{I1} symbolic within ctypes; param lb{J} default 0; param ub{J} default Infinity; var x{j in J} >= if lb[j] <= -1.7e38 then -Infinity else lb[j] <= ub[j]; set zork := setof{i in I1} (i,ctype[i]); minimize Obj{(i,'N') in zork}: sum{(i,j) in Aij} A[i,j]*x[j]; E{(i,'E') in zork}: sum{(i,j) in Aij} A[i,j]*x[j] == b[i]; L{(i,'L') in zork}: sum{(i,j) in Aij} A[i,j]*x[j] <= b[i]; G{(i,'G') in zork}: sum{(i,j) in Aij} A[i,j]*x[j] >= b[i]; LR{(i,'LR') in zork}: b[i] - db[i] <= sum{(i,j) in Aij} A[i,j]*x[j] <= b[i]; GR{(i,'GR') in zork}: b[i] + db[i] >= sum{(i,j) in Aij} A[i,j]*x[j] >= b[i]; ====================== 3. MPS1.MOD # AMPL model for an MPS file: this one preserves row order. # Use the awk script "m2a" to turn an MPS file into suitable data. set Aij dimen 2; #constraint matrix indices set I1; # to allow empty rows set J := setof{(i,j) in Aij} j; #columns param A{Aij}; #constraint matrix nonzeros param b{I1} default 0; #right-hand side param db{I1}; #for ranges set ctypes := {'N', 'L', 'E', 'G', 'LR', 'GR'}; param ctype{I1} symbolic within ctypes; param lb{J} default 0; param ub{J} default Infinity; var x{j in J} >= if lb[j] <= -1.7e38 then -Infinity else lb[j] <= ub[j]; set zork := setof{i in I1} (i,ctype[i]); c{i in I1: ctype[i] != 'N'}: (if ctype[i] == 'N' || ctype[i] == 'L' then -Infinity else if ctype[i] == 'G' || ctype[i] == 'GR' || ctype[i] == 'E' then b[i] else b[i] - db[i]) <= sum{(i,j) in Aij} A[i,j]*x[j] <= (if ctype[i] == 'N' || ctype[i] == 'G' then Infinity else if ctype[i] == 'L' || ctype[i] == 'LR' || ctype[i] == 'E' then b[i] else b[i] + db[i]); minimize Obj{(i,'N') in zork}: sum{(i,j) in Aij} A[i,j]*x[j];