GLPK/GMPL Workarounds

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


If–then–else conditional edit

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 {0} could be replaced by any set with one element. The for 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 edit

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

#  sorting_symbolic.mod - how to sort arrays in MathProg
#  based on code by Andrew Makhorin

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

set I;

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

#  If we print all its members:

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

#  the output may look like follows:
#
#  a[a] = 2.64156
#  a[b] = 2.04798
#  a[c] = 2.14843
#  a[d] = 4.76896
#  a[e] = 6.09132
#  a[f] = 3.27780
#  a[g] = 4.06113
#  a[h] = 4.05898
#  a[i] = 6.63120
#  a[j] = 6.50318
#  a[k] = 3.46065
#  a[l] = 4.69845
#
#  However, we would like the parameter members to appear in the order
#  of ascending values.
#
#  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});

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

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

#  where ind[k] = {i} iff pos[k] = i.
#
#  Now, the following statement:

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

#  prints the parameter members in the desired order:
#
#  a[b] = 2.04798
#  a[c] = 2.14843
#  a[a] = 2.64156
#  a[f] = 3.27780
#  a[k] = 3.46065
#  a[h] = 4.05898
#  a[g] = 4.06113
#  a[l] = 4.69845
#  a[d] = 4.76896
#  a[e] = 6.09132
#  a[j] = 6.50318
#  a[i] = 6.63120

solve;

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

Mimicking an AMPL defined variable edit

The AMPL language has a construct called defined variables. [1] 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 — 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 — 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 edit

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
*
**********************************************/

# Superset
set S; 

# Number of elements in subset
param m;

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

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

# Set of indices for a subset of size i of set S
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)) };

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

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

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

# Number of subsets of size i of a set of size j - 1
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)) ;

# Subsets j of size i
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];

# Set of subsets of size m
set C := J[m]; 

# Elements in subset c
set Sc{c in C} := N[m, 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;

References edit

  1. Fourer, Robert; Gay, David M.; Kerningham, Brian W. (2002). AMPL : a modeling language for mathematical programming (2nd ed.). Duxbury Press. p. 131. ISBN 978-0534388096. Available as a downloadable PDF.