Array handling
Mosel 5 has two categories of arrays: sparse arrays and dense arrays. Sparse arrays include explicitly dynamic arrays that keep the same behaviour as in previous versions and the new array type hashmap. Dense arrays are all arrays that are not specifically marked as a sparse array type, namely static arrays (same behaviour as in previous versions) and not fixed (previously: implicitly dynamic) arrays that are now handled more consistently, always resulting in the same representation independent of index set finalization.
- Arrays for which index sets are not known at their declaration and that are not marked as dynamic or hashmap are now always represented as dense arrays independently of whether the index sets have been finalized (whereas previously they were represented as sparse arrays if the index sets were not finalized, and otherwise as dense arrays).
⇒ It is recommended to check your Mosel code for arrays that are not explicitly marked as dynamic and for which index sets are not known at the time of their creation since the default behaviour is changing in certain cases as shown below.- Mosel 3-4:
declarations RD: range D: dynamic array(RD) of real A2,A3: array(RD) of real end-declarations ! Explicitly dynamic array D(1):=10; D(-2):=-20; D(3):=150 ! Mosel 4 output: writeln("D: ", D, " RD: ", RD) ! D: [(-2,-20),(1,10),(3,150)] RD: -2..3 writeln("Size: ", D.size) ! Size: 3 ! Array with dynamic index set forall(i in RD | exists(D(i)) ) A2(i):=D(i) writeln("A2: ", A2, " size=", A2.size) ! A2: [(-2,-20),(1,10),(3,150)] size=3 ! Finalize index set before array access finalize(RD) forall(i in RD | exists(D(i)) ) A3(i):=D(i) writeln("A3: ", A3, " size=", A3.size) ! A3: [-20,0,0,10,0,150] size=6
- Mosel 5:
declarations RD: range D: dynamic array(RD) of real A2,A3: array(RD) of real end-declarations ! Explicitly dynamic array D(1):=10; D(-2):=-20; D(3):=150 ! Mosel 5 output: writeln("D: ", D, " RD: ", RD) ! D: [(-2,-20),(1,10),(3,150)] RD: -2..3 writeln("Size: ", D.size) ! Size: 3 ! Array with dynamic index set forall(i in RD | exists(D(i)) ) A2(i):=D(i) writeln("A2: ", A2, " size=", A2.size) ! A2: [-20,0,0,10,0,150] size=6 ! Finalize index set before array access finalize(RD) forall(i in RD | exists(D(i)) ) A3(i):=D(i) writeln("A3: ", A3, " size=", A3.size) ! A3: [-20,0,0,10,0,150] size=6
- All entries corresponding to defined index values are created at once
- previously: with dynamic index sets entries only for assigned values
declarations A: array(S: set of string) of real end-declarations S:={'a','b','c'} A('c'):=1.5 writeln("A: ", A, " size=", A.size) ! Output: ! Mosel 4: A: [(`c',1.5)] size=1 ! Mosel 5: A: [0,0,1.5] size=3
- Arrays grow if index sets increase in size
- previously: no change
declarations B1,B2: array(SB:set of integer) of real end-declarations B1(1):=1.5; B1(4):=4.5 writeln("B1 size=", B1.size, " B2 size=", B2.size) ! Mosel 4: B1 size=2 B2 size=0 ! Mosel 5: B1 size=2 B2 size=2 writeln("B1:", B1, " B2:",B2, " SB:", SB) ! Mosel 4: B1:[(1,1.5),(4,4.5)] B2:[] SB:{1,4} ! Mosel 5: B1:[1.5,4.5] B2:[0,0] SB:{1,4} ! Growing index set SB+={7,10} writeln("B1 size=", B1.size, " B2 size=", B2.size) ! Mosel 4: B1 size=2 B2 size=0 ! Mosel 5: B1 size=4 B2 size=4 writeln("B1:", B1, " B2:",B2, " SB:", SB) ! Mosel 4: B1:[(1,1.5),(4,4.5)] B2:[] SB:{1,4,7,10} ! Mosel 5: B1:[1.5,4.5,0,0] B2:[0,0,0,0] SB:{1,4,7,10}
- There is no longer any need for using create on arrays of mpvar that are not explicitly dynamic
public declarations x: array(I:range) of mpvar y: array(string) of mpvar end-declarations Ctr1:=sum(i in [1, 2, 5, 6]) i*x(i) <= 20 Ctr2:=sum(i in ['a','b','c'], ct as counter) (ct+1)*y(i) <= 10 exportprob ! Mosel 4: empty problem (variables have not been created) ! Mosel 5: _R1: 2 y(a) + 3 y(b) + 4 y(c) <= 10 ! _R2: x(1) + 2 x(2) + 5 x(5) + 6 x(6) <= 20 writeln("x size=", x.size, " y size=", y.size) ! Mosel 4: x size=0 y size=0 ! Mosel 5: x size=6 y size=3
- Use finalize on index sets in order to prevent the creation of additional (unwanted) entries
options noautofinal public declarations COST: array(PERIODS:range) of real x: array(PERIODS) of mpvar Ctr: array(PERIODS) of linctr end-declarations initializations from "cost.dat" COST end-initializations ! COST: [(1) 3 (2) 6 (3) 9 (4) 6 (5) 2 (6) 2 ] forall(t in PERIODS) create(x(t)) ! Required by Mosel 4, not Mosel 5 forall(t in PERIODS) Ctr(t):= x(t) >= x(t+1) ! This should really be: x(t) >= if(t+1 in PERIODS, x(t+1), 0) ! Output Mosel 4: Mosel 5: exportprob("") ! Ctr(6): x(6) >= 0 Ctr(6): x(6) - x(7) >= 0 writeln("Periods: ", PERIODS) ! Periods: 1..6 Periods: 1..7
- Use sparse (dynamic or hashmap) arrays when performing tests with exists, and also to prevent the creation of undesired entries (e.g. completion of ranges)
declarations A: array(R: range,set of integer) of integer DA: dynamic array(R,set of integer) of integer end-declarations writeln("A size=", A.size) ! Mosel 4: size=0 Mosel 5: size=0 A(10,10):=10; A(5,5):=5 writeln("A size=", A.size) ! Mosel 4: size=2 Mosel 5: size=12 writeln("DA size=", DA.size) ! Mosel 4: size=0 Mosel 5: size=0 DA(10,10):=10; DA(5,5):=5 writeln("DA size=", DA.size) ! Mosel 4: size=2 Mosel 5: size=2 writeln(A, " is dynamic:", isdynamic(A)) ! Mosel 4: [(5,5,5),(10,10,10)] is dynamic:false ! Mosel 5: [0,5,0,0,0,0,0,0,0,0,10,0] is dynamic:false writeln("A(7,10) exists:", exists(A(7,10))) ! Mosel 4: false Mosel 5: true writeln("DA(7,10) exists:", exists(DA(7,10))) ! Mosel 4: false Mosel 5: false
- Use sparse arrays if you wish to delete entries with delcell or (new in Mosel 5) reset
- for non-dynamic arrays these now result in resetting array contents to default values
declarations A,B: array(S:set of integer) of integer DA: dynamic array(S) of integer end-declarations writeln("A size=", A.size) ! Mosel 4: size=0 Mosel 5: size=0 S:={1,3}; A(4):=4.5; A(8):=8.5 writeln("A size=", A.size, " A=", A) ! Mosel 4: size=2 A=[(4,4.5),(8,8.5)] ! Mosel 5: size=4 A=[0,0,4.5,8.5] delcell(A) ! Same as: reset(A) writeln("A size=", A.size, " A=", A) ! Mosel 4: size=0 A=[] ! Mosel 5: size=4 A=[0,0,0,0] finalize(S) B(4):=4.5; B(8):=8.5 writeln("B size=", B.size, " B=", B) ! Mosel 4: size=4 B=[0,0,4.5,8.5] ! Mosel 5: size=4 B=[0,0,4.5,8.5] delcell(B) ! Same as: reset(B) writeln("B size=", B.size, " B=", B) ! Mosel 4: size=4 B=[0,0,4.5,8.5] ! Mosel 5: size=4 B=[0,0,0,0] DA(4):=4.5; DA(8):=8.5 writeln("DA size=", DA.size, " DA=", DA) ! Mosel 4+5: size=2 DA=[(4,4.5),(8,8.5)] delcell(DA(4)) writeln("DA size=", DA.size, " DA=", DA) ! Mosel 4+5: size=1 DA=[(8,8.5)] delcell(DA) ! Same as: reset(DA) writeln("DA size=", DA.size, " DA=", DA) ! Mosel 4+5: size=0 DA=[]