Initializing arrays

Describes the various ways in which you can initialize arrays.

You can initialize arrays:

Externally

Arrays can be initialized by external data, in which case the declaration has the form:


int a[1..2] [1..3] = ...; 

and the actual initialization is given in a data source, which is a separate .dat file in IBM ILOG OPL.

  • By listing values

    This is how arrays are initialized in most of the examples presented so far. Multidimensional arrays in OPL are, in fact, arrays of arrays and must be initialized accordingly. For example, the declaration:

    
    /* .mod file */
    int a[1..2][1..3] = ...;
    /* .dat file */
    a = [
    [10, 20, 30],
    [40, 50, 60]
    ];
    

    initializes a two-dimensional array by giving initializations for the one-dimensional arrays of its first dimension. It is easy to see how to generalize this initialization to any number of dimensions.

  • By specifying pairs

    An array can also be initialized by specifying pairs (index, value), as in the declaration:

    
    /* .mod file */
    int a[Days] = ...;
    /* .dat file */
    a = #[
    “Monday”: 1,
    ”Tuesday”: 2,
    ”Wednesday”: 3,
    ”Thursday”: 4,
    ”Friday”: 5,
    ”Saturday”: 6,
    ”Sunday”: 7
    ]#;
    
    Note:
    1. When the initialization is specified by (index, value) pairs, the delimiters #[ and ]# must be used instead of [ and ].

    2. The ordering of the pairs can be arbitrary.

    These two forms of initialization can be combined arbitrarily, as in:

    
    /* .mod file */
    int a[1..2][1..3] = ...;
    /* .dat file */
    a = #[
    2: [40, 50, 60],
    1: [10, 20, 30]
    ]#; 
    

Internally

You can initialize arrays internally (that is, in the .mod file) using the same syntax as in .dat files. Here, the array items may be expressions that are evaluated during initialization. The syntax for pairs #[, ]# is not available for internal initialization.

In preprocessing instructions

Arrays can also be initialized in the preprocessing instructions, as in:

range R = 1..8;
int a[R];
execute {
  for(var i in R) {
    a[i] = i + 1;
  }}

which initializes the array in such a way that a[1] = 2, a[2] = 3, and so on. See Preprocessing of data.

As generic arrays

OPL also supports generic arrays, that is, arrays whose items are initialized by an expression. These generic arrays may significantly simplify the modeling of an application. The declaration:

int a[i in 1..10] = i+1; 

declares an array of 10 elements such that the value of a[i] is i+1. Generic arrays can of course be multidimensional, as in:

int m[i in 0..10][j in 0..10] = 10*i + j; 

which initializes element m[i][j] to 10*i + j. Generic arrays are useful in performing some simple transformations. For instance, generic arrays can be used to transpose matrices in a simple way, as in:

int m[Dim1][Dim2] = ...; 
int t[j in Dim2][i in Dim1] = m[i][j]; 

More generally speaking, generic arrays can be used to permute the indices of arrays in simple ways.

As generic indexed arrays

To have more flexibility when initializing arrays in a generic way, OPL enables you to control the index value in addition to the item value, as described earlier in As generic arrays. To illustrate the syntax, the same examples can be expressed as follows:

int a[1..10] = [ i-1 : i | i in 2..11 ]; 
int m[0..10][0..10] = [ i : [ j : 10*i+j ] | i,j in 0..10 ]; 

This syntax is close to the syntax used for initializing arrays in .dat files by means of indices, delimited by #[ and ] #, as explained above in Specifying pairs. Using this syntax is an efficient means of initializing arrays used to index data.

The oilDB.mod example contains an execute block that performs initialization. Instead of:

GasType gas[Gasolines];
execute {
  for(var g in gasData) {
    gas[g.name] = g
  }
}

the same can be expressed with the syntax for generic indexed arrays as:

GasType gas[Gasolines] = [ g.name : g | g in gasData ];

Likewise, this syntax, from transp4.mod

float Cost[Routes];
execute INITIALIZE {
  for( var t in TableRoutes ) {
      Cost[Routes.get(t.p,Connections.get(t.o,t.d))] = t.cost;
   }
}

is equivalent to


float Cost[Routes] = [ <t.p,<t.o,t.d>>:t.cost | t in TableRoutes ];
Note:
  1. It is recommended to use generic arrays or generic indexed arrays whenever possible, since they make the model more explicit and readable.

  2. If an index is met more than once, no warning is issued and the latest value set for this index is the one kept.

    For example:

    int n=5;
    
    {int} s= {1,3,4,2,5};
    sorted {int} s2=asSet(1..n);;
    reversed {int} s3=asSet(1..n);;
    
    int x[1..n]=[maxl(n-i,i): i | i in s];
    int x2[1..n]=[maxl(n-i,i): i | i in s2];
    int x3[1..n]=[maxl(n-i,i): i | i in s3];
    
    execute
    {
     writeln(x);
     writeln(x2);
     writeln(x3);
    } 

    gives out

    [0 0 2 4 5]
    [0 0 3 4 5]
    [0 0 2 1 5]