Initializing help system before first use

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=[]