Use of exists
The Mosel compiler is able to identify sparse loops and optimizes them automatically, such as in the following example:
declarations I=1..1000 J=1..500 A: dynamic array(I,J) of real x: array(I,J) of mpvar end-declarations initializations from "mydata.dat" A end-initializations C:= sum(i in I,j in J | exists(A(i,j))) A(i,j)*x(i,j) = 0
Notice that we obtain the same definition for the constraint C with the following variant of the code, but no loop optimization takes place:
C:= sum(i in I,j in J) A(i,j)*x(i,j) = 0
Here all index tuples are enumerated and the corresponding entries of A are set to 0. Similarly, if not all entries of x are defined, the missing entries are interpreted as 0 by the sum operator.
The following rules have to be observed for efficient use of the function exists, :
- The arrays have to be indexed by named sets (here I and J):
A: dynamic array(I,J) of real ! can be optimized H: hashmap array(I,J) of real ! can be optimized B: dynamic array(1..1000,1..500) of real ! cannot be optimized
- The same sets have to be used in the loops:
forall(i in I,j in J | exists(A(i,j))) ! fast K:=I; forall(i in K,j in 1..500 | exists(A(i,j))) ! slow
- The order of the sets has to be respected, particularly for dynamic arrays:
forall(i in I,j in J | exists(A(i,j))) ! fast forall(j in J,i in I | exists(H(i,j))) ! slower forall(j in J,i in I | exists(A(i,j))) ! slowest
- The exists function calls have to be at the beginning of the condition:
forall(i in I,j in I | exists(A(i,j)) and i+j<>10) ! fast forall(i in J,j in J | i+j<>10 and exists(A(i,j))) ! slow
- The optimization does not apply to or conditions:
forall(i in I,j in J | exists(A(i,j)) and i+j<>10) ! fast forall(i in I,j in J | exists(A(i,j)) or i+j<>10) ! slow