Table of Contents
Introduction
The option
statement is used to set various global system parameters to control among other things output detail, the solution process and the layout of displays. GAMS provides default values for global system parameters that are adequate for the most purposes. However, there are always cases when the user would like to maintain control of some aspects of the run. In addition, the option statement provides an efficient and compact syntax to perform powerful operations on identifiers. Observe that option statements are processed at execution time unlike dollar control options that are processed at compile time.
This chapter is organized as follows. We will first introduce the general syntax of the option statement, then we will continue with a list of all available options that may be used with option statements and provide links to their detailed explanations in the GAMS Call chapter. Finally we turn to the special options that involve identifiers.
The Syntax of the Option Statement
The general form of an option statement is as follows:
option(s) key1 [= value1] { ,|EOL key2 [= value2] } ;
The keyword option
or options
indicates that this is an option statement. It is followed by key1
, which is one of the options that are listed in this chapter. Consider the following simple example:
option reslim=800;
Here the keyword option
is followed by the key
reslim. The option reslim
specifies the maximum time in seconds that a solver may run before it terminates. Thus, in this example we give the solver 800 seconds to come up with a solution.
- Note
- Option names are not reserved words and therefore they do not conflict with other uses of their names.
- Option statements do not allow expressions. It is therefore not possible to assign parameter values to an option.
The following doesn't work:
However, if the desired option is available as model attribute, one can assign parameter values there:scalar p /3/; option reslim=p;
scalar p /3/; transport.reslim = p;
Observe that it depends on the respective option whether a value is expected and if so, what type of value. There are six different cases. An overview is given in Table 1.
Key | Value | Type of Value | Examples |
---|---|---|---|
yes | no | - | dmpOpt, eject, memoryStat |
yes | yes | integer number | decimals, limcol, seed |
yes | yes | real number | FDDelta, optCR, resLim |
yes | yes | text string | LP, solPrint, sysout |
yes | yes | identifier | See identifier options. |
no | no | - | See identifier operations. |
Table 1: Types of Options
Note that the last type is special: it does not involve a named option or key
, but the keyword option
is followed by identifiers and identifier operators. These special option statements are discussed in detail in section Special Options: Identifier Operations.
Observe that the value of an option may be reset as often as necessary, the new value will replace the previous value each time. Further, more than one option may be specified with one option statement and commas or end-of-line characters are both legal separators between options.
We will demonstrate with the following example how several options may be used. The code snippet may be added to the model [DICE].
option measure, limcol = 100
optcr = 0.00, mip = xpress ;
solve xdice using mip max wnx;
option clear = comp;
Note that in the first option statement four options are specified: option measure has no associated value, option limcol expects an integer value, option optcr expects a real value and option MIP expects a text string as value. The second option statement specifies just one identifier option: clear, which has the variable comp
as value.
- Attention
- Option statements are executed in sequence with other instructions. Therefore, if an option statement is located between two solve statements, the new values will be assigned between the solves and thus they will apply only to the second solve statement.
List of Options
The options available through the option statement are grouped into the following functional categories:
- Options that affect output details
- Solver specific parameters
- Options that control choice of solver
- Options that affect input program control
- Other options
- Special options that involve identifiers
In the following subsections we will offer brief descriptions of the options in the first five categories. Note that each entry is linked to a detailed description of the respective option. Observe that detailed descriptions of all GAMS command line parameters, options and model attributes are given in section Detailed Descriptions of All Options. The options that belong to the last category are special, they are introduced and discussed in section Special Options that Involve Identifiers below.
Options that Control Output Details
Option | Description |
---|---|
asyncSolLst | Print solution listing when asynchronous solve (Grid or Threads) is used |
decimals | Decimal places for display statements |
dispWidth | Number of characters to be printed in the column labels of all subsequent display statements |
eject | Inject a page break into the LST file |
epsToZero | Treat eps as zero when unloading to GDX |
limCol | Maximum number of columns listed in one variable block |
limRow | Maximum number of rows listed in one equation block |
maxGenericFiles | Maximum number of generic file names tried at execution time file creation |
MCPRHoldFx | Print list of rows that are perpendicular to variables removed due to the holdfixed setting |
profile | Execution profiling |
profileTol | Minimum time a statement must use to appear in profile generated output |
solPrint | Solution report print option |
solSlack | Causes the equation output in the listing file to contain slack variable values instead of level values |
sysOut | Solver Status file reporting option |
Options that Control Solver-Specific Parameters
Option | Description |
---|---|
bRatio | Basis detection threshold |
domLim | Domain violation limit solver default |
holdFixedAsync | Allow HoldFixed for models solved asynchronously as well |
intVarUp | Set mode for default upper bounds on integer variables |
iterLim | Iteration limit of solver |
optCA | Absolute Optimality criterion solver default |
optCR | Relative Optimality criterion solver default |
reform | Reformulation level |
resLim | Wall-clock time limit for solver |
savePoint | Save solver point in GDX file |
solveLink | Solver link option |
sys12 | Pass model with generation errors to solver |
threads | Number of processors to be used by a solver |
Options that Control the Choice of Solver
Option | Description |
---|---|
CNS | Constrained Nonlinear Systems - default solver |
DNLP | Non-Linear Programming with Discontinuous Derivatives - default solver |
EMP | Extended Mathematical Programs - default solver |
LP | Linear Programming - default solver |
MCP | Mixed Complementarity Problems - default solver |
MINLP | Mixed-Integer Non-Linear Programming - default solver |
MIP | Mixed-Integer Programming - default solver |
MIQCP | Mixed Integer Quadratically Constrained Programs - default solver |
MPEC | Mathematical Programs with Equilibrium Constraints - default solver |
NLP | Non-Linear Programming - default solver |
QCP | Quadratically Constrained Programs - default solver |
RMINLP | Relaxed Mixed-Integer Non-Linear Programming - default solver |
RMIP | Relaxed Mixed-Integer Programming - default solver |
RMIQCP | Relaxed Mixed Integer Quadratically Constrained Programs - default solver |
RMPEC | Relaxed Mathematical Programs with Equilibrium Constraints - default solver |
solver | Default solver for all model types that the solver is capable to process |
Options that Affect Input Program Control
Option | Description |
---|---|
ECImplicitLoad | Allow implicit loading of symbols from embedded code or not |
fdDelta | Step size for finite differences |
fdOpt | Options for finite differences |
gdxUels | Unload labels or UELs to GDX either squeezed or full |
seed | Random number seed |
solveOpt | Multiple solve management |
strictSingleton | Error if assignment to singleton set has multiple elements |
sys18 | Use backward compatible (i.e. pre-GAMS 31) scheme for reading floating-point numbers |
zeroToEps | Treat zero as eps |
Other Options
Option | Description |
---|---|
checkErrorLevel | Check errorLevel automatically after executing external program |
dmpOpt | Debugging option: causes GAMS to echo the runtime option settings |
dmpSym | Debugging option: causes GAMS to echo the symbol table to the listing file |
dmpUserSym | Debugging option: causes GAMS to echo the symbol table to the listing file for user defined symbols only |
dualCheck | Output on the reduced cost condition |
forLim | GAMS looping limit |
integer1..5 | Integer communication cells |
measure | Output of time and memory use since the last measure statement or the program beginning |
memoryStat | Show memory statistics in the LST file |
real1..5 | Real communication cells |
subSystems | Lists all solvers available as well as the current default and active solvers in the LST file |
sys10 | Changes rpower to ipower when the exponent is constant and within 1e-12 of an integer |
sys11 | Dynamic resorting if indices in assignment/data statements are not in natural order |
sys15 | Automatic switching of data structures used in search records |
sys16 | Disable search record memory (aka execute this as pre-GAMS 24.5) |
sys17 | Disable sparsity trees growing with permutation (aka execute this as pre-GAMS 24.5) |
sys19 | Disable permutation on Column Generation (aka execute this as pre-GAMS 36) |
threadsAsync | Limit on number of threads to be used for asynchronous solves (solveLink=6) |
Special Options that Involve Identifiers
Several options involve identifiers: they either take identifiers as values or have no key and value, but perform an operation on an identifier. In the following two subsections we will introduce and discuss these special options.
Special Options: Identifier Options
The value of identifier options is not a string or a number, but an identifier. In this subsection we will describe these options in detail.
This option resets an identifier to its default value to free memory. The syntax is as follows:
option clear = identifier;
The following identifier types may be reset: sets, parameters, equations and variables. The option will free up memory to the GAMS heap manager, thus the memory may be used by GAMS but not by the operating system. To force the memory to be freed up to the operating system, the GAMS process needs to be terminated. One way to do this is to restart the execution system by solving a dummy model with the option solveLink set to zero.
This option is a synonym to option clear. Observe that the dollar control option $kill is not a synonym to $clear.
This option rearranges the values of a parameter in a random order. The syntax is as follows:
option shuffle = itemname;
Here itemname
is a one-dimensional parameter. One-dimensional parameters may be declared (and defined) in four different ways, depending on the domain and the data. The following table gives an overview of the effect of the option shuffle
in the four cases.
No Data | Has Data | |
---|---|---|
Universal set as domain | Use the universal set to initialize the data (case 1 in the example below). | Use the universal set to add zero values before shuffling the data (case 3 in the example below). |
Specific set as domain | Use the domain to initialize the data (case 2 in the example below). | Use the domain to add zero values before shuffling the data (case 4 in the example below). |
If the parameter was declared without data (the second column in the table above), the domain or the universal set will be used to assign the numbers 1 to N
, where N
is the number of elements in the domain or the universal set. If the parameter was declared with data (the third column in the table above), the domain or the universal set will be used to add zeroes for possibly missing entries. These zero values will participate in the random shuffle, but they will not be stored in the parameter. The following example serves as illustration:
Set i / i1*i5 /
j / j1*j5 /;
option decimals = 0;
*Case 1: universal set as domain and no data
Parameter A(*) "The universe is used to fill the parameter";
option shuffle = A;
display A;
*Case 2: set j as domain and no data
Parameter B(j) "The set j is used to fill the parameter";
option shuffle = B;
display B;
*Case 3: universal set as domain and has data
Parameter C(*) "The universe is used to add zeroes" / j2 2, j4 4 /;
option shuffle = C;
display C;
*Case 4: set i as domain and has data
Parameter D(i) "The set i is used to add zeroes" / i1 10, i3 30, i5 50 /;
option shuffle = D;
display D;
The code above will generate the output that follows. Observe that in this example, the universal set is the union of the sets i
and j
, which means that all elements of the sets i
and j
are members of the universal set. Note that we use random numbers, therefore the outcomes from a different run may vary.
---- 9 PARAMETER A The universe is used to fill the parameter i1 4, i2 1, i3 7, i4 9, i5 6, j1 10, j2 3, j3 5 j4 8, j5 2 ---- 14 PARAMETER B The set j is used to fill the parameter j1 1, j2 5, j3 2, j4 4, j5 3 ---- 19 PARAMETER C The universe is used to add zeroes j1 2, j2 4 ---- 24 PARAMETER D The set i is used to add zeroes i2 30, i4 50, i5 10
In the next example we will demonstrate how to generate a random mapping of a set:
Set i / i1*i6 /,
rmi(i,i) "random mapping";
Parameter A(i);
option shuffle = A;
rmi(i, i + (- Ord(i) + A(i))) = yes;
display rmi;
A display of the set rmi
follows. Note that there is exactly one element in each row and each column:
---- 7 SET rmi random mapping i1 i2 i3 i4 i5 i6 i1 YES i2 YES i3 YES i4 YES i5 YES i6 YES
Observe that each use of the option shuffle
will generate a new random data rearrangement.
Special Options: Identifier Operations
In some cases the keyword option
in an option statement is followed by an identifier and one or more operators to perform identifier operations like display control, index matching, projection and aggregation of sets and parameters and permutation of sets and parameters.
Display Control
The display statement is introduced and discussed in chapter The Display Statement. While GAMS provides defaults for the displayed identifiers that suffice in most cases, the print format may be customized with the following option statement:
option ident:d;
option ident:d:r:c;
The keyword option
is followed by the name of an identifier ident
, a colon and an integer value d
. Note that d
may be between 0 and 8 and specifies the number of decimal places that will be displayed for the respective identifier. The specifications r
and c
are optional. They denote the number of index positions printed as row labels and the number of index positions printed as column labels respectively. Note that if r
is zero, a list format will be used. For more information and examples, see sections Local Display Control and Display Statement to Generate Data in List Format.
Index Matching
Index matching is a very compact way to define multi-dimensional sets. The general syntax is as follows:
option set_name(index1:index2[:index3:...]);
The keyword option
is followed by the name of the set, set_name
, and two (or more) indices in parentheses that are linked with the matching operator ':'
. Note that the set must have been declared earlier in the program. If the set has also been defined earlier in the program, it will be cleared first and then the matching operation will be processed. Note furthermore that the list of identifiers may be expanded to more than two and that besides the matching operator ':'
also ','
may be used and will be interpreted as product operator. Consider the following example which also makes use of display control:
Set i / i1,i2/
j / j1,j2,j3 /
k / k1*k5 /
ij(i,j), ijk(i,j,k), kij(k,i,j);
* index matching
Option ij(i:j), ijk(i,j:k), kij(k:i,j);
* display control
Option ij:0:0:1, ijk:0:0:1, kij:0:0:1;
Display ij, ijk, kij;
In its simplest form the matching operator is used to create the two dimensional set ij
.
---- 9 SET ij i1.j1 i2.j2
Note that each member of the index i
has been matched with a member of the index j
until one of the indices ran out of members.
The index matching operations to define the three-dimensional sets ijk
and kij
illustrate a more sophisticated usage of the index operator. The sets ijk
and kij
are built with the indices from left to right using the product operator when a ','
is encountered or the matching operator when a ':'
is found.
For ijk
the first operator is the ','
which is interpreted as product operator for the sets i
and j
and hence builds the Cartesian product of the two sets which has six 2-tuples as elements (i1.j1, i1.j2, i1.j3, i2.j1, i2.j2, i2.j3
). The matching operator ':'
is then applied to match those 2-tuples with the five set elements in k
. The resulting sets are:
---- 9 SET ijk i1.j1.k1 i1.j2.k2 i1.j3.k3 i2.j1.k4 i2.j2.k5 ---- 9 SET kij k1.i1.j1 k1.i1.j2 k1.i1.j3 k2.i2.j1 k2.i2.j2 k2.i2.j3
The previous example can be extended to define sets of even higher dimension in the following way:
set h / h1*h4 /
hijk_1(h,i,j,k)
hijk_2(h,i,j,k);
* index matching
Option hijk_1(h:ijk);
Option hijk_2(h:i,j:k);
* display control
Option hijk_1:0:0:1, hijk_2:0:0:1;
Display hijk_1, hijk_2;
Note that sets hijk_1
and hijk_2
will be different even though hijk_1
uses set ijk
and hijk_2
uses the same matching and product operation used at definition of ijk
but spelled out. As already mentioned above, the matching operator builds up the sets with the indices from left to right. Hence, as set ijk
is build first and then used on the right of the matching operator the two sets are built up differently.
---- 19 SET hijk_1 h1.i1.j1.k1 h2.i1.j2.k2 h3.i1.j3.k3 h4.i2.j1.k4 ---- 19 SET hijk_2 h1.i1.j1.k1 h1.i1.j2.k2 h1.i1.j3.k3 h2.i2.j1.k4 h2.i2.j2.k5
Projection and Aggregation of Sets and Parameters
In GAMS, projection and aggregation operations on sets may be performed in two different ways: with an assignment and the sum
operator, and with an option statement.
Using an assignment and the sum
operator is the slower but more intuitive way. Assignments and the sum
operator are introduced and discussed in detail in chapter Data Manipulations with Parameters and section Indexed Operations respectively. Here we only show how they may be used in the context of sets to perform projections and aggregations. The following example serves as illustration.
Sets i / i1*i3 /
j / j1*j2 /
k / k1*k4 /
ijk(i,j,k) / #i.#j.#k /
ij1a(i,j)
ij1b(i,j);
Scalars Count_1a, Count_1b, Count_2a, Count_2b;
* Method 1: Using an assignment and the sum operator for a projection
ij1a(i,j) = sum(k,ijk(i,j,k));
* Method 1: Using an assignment and the sum operator for aggregations
Count_2a = sum(ijk(i,j,k),1);
Count_1a = sum(ij1a(i,j),1);
Note that the set ijk
is a three-dimensional set, its elements are 3-tuples and all permutations of the elements of the three sets i
, j
and k
are in its domain. Thus the number of elements of the set ijk
is 3 x 2 x 4 = 24. The sets ij1a
and ij1b
are two-dimensional sets that are declared in the set statement, but not defined. The first assignment statement defines the members of the set ij1a
. This is a projection from the set ijk
to the set ij1a
where the three-tuples of the first set are mapped onto the pairs of the second set, such that the dimension k
is eliminated. This means that the four elements "i1.j1.k1"
, "i1.j1.k2"
, "i1.j1.k3"
and "i1.j1.k4"
of the set ijk
are all mapped to the element "i1.j1"
of the set ij1a
. Note that in this context, the result of the sum
operation is not a number but a set. The second and third assignments are aggregations, where the number of elements of the two sets are computed. As already mentioned, the result of the first aggregation is 24 and the result of the second aggregation is 6 = 24 / 4.
The second way to perform projections and aggregations is faster and more compact, it uses an option statement. The general syntax of this option statement is as follows.
option ident1 < ident2 ;
option ident1 <= ident2 ;
The keyword option
is followed by the identifiers ident1
and ident2
which are linked by the symbol '<'
or '<='
. Observe that in most cases the two symbols have the same effect. The exception is the special case when both identifiers are defined over domains that use at least one shared index set more than once, see the example below. Note that in general the dimension of the item on the left has to be equal or less than the dimension of the item on the right. Further, the index space of the two identifiers must be matchable. If the dimensions of the two identifiers are equal, then the same indices must appear in both, albeit the order may differ. If the dimension of the left item is less than the dimension of the right item, then the indices on the left must also appear on the right.
Observe that if both identifiers are sets, the operation will be a projection. However, if the identifier on the left-hand side is a scalar or a parameter and the identifier on the right-hand side is a set it will be an aggregation. The example that follows shows how the projection and the two aggregations above are accomplished with the option statement.
* Method 2: Option statement performs a projection
Option ij1b < ijk;
* Method 2: Option statements performs aggregations (counting of elements)
Option Count_2b < ijk;
Option Count_1b < ij1b;
display ijk, ij1a, ij1b, Count_1a, Count_1b, Count_2a, Count_2b;
In the example above, the set on the left-hand side, ij1b
, has fewer indices than the set on the right-hand side, ijk
. Observe that if the two sets differ only in the order of the indices then a projection will have the effect of a permutation of the tuple.
- Note
- The option statement for projection and aggregation operations may also be applied to parameters.
Until now the indices in the domain of the sets were unique. A special case arises when sets are defined over a domain with the same indices, for example the set s(i,i,i)
. In this case, a projection always has the effect of a permutation. Users may choose whether they wish to perform the permutation from left to right or from right to left. The option statement
Option item1 < item2 ;
means a right-to-left permutation, while the option statement
Option item1 <= item2 ;
entails a left-to-right permutation. The following example clarifies the difference:
Set i / i1*i3 /
s(i,i,i) "Set members" / i1.i2.i3, i3.i3.i1/
pR1(i,i) "projection right to left with assignment"
pR2(i,i) "projection right to left with option statement"
pL1(i,i) "projection left to right with assignment"
pL2(i,i) "projection left to right with option statement" ;
Alias (i,ii,iii);
* Right-to-left permutation, two ways
pR1(i,ii) = sum(s(iii,ii,i),1);
option pR2 < s;
* Left-to-right permutation, two ways
pL1(i,ii) = sum(s(i,ii,iii),1);
option pL2 <= s;
option s:0:0:1, pR1:0:0:1, pR2:0:0:1, pL1:0:0:1, pL2:0:0:1;
display s, pR1, pR2, pL1, pL2 ;
Note that in the right-to-left permutation, the element "i1.i2.i3"
is projected to "i3.i2"
and the element "i3.i3.i1"
is projected to "i1.i3"
. In the left-to-right permutation however, the the element "i1.i2.i3"
is projected to "i1.i2"
and the element "i3.i3.i1"
is projected to "i3.i3"
. Hence, the left-to-right permutation (<=
) might be more intuitive.
Our examples so far involved only sets. As mentioned above, projections and aggregations may also be performed with parameters. However, there are some subtle differences. The first difference refers to the terminology: we aggregate sets, but we count parameters. The second difference is the result of the operation if the domain of the left symbol is just a permuted version of the domain of the right symbol. Consider the following example:
Set i / i1*i3 /
j / j1*j2 /;
Table p(i,j)
j1 j2
i1 1 2
i2 3 4
i3 5 6;
parameter pperm(j,i);
option pperm < p;
option decimals = 0;
display p, pperm;
The output generated by the display statement follows:
---- 13 PARAMETER p j1 j2 i1 1 2 i2 3 4 i3 5 6 ---- 13 PARAMETER pperm i1 i2 i3 j1 1 3 5 j2 2 4 6
Permutation of Sets and Parameters
In GAMS, the >
sign can be used to create complete permutations of one- and multi-dimensional sets and parameters. Consider the following example based on the test library model [PERM1]:
First, a set i
for which all permutations should be computed is declared and defined. A permutation of a one-dimensional set i
can be represented by a two-dimensional set like perm(i,i)
where the i
index is duplicated. In the example, set perm(i,i)
represents permutation (1 2)(3)
in cycle notation. For a set with three elements, there are 3*2*1=6
permutations. The statement option pall > i;
results in all permutations of i
being computed and stored in three-dimensional set pall(p,i,i)
where the first index p
serves as a counter to enumerate all permutations.
set i 'set to permute' / i1*i3 /
perm(i,i) 'exemplary permutation' / i1.i2, i2.i1, i3.i3 /
$eval pmax fact(card(i))
p 'permutation index' / p1*p%pmax% /
pall(p,i,i) 'permutation set';
option pall > i;
option pall:0:0:1;
display pall;
Note that we use display control such that the display statement results in:
---- 8 SET pall permutation set p1.i1.i1 p1.i2.i2 p1.i3.i3 p2.i1.i1 p2.i2.i3 p2.i3.i2 p3.i1.i2 p3.i2.i1 p3.i3.i3 p4.i1.i2 p4.i2.i3 p4.i3.i1 p5.i1.i3 p5.i2.i1 p5.i3.i2 p6.i1.i3 p6.i2.i2 p6.i3.i1
For multi-dimensional sets, the permutation operator follows the same logic. Consider the following example:
Sets j
, k
and a two-dimensional set jk(j,k)
are defined. In order to find all permutations of jk(j,k)
, the indices are again duplicated and a permutation index is introduced:
set j / j1*j2 /, k / k1*k5 /
jk(j,k) / j1.k3, j1.k5, j2.k1 /
$eval pmax fact(card(jk))
p / p1*p%pmax% /
pall(p,j,k,j,k);
option pall > jk;
option pall:0:0:1;
display pall;
The display statement results in:
---- 8 SET pall p1.j1.k3.j1.k3 p1.j1.k5.j1.k5 p1.j2.k1.j2.k1 p2.j1.k3.j1.k3 p2.j1.k5.j2.k1 p2.j2.k1.j1.k5 p3.j1.k3.j1.k5 p3.j1.k5.j1.k3 p3.j2.k1.j2.k1 p4.j1.k3.j1.k5 p4.j1.k5.j2.k1 p4.j2.k1.j1.k3 p5.j1.k3.j2.k1 p5.j1.k5.j1.k3 p5.j2.k1.j1.k5 p6.j1.k3.j2.k1 p6.j1.k5.j1.k5 p6.j2.k1.j1.k3
In addition to set elements, it is also possible to permute numerical data in a GAMS parameter. Consider the following example where all permutations of the numerical values stored in the one-dimensional parameter a(i)
are computed:
set i / i1*i3 /
$eval pmax fact(card(i))
p / p1*p%pmax% /;
Parameter a(i) /i1 1, i2 2, i3 3/
pall_a(p,i);
option pall_a > a;
option pall_a:0:1:1;
display pall_a;
The display statement results in:
---- 8 PARAMETER pall_a 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
The permutation can also be extended to multi-dimensional parameters. Consider the following example where all permutations of the numerical values stored in the two-dimensional parameter b(j,k)
are computed:
set j / j1*j2 /, k / k1*k5 /;
Parameter b(j,k) /j1.k3 1, j1.k5 2, j2.k1 3/;
$eval pmax fact(card(b))
set p / p1*p%pmax% /;
parameter pall_b(p,j,k);
option pall_b > b;
option pall_b:0:1:2;
display pall_b;
The display statement results in:
---- 8 PARAMETER pall_b 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