GLPK/GMPL Workarounds

This page offers alternative constructions for features that are not specifically supported by GMPL (MathProg).

If–then–else conditional
GLPK does not provide an IF–THEN–ELSE syntax, often useful when post-processing results. Instead use the following syntax:

for {{0}: condition}{        # IF condition THEN } for {{0}: not condition} { # ELSE }                            # ENDIF

The  could be replaced by any set with one element. The  statement will iterate only once over the expression inside the subsequent braces.

The following minimal example creates output with differing line formats, dependent on whether a number is even or odd: for{ c in {1..10} } { for {{0}: c mod 2 == 0} { printf "even\t%d\n", c;  } for {{0}: c mod 2 != 0} { printf "odd\t%d\n", c;  } } end;

Sorted output
It may be desirable to output a sorted sequence. The following example shows how:


 * 1)  sorting_symbolic.mod - how to sort arrays in MathProg
 * 2)  based on code by Andrew Makhorin


 * 1)  Sometimes it is necessary to print parameters or variables in the
 * 2)  order of ascending or descending their values. Suppose, for example,
 * 3)  that we have the following subscripted parameter:

set I;

param a{i in I} := Uniform(2, 7);


 * 1)  If we print all its members:

printf{i in I} "a[%2s] = %g\n", i, a[i];


 * 1)  the output may look like follows:
 * 2)  a[a] = 2.64156
 * 3)  a[b] = 2.04798
 * 4)  a[c] = 2.14843
 * 5)  a[d] = 4.76896
 * 6)  a[e] = 6.09132
 * 7)  a[f] = 3.27780
 * 8)  a[g] = 4.06113
 * 9)  a[h] = 4.05898
 * 10)  a[i] = 6.63120
 * 11)  a[j] = 6.50318
 * 12)  a[k] = 3.46065
 * 13)  a[l] = 4.69845
 * 14)  However, we would like the parameter members to appear in the order
 * 15)  of ascending values.
 * 16)  Introduce the following auxiliary parameter:
 * 1)  of ascending values.
 * 2)  Introduce the following auxiliary parameter:
 * 1)  Introduce the following auxiliary parameter:

param pos{i in I} := card({j in I: a[j] < a[i] or a[j] = a[i] and j < i});


 * 1)  where pos[i] = k - 1 means that in the sorted list member a[i] has
 * 2)  k-th position, 1 <= k <= |I|. Then introduce another auxiliary
 * 3)  parameter:

set ind{k in 1..card(I)} := setof{i in I: pos[i] = k - 1} i;


 * 1)  where ind[k] = {i} iff pos[k] = i.
 * 2)  Now, the following statement:
 * 1)  Now, the following statement:

printf "\n"; printf{k in 1..card(I), l in ind[k]} "a[%2s] = %g\n", l, a[l];


 * 1)  prints the parameter members in the desired order:
 * 2)  a[b] = 2.04798
 * 3)  a[c] = 2.14843
 * 4)  a[a] = 2.64156
 * 5)  a[f] = 3.27780
 * 6)  a[k] = 3.46065
 * 7)  a[h] = 4.05898
 * 8)  a[g] = 4.06113
 * 9)  a[l] = 4.69845
 * 10)  a[d] = 4.76896
 * 11)  a[e] = 6.09132
 * 12)  a[j] = 6.50318
 * 13)  a[i] = 6.63120
 * 1)  a[i] = 6.63120

solve;

data; set I := a b c d e f g h i j k l; end;
 * 1) set I := 1 2 3 4 5 6 7 8 9 10 11 12;

Mimicking an AMPL defined variable
The AMPL language has a construct called defined variables. A defined variable consists of a variable declaration with an equals sign and a term on the right-hand side. Take for example:

var f{k in 1..K} = sum{i in 1..I, j in 1..J} x[i,j,k]*w[i];

Here f is a defined variable. The statement above does not actually declare a structural variable but rather works like a kind of a macro &mdash; so that each occurrence of f[k] is replaced by:

sum{i in 1..I, j in 1..J} x[i,j,k]*w[i]

This construct is not supported in GMPL. But you can use a structural variable and a constraint instead to achieve the same effect &mdash; the downside being that this formulation may render your problem harder to solve:

var f{k in 1..K}; s.t. c1{k in 1..K} : f[k] = sum{i in 1..I, j in 1..J} x[i,j,k]*w[i];

Sets of sets
Sets of sets do not exist in GMPL. Instead an indexing set and an indexed set can be used. The example below shows how to enumerate all subsets of given size of a superset.

/**********************************************
 * For a set of superset S determine all subsets
 * of size m
 * of size m

set S;
 * 1) Superset

param m;
 * 1) Number of elements in subset

param n := card(S);
 * 1) Number of elements in superset

set I := {1 .. m};
 * 1) Set of subset sizes less or equal to m

set J{i in I} := { 1 .. round((prod{a in {1..n}}a) /  (prod{a in {1..i}}a) / (prod{a in {1..n-i}}a)) };
 * 1) Set of indices for a subset of size i of set S

set K := {1 .. n};
 * 1) Set of indices for S

set L{k in K} := setof{s in S : k == sum{t in S : t <= s} 1} s;
 * 1) Set containing the kth member of S

set M{i in I} := {i .. n};
 * 1) Set of integers in [i, n]

param ji{i in I, j in M[i]} := if i==j then 0 else round((prod{a in {1..j-1}}a) /  (prod{a in {1..i}}a) / (prod{a in {1..j-1-i}}a)) ;
 * 1) Number of subsets of size i of a set of size j - 1

set N{i in I, j in J[i]} := if i == 1 then L[j] else N[i-1,j - ji[i,max{k in M[i] : ji[i,k] < j} k]] union L[max{k in M[i] : ji[i,k] < j} k];
 * 1) Subsets j of size i

set C := J[m];
 * 1) Set of subsets of size m

set Sc{c in C} := N[m, c];
 * 1) Elements in subset c

solve;

printf "Last 100 subsets\n"; for {c in C: c > card(C) - 100} { printf "[%d]: ", c; printf {s in Sc[c]} "%s ", s;  printf "\n"; }

printf "\nChecking cardinality\n"; printf {c in C} "%s", if card(Sc[c]) != m then "Wrong cardinality! " else ""; printf "\n";

printf "Checking disjunctness\n"; for {c in C} printf {d in C: d > c} "%s", if card(Sc[c] union Sc[d]) <= m then "Two subsets are the same!" else ""; printf "\n";

printf "Number of subsets = %d\n\n", card(C);

data;

param m:= 4;

set S := A B C D E F G H I J K L;

end;