跳转到内容

GLPK/GMPL 解决方案

来自维基教科书,开放的书,开放的世界

此页面提供了 GMPL (MathProg) 不支持的功能的替代结构。


如果 - 那么 - 否则 条件语句

[编辑 | 编辑源代码]

GLPK 不提供 IF-THEN-ELSE 语法,这在对结果进行后处理时通常很有用。请改用以下语法

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

{0} 可以被任何只有一个元素的集合替换。for 语句将只在后续大括号内的表达式上迭代一次

以下最小示例创建具有不同行格式的输出,这取决于数字是偶数还是奇数

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;

排序输出

[编辑 | 编辑源代码]

您可能希望输出排序序列。以下示例显示了如何操作

#  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;

模拟 AMPL 定义的变量

[编辑 | 编辑源代码]

AMPL 语言有一个称为定义变量的结构。 [1] 定义变量由一个带有等号的变量声明和一个右边的项组成。举个例子

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

这里f是一个定义的变量。上面的语句实际上并没有声明一个结构变量,而是像一种宏一样工作——因此,每个出现的f[k]将被替换为

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

此结构不受 GMPL 支持。但是,您可以使用结构变量和约束来实现相同的效果——缺点是这种公式可能会使您的问题更难解决

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];

集合的集合

[编辑 | 编辑源代码]

GMPL 中不存在集合的集合。相反,可以使用索引集合和索引集合。下面的示例显示了如何枚举给定大小的超集的所有子集。

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

参考文献

[编辑 | 编辑源代码]
  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. 可作为可下载的 PDF 文件获取。
华夏公益教科书