Packages



A package is a library written in the Mosel language (this feature is introduced by Mosel 2.0). Its structure is similar to models, replacing the keyword model by package. Packages are included into models with the uses statement, in the same way as this is the case for modules. Unlike Mosel code that is included into a model with the include statement, packages are compiled separately, that is, their contents are not visible to the user.

Typical uses of packages include

Packages may define new constants, subroutines, and types for the Mosel language as shown in the following examples (the first two examples correspond to the first two module examples of the Mosel Native Interface User Guide).

Definition of constants

The following package myconstants defines one integer, one real, one string, and two boolean constants.

package myconstants

 public declarations
  MYCST_BIGM = 10000          ! A large integer value
  MYCST_TOL = 0.00001         ! A tolerance value
  MYCST_LINE =                ! String constant
     "----------------------------------------------------------------"
  MYCST_FLAG = true           ! Constant with value true
  MYCST_NOFLAG = false        ! Constant with value false
 end-declarations

end-package

The structure of a package is similar to the structure of Mosel models, with the difference that we use the keyword package instead of model to mark its beginning and end.

After compiling our package with the standard Mosel command (assuming the package is saved in file myconstants.mos)

mosel -c "comp myconstants"

it can be used in a Mosel model (file myconst_test.mos):

model "Test myconstants package"
 uses "myconstants"

 writeln(MYCST_LINE)
 writeln("BigM value: ", MYCST_BIGM, ", tolerance value: ", MYCST_TOL)
 writeln("Boolean flags: ", MYCST_FLAG, " ", MYCST_NOFLAG)
 writeln(MYCST_LINE)
 
end-model

Please note the following:

  1. Package name: compiling a package will result in a file packagename.bim. This package is invoked in a Mosel model by the statement
    uses "packagename"
    The name of the Mosel package source file (.mos file) may be different from the name given to the BIM file.
  2. Internal package name: the name given in the Mosel file after the keyword package is the internal name of the package. It must be a valid Mosel identifier (and not a string). This name may be different from the name given to the BIM file, but it seems convenient to use the same name for both.
  3. Package location: for locating packages Mosel applies the same rules as for locating modules; it first searches in the directory dso of the Xpress-MP installation, that is, in XPRESSDIR/dso, and then in the directories pointed to by the environment variable MOSEL_DSO. The contents of the latter can be set freely by the user.
    To try out the package examples in this chapter, you may simply include the current working directory ('.') in the locations pointed to by MOSEL_DSO, so that packages in the current working directory will be found, for example:
    Windows: set MOSEL_DSO=.
    Unix/Linux, C shell: setenv MOSEL_DSO .
    Unix/Linux, Bourne shell: export MOSEL_DSO; MOSEL_DSO=.
    In general, and in particular for the deployment of an application, it is recommended to work with absolute paths in the definition of environment variables.

Having made sure that Mosel is able to find our package myconstants.bim, executing the test model above will produce the following output:

----------------------------------------------------------------
BigM value: 10000, tolerance value: 1e-05
Boolean flags: true false
----------------------------------------------------------------

When comparing with the C implementation of the module example myconstants in the Mosel Native Interface User Guide we can easily see that the package version is much shorter.

Definition of subroutines

We now show a package (file solarray.mos) that defines several versions of a subroutine, solarray, which copies the solution values of an array of decision variables of type mpvar into an array of real of the same size. For each desired number (1–3) and type (integer or string) of array indices we need to define a new version of this subroutine.

package solarraypkg 

! **** Integer indices (including ranges) ****
 public procedure solarray(x:array(R:set of integer) of mpvar,
                           s:array(set of integer) of real)
  forall(i in R) s(i):=getsol(x(i))
 end-procedure 

 public procedure solarray(x:array(R1:set of integer,
                                   R2:set of integer) of mpvar,
                           s:array(set of integer, 
                                   set of integer) of real)
  forall(i in R1, j in R2) s(i,j):=getsol(x(i,j))
 end-procedure 
 
 public procedure solarray(x:array(R1:set of integer,
                                   R2:set of integer,
                                   R3:set of integer) of mpvar,
                           s:array(set of integer,
                                   set of integer,
                                   set of integer) of real)
  forall(i in R1, j in R2, k in R3) s(i,j,k):=getsol(x(i,j,k))
 end-procedure 

! ****String indices ****
 public procedure solarray(x:array(R:set of string) of mpvar,
                           s:array(set of string) of real)
  forall(i in R) s(i):=getsol(x(i))
 end-procedure 

 public procedure solarray(x:array(R1:set of string,
                                   R2:set of string) of mpvar,
                           s:array(set of string, 
                                   set of string) of real)
  forall(i in R1, j in R2) s(i,j):=getsol(x(i,j))
 end-procedure 
 
 public procedure solarray(x:array(R1:set of string,
                                   R2:set of string,
                                   R3:set of string) of mpvar,
                           s:array(set of string,
                                   set of string,
                                   set of string) of real)
  forall(i in R1, j in R2, k in R3) s(i,j,k):=getsol(x(i,j,k))
 end-procedure 
