FICO Xpress Optimization Examples Repository
 FICO Optimization Community FICO Xpress Optimization Home

Using 'exists' for loops over sparse arrays

Description
The models loop.mos/looph.mos and proj.mos show the effect of using the keyword exists in conditions on loops over sparse arrays. As can be seen, the careful formulation of loops may result in a considerable speedup of the model execution time. Mosel defines two forms of sparse arrays, namely dynamic arrays and hashmap arrays. The model sparsearrays.mos compares the performance of these two forms for different cases of enumerations.

Further explanation of this example: 'Mosel User Guide', Appendix 'Good modeling practice' explains in detail the correct use of exists.

Source Files
By clicking on a file name, a preview is opened at the bottom of this page.

Data Files

sparsearrays.mos

(!*******************************************************
Mosel Example Problems
======================

file sparsearrays.mos

Comparing speed of dynamic and hashmap arrays
for different cases of enumeration

(c) 2018 Fair Isaac Corporation
author: S. Heipcke, Sep. 2018
*******************************************************!)

model "dynamic vs hashmap"
uses "mmsystem"

declarations
R1 = 1..2000
R2 = 1..500
R3 = 1..500
D,D2: dynamic array(R1,R2,R3) of real
H,H2: hashmap array(R1,R2,R3) of real
end-declarations

! **** Initialize arrays with random data ****
function randint(vmin,vmax: integer): integer
if vmax<vmin then
setmatherr("upper bound is smaller than lower bound")
return
end-if
returned:= round((vmax-vmin)*random)+vmin
end-function

setrandseed(17)
starttime:=gettime
r2min:=R2.first; r2max:=R2.last; r3min:=R3.first; r3max:=R3.last
forall(i1 in R1,k in 1..100) do
j2:=randint(r2min,r2max); j3:=randint(r3min,r3max)
D(i1,j2,j3):=i1;H(i1,j2,j3):=i1
end-do
forall(i1 in R1) do
j2:=randint(r2min,r2max); j3:=randint(r3min,r3max)
D2(i1,j2,j3):=i1; H2(i1,j2,j3):=i1
end-do
writeln(gettime-starttime, " Data input: D size=", D.size,", H size=", H.size,
", D2 size=", D2.size,", H2 size=", H2.size)

! **** Enumeration with 'exists' in suitable (linear) order ****
! **** (dynamic faster than hashmap) ****
starttime:=gettime
a:=count(i1 in R1, i2 in R2, i3 in R3 | exists(D(i1,i2,i3)))
writeln(gettime-starttime, " Enum lin D (", a, ")")

starttime:=gettime
a:=count(i1 in R1, i2 in R2, i3 in R3 | exists(H(i1,i2,i3)))
writeln(gettime-starttime, " Enum lin H (", a, ")")

! **** Enumeration in unsuitable order (inversed order of sets) ****
! **** (hashmap faster than dynamic) ****
starttime:=gettime
a:=count(i3 in R3, i2 in R2, i1 in R1 | exists(D2(i1,i2,i3)))
writeln(gettime-starttime, " Enum inv D2 (", a, ")")

starttime:=gettime
a:=count(i3 in R3, i2 in R2, i1 in R1 | exists(H2(i1,i2,i3)))
writeln(gettime-starttime, " Enum inv H2 (", a, ")")

end-model

`