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
- development of your personal `tool box'
- model parts (e.g., reformulations) or algorithms written in Mosel that you wish to distribute without disclosing their contents
- add-ons to modules that are more easily written in the Mosel language
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-packageThe 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-modelPlease note the following:
- 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.- 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.
- 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-packageUsing 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-modelOutput 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-packagewhich 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-modelAt 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-packagePackages 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.
- Definition
- Package
- library written in the Mosel language
- Module
- dynamic library written in C that obeys the conventions of the Mosel Native Interface
- Functionality
- Package
- define
- symbols
- subroutines
- types
- Module
- extend the Mosel language with
- constant symbols
- subroutines
- operators
- types
- control parameters
- IO drivers
- Efficiency
- Package
- like standard Mosel models
- Module
- faster execution speed
- higher development effort
- Use
- Package
- making parts of Mosel models re-usable
- deployment of Mosel code whilst protecting your intellectual property
- Module
- connection to external software
- time-critical tasks
- definition of new I/O drivers and operators for the Mosel language
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.