Initializing sets
You can initialize sets in three different ways.
Externally
As stated in Initializing sets, in the Sets topic, the simplest way to initialize a set is by listing its values explicitly in the .dat file.
For example, the declaration:
/* .mod file */
tuple Precedence {
int before;
int after;
}
{Precedence} precedences = ...;
/* .dat file */
precedences = {<1,2>, <1,3>, <3,4>};
initializes a set of tuples.
Internally
You can also initialize sets internally (in the .mod file), more precisely by using set expressions using previously defined sets and operations such as union, intersection, difference, and symmetric difference. The symmetric difference of two sets A and B is
(A
B) \ (A
B)
described in Expressions.
For example, the declarations:
{int} s1 = {1,2,3};
{int} s2 = {1,4,5};
{int} i = s1 inter s2;
{int} j = {1,4,8,10} inter s2;
{int} u = s1 union {5,7,9};
{int} d = s1 diff s2;
{int} sd = s1 symdiff {1,4,5};
initialize i to {1}, u to {1,2,3,5,7,9}, d to {2,3},
and sd to {2,3,4,5}.
It is also possible to initialize a set from a range expression. For example, the declaration:
{int} s = asSet(1..10)
initializes s to {1,2,..,10}
It is important to point out at this point that sets initialized by ranges are represented explicitly (unlike ranges). As a consequence, a declaration of the form
{int} s = asSet(1..100000);
creates a set where all the values 1, 2,
..., 100000 are explicitly represented, while the
range
range s = 1..100000;
represents only the bounds explicitly.
Note that
when writing the assignment s2=s1, you add one element
to s1, that element is also added to s2.
If you do not want this, write
s1={i|i in s2}
For example, compare the statements in the following table.
| If you write | the result is |
|---|---|
|
} |
{1 2 3} |
|
} |
{1 2} |
As generic sets
OPL supports generic sets which have an expressive power similar to relational database queries. For example, the declaration:
{int} s = {i | i in 1..10: i mod 3 == 1};
initializes s with the set {1,4,7,10}.
A generic set is a conjunction of expressions of the form
p in S : condition
where p is a parameter (or a tuple
of parameters), S is a range or a finite set, and condition is
a Boolean expression. These expressions are also used in forall statements
and aggregate operators and are discussed in detail in Formal parameters.
The declaration:
{string} Resources ...;
{string} Tasks ...;
Tasks res[Resources] = ...;
tuple Disjunction {
{string} first;
{string} second;
}
{Disjunction} disj = {<i,j> |
r in Resources, ordered i,j in res[r]
};
is a more interesting example, showing a conjunction of expressions, and is explained in detail in Formal parameters. Generic sets are often useful when you transform a data structure (e.g. the data stored in a file) into a data structure more appropriate for stating the model effectively. Consider, for example, the declarations:
{string} Nodes ...;
int edges[Nodes][Nodes] = ...;
which describe the edges of a graph in terms of a Boolean adjacency matrix. It may be important for the model to use a sparse representation of the edges (because, for instance, edges are used to index an array). The declaration:
tuple Edge {
Nodes o;
Nodes d;
}
{Edge} setEdges = {<o,d> | o,d in Nodes : edges[o][d]==1};
computes this sparse representation using a simple generic set. It is of course possible to define generic arrays of sets. For example, the declaration:
{int} a[i in 3..4] = {e | e in 1..10: e mod i == 0};
initializes a[3] to {3,6,9} and a[4] to {4,8}.