end-package

Using the package in a Mosel model (file solarr_test.mos):

model "Test solarray package"
 uses "solarray", "mmxprs"

 declarations
  R1=1..2
  R2={6,7,9}
  R3={5,-1}
  x: array(R1,R2,R3) of mpvar
  sol: array(R1,R2,R3) of real
 end-declarations

! Define and solve a small problem  
 sum(i in R1, j in R2, k in R3) (i+j+2*k) * x(i,j,k) <= 20
 forall(i in R1, j in R2, k in R3) x(i,j,k)<=1
 maximize(sum(i in R1, j in R2, k in R3) (i+2*j+k) * x(i,j,k))

! Get the solution array  
 solarray(x,sol)

! Print the solution 
 forall(i in R1, j in R2, k in R3)
  writeln(" (", i, ",", j, ",", k, ") ", sol(i,j,k), " ", getsol(x(i,j,k)))
 writeln(sol)
 
end-model

Output produced by this model:

 (1,6,-1) 1 1
 (1,6,5) 0 0
 (1,7,-1) 1 1
 (1,7,5) 0 0
 (1,9,-1) 1 1
 (1,9,5) 0 0
 (2,6,-1) 0.166667 0.166667
 (2,6,5) 0 0
 (2,7,-1) 0 0
 (2,7,5) 0 0
 (2,9,-1) 0 0
 (2,9,5) 0 0
[1,0,1,0,1,0,0.166667,0,0,0,0,0] 

This example may be classified as a `utility function' that eases tasks occurring in a similar way in several of your models. Another example of such a utility function could be a printing function that simply outputs the solution value of a decision variable with some fixed format (if you apply write/writeln to a decision variable of type mpvar you obtain the pointer of the variable, and not its solution value).

If we again make the comparison with the implementation as a module we see that both ways have their positive and negative points: the implementation as a module is clearly more technical, requiring a considerable amount of C code not immediately related to the implementation of the function itself. However, at the C level we simply check that the two arguments have the same index sets, without having to provide a separate implementation for every case, thus making the definition more general.

Definition of types

In Section Initialization of records from file we have seen the example arcs.mos that defines a record to represent arcs of a network. If we wish to use this data structure in different models we may move its definition into a package 'arc' to avoid having to repeat it in every model.

Such a package may look as follows (file arc.mos):

package arcPkg

 public declarations
  arc = public record                   ! Arcs:
   Source,Sink: string                  !   Source and sink of arc
   Cost: real                           !   Cost coefficient
  end-record 
 end-declarations

end-package  

which is used thus from the model file:

model "Arcs2"
 uses "arc"

 declarations
  NODES: set of string                  ! Set of nodes
  ARC: array(ARCSET:range) of arc       ! Arcs
 end-declarations

 initializations from 'arcs.dat'
  ARC
 end-initializations

! Calculate the set of nodes
 NODES:=union(a in ARCSET) {ARC(a).Source, ARC(a).Sink}
 writeln(NODES)

 writeln("Average arc cost: ", sum(a in ARCSET) ARC(a).Cost / getsize(ARCSET) )

end-model  

At this place, the use of the keyword public may call for some explanation. Here and also in the example `myconstants' the whole declarations block is preceded by the public marker, indicating that all objects declared in the block are public (i.e., usable outside of the package definition file). If only some declarations are public and others in the same block are private to the package, the public marker needs to preceed the name of every object within the declarations that is to become public instead of marking the entire block as public.

The second occurrence of the public marker in the definition of package `arc' is immediately in front of the keyword record, meaning that all fields of the record are public. Again, it is possible to select which fields are accessible from external files (for example, you may wish to reserve some fields for special flags or calculations within your package) by moving the keyword public from the record definition in front of every field name that is to be marked as public.

A definition of package `arc' equivalent to the one printed above therefore is the following.

package arcPkg2

 declarations
  public arc = record                   ! Arcs:
   public Source,Sink: string           !   Source and sink of arc
   public Cost: real                    !   Cost coefficient
  end-record 
 end-declarations

end-package  

Packages vs. modules

The possibility of writing packages introduces a second form of libraries for Mosel, the first being modules (see the `Mosel Native Interface User Guide' for further detail). The following list summarizes the main differences between packages and modules.

As can be seen from the list above, the choice between packages and modules depends largely on the contents and intended use of the library you wish to write.



If you have any comments or suggestions about these pages, please send mail to docs@dashoptimization.com.