perm1.gms : Test for various permutations

Description

Contributor: Michael Bussieck

  part 1


Small Model of Type : GAMS


Category : GAMS Test library


Main file : perm1.gms

$title Test for various permutations (PERM1,SEQ=556)

$onText
Contributor: Michael Bussieck
$offText

* part 1
set i / i1*i3 /;
* Set i consists of i1 i2 i3. Since sets can be reordered, we need a second index
* to represent a permutation
set perm1(i,i) / i1.i2, i2.i1, i3.i3 /;
* This set represents in cycle notation: (1 2)(3)

* Using the factorial we can compute the number of all possible
* permutations of i: 3! = 3*2*1 = 6
$eval pmax fact(card(i))
set p permutation index /p1*p%pmax%/;

* For this small set i we can write them all down
set table pall(p,i,i)
       i1  i2  i3
p1.i1   1
p1.i2       1
p1.i3           1

p2.i1   1
p2.i2           1
p2.i3       1

p3.i1       1
p3.i2   1
p3.i3           1

p4.i1       1
p4.i2           1
p4.i3   1

p5.i1           1
p5.i2   1
p5.i3       1

p6.i1           1
p6.i2       1
p6.i3   1
;

* There is also special GAMS syntax to produce the set pall from the set p and i
set pall2(p,i,i); option pall2 > i;

* The order of the permutation depends on how we generate them, but will still
* compare pall and pall2
alias (i,ii);
set error01(p,i,i); error01(p,i,ii) = pall(p,i,ii) xor pall2(p,i,ii);
abort$card(error01) 'permutation pall and pall2 differ', error01;

* This syntax is not limited to one dimensional sets i, we can do the same with
* multidimensional sets:

set j / j1*j2 /, k / k1*k5 /
    jk(j,k) / j1.k3, j1.k5, j2.k1 /;

* jk is a three element set, so we will have 3! = 3*2*1 = 6 permutations
* so we can use the p index to represent all permutations
set pjkall(p,j,k,j,k); option pjkall > jk;

execute_unload 'jk', pjkall;
execute_load 'jk', pjkall;

* pikall will have j1.k3 -> j1.k3, j1.k5 -> j1.k5, j2.k1 -> j2.k1
*                  j1.k3 -> j1.k3, j1.k5 -> j2.k1, j2.k1 -> j1.k5
*                  j1.k3 -> j1.k5, j1.k5 -> j1.k3, j2.k1 -> j2.k1
*                  ...

* We can use our pall set to verify this
set ijk(i,j,k) / #i:#jk /;
set pjkall2(p,j,k,j,k);

loop(pall(p,i,ii),
  pjkall2(p,jk,j,k)$ijk(i,jk) = sum(ijk(ii,j,k),1));

set error02(p,j,k,j,k); error02(p,jk,j,k) = pjkall(p,jk,j,k) xor pjkall2(p,jk,j,k);
abort$card(error02) 'permutation pjkall and pjkall2 differ', error02;

* We can permute set elements using a second index as seen above, but we can
* also permute numerical data in a GAMS parameter.

Parameter a(i) /i1 1, i2 2, i3 3/;

* Here we do not need to have another index we can just represent the
* permutations in the following way

Table paall(p,i)
       i1  i2  i3
p1      1   2   3
p2      1   3   2
p3      2   1   3
p4      2   3   1
p5      3   1   2
p6      3   2   1
;

Parameter paall2(p,i); option paall2 > a;

set error03(p,i); error03(p,i) = paall(p,i) <> paall2(p,i);
abort$card(error03) 'paall and paall2 differ', error03, paall, paall2;

* Note that we can also compute the data permutation from the set permuatation
Parameter paall3(p,i);
paall3(p,i) = sum(pall(p,i,ii), a(ii));

set error04(p,i); error04(p,i) = paall(p,i) <> paall3(p,i);
abort$card(error04) 'paall and paall3 differ', error03, paall, paall3;

* Again data permutations can be also done for multi dimensional parameters
Parameter b(j,k) /j1.k3 1, j1.k5 2, j2.k1 3/;
Table pball(p,j,k)
       j1.k3 j1.k5 j2.k1
p1      1     2     3
p2      1     3     2
p3      2     1     3
p4      2     3     1
p5      3     1     2
p6      3     2     1
;

Parameter pball2(p,j,k); option pball2 > b;

execute_unload 'jk', pball2;
execute_load 'jk', pball2;

set error05(p,j,k); error05(p,jk) = pball(p,jk) <> pball2(p,jk);
abort$card(error05) 'pball and pball2 differ', error05, pball, pball2;

* With the data permutation there is one particularity. If the data contain
* a number twice, for example
Parameter c(i) /i1 1, i2 1, i3 3/;

* The GAMS permutation does not fold the permutations that result in the
* same data record. So we have again 6 permutations where p1=p3, p2=p4 and p5=p6

Table pcall(p,i)
       i1  i2  i3
p1      1   1   3
p2      1   3   1
p3      1   1   3
p4      1   3   1
p5      3   1   1
p6      3   1   1
;

Parameter pcall2(p,i); option pcall2 > c;

set error06(p,i); error06(p,i) = pcall(p,i) <> pcall2(p,i);
abort$card(error06) 'pcall and pcall2 differ', error06, pcall, pcall2;