Initializing help system before first use

# Packages

Topics covered in this chapter:

- Definition of constants
- Definition of subroutines
- Definition of types
- Definition of parameters
- Namespaces
- Package version management
- Packages vs. modules

A package is a library written in the Mosel language (this feature was 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 for dynamic loading (the package BIM needs to be present for model execution), in the same way as this is the case for modules (DSO). Alternatively, packages can be loaded statically via imports in which case they get included in the model BIM file (this option is not available for modules that are always dynamic). 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, types, and parameters 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).

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 similar rules as for locating modules; it first uses the list of prefixes defined by the compiler option -bx or the environment variable MOSEL_BIM, it then searches in the directory dso of the Xpress installation (see Section 2.3.1 Directive uses of the Mosel Language Reference for further detail), and in the directories pointed to by the environment variable MOSEL_DSO. The contents of the enviroment variables MOSEL_BIM and MOSEL_DSO 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=.
   Alternatively, you can use the compilation option -bx to indicate the location of package files (this option does not apply to DSOs):
   mosel exe -bx ./ mymodel.mos
   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.

## 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 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

Having made sure that Mosel is able to find our package myconstants.bim (see the notes about package location at Packages), 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 solarraypkg.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 solarrpkg_test.mos):

    model "Test solarray package"
     uses "solarraypkg", "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.

### Implementation alternative using union types and iterator

A generic implementation of the subroutine solarray (see file solarranypkg.mos) can be achieved with the help of union types in combination with the iterator functionality provided by the module mmreflect that makes it possible to enumerate arrays of dense or sparse format without any explicit knowledge about their indexing sets. As a first step, this routine needs to check whether the two arguments are indeed arrays of the expected types (mpvar and real respectively), followed by a comparison of the index sets, similarly to the C implementation as a module. This new implementation accepts any type and number of index sets and is therefore considerably more generic than any set of explicitly defined overloaded subroutine versions.

    package solarrayanypkg
     uses "mmreflect"

     ! Utility routine checking whether 2 arrays have the same index set types
     function checkindices(x:any, s:any): boolean
       returned:= x.array.nbdim=s.array.nbdim and
         and(i in 1.. x.array.nbdim)
           x.array.index(i).eltype=s.array.index(i).eltype
     end-function

     ! Generic implementation of solarray routine
     public procedure solarray(x:any, s:any)
       declarations
         it: iterator
       end-declarations
       if x is array of mpvar and s is array of real then
         if checkindices(x,s) then
           inititer(it,x.array)
           reset(s.array)
           while (nextcell(it)) s.array(it).real:= x.array(it).mpvar.sol
         else
           writeln("SOLARRAY: array indices don't match")
         end-if
       else
         writeln("SOLARRAY: arguments must be arrays of type mpvar / real")
       end-if
     end-procedure

    end-package

This subroutine solarray provided by the package solarranypkg is used exactly in the same way as what we have seen earlier for the package solarrpkg.

## 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 'arcpkg' to avoid having to repeat it in every model.

Such a package may look as follows (file arcpkg.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 "arcpkg"

     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 `arcpkg' 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 `arcpkg' 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

## Definition of parameters

Mosel parameters are scalars of one of the four basic types (real/integer/string/boolean). Packages can define new parameters by declaring their names and type in the parameters section. The package needs to store the current values of the parameters in separate model entities and will usually initialize default values for the parameters.

    package parpkg

     ! Specify parameter names and types
     parameters
      "p1":real
      "p2":integer
      "p3":string
      "p4":boolean
     end-parameters

     ! Entities for storing current parameter values
     declarations
      myp1: real
      myp2: integer
      myp3: string
      myp4: boolean
     end-declarations

     ! Set default values for parameters
     myp1:=0.25
     myp2:=10
     myp3:="default"
     myp4:=true

     !... Parameter access routines ...
    end-package

The access routines for the four parameter types have a fixed format, namely packagename∼get[r|i|s|b]param and packagename∼set[r|i|s|b]param as shown in the code extract below.

     ! Get value of a real parameter
     public function parpkg~getrparam(p:string):real
      case p of
       "p1": returned:=myp1
      end-case
     end-function

     ! Get value of an integer parameter
     public function parpkg~getiparam(p:string):integer
      case p of
       "p2": returned:=myp2
      end-case
     end-function

     ! Get value of a string parameter
     public function parpkg~getsparam(p:string):string
      case p of
       "p3": returned:=myp3
      end-case
     end-function

     ! Get value of a boolean parameter
     public function parpkg~getbparam(p:string):boolean
      case p of
       "p4": returned:=myp4
      end-case
     end-function

     ! Set value for real parameters
     public procedure parpkg~setparam(p:string,v:real)
      case p of
       "p1": myp1:=v
      end-case
     end-procedure

     ! Set value for integer parameters
     public procedure parpkg~setparam(p:string,v:integer)
      case p of
       "p2": myp2:=v
      end-case
     end-procedure

     ! Set value for string parameters
     public procedure parpkg~setparam(p:string,v:string)
      case p of
       "p3": myp3:=v
      end-case
     end-procedure

     ! Set value procedure for boolean parameters
     public procedure parpkg~setparam(p:string,v:boolean)
      case p of
       "p4": myp4:=v
      end-case
     end-procedure

A model using the package 'parpkg' will access the package parameters via Mosel's standard getparam and setparam routines ( the parameter names are not case-sensitive and their names can be preceded by the package name).

    model "Packages with parameters"
     uses 'parpkg'

     ! Display default parameter values
     writeln("Default values:",
       " p1=", getparam("parpkg.P1"), " p2=", getparam("P2"),
       " p3=", getparam("parpkg.p3"), " p4=", getparam("p4"))

     ! Change values
     setparam("p1",133)
     setparam("parpkg.p2",-77)
     setparam("P3","tluafed")
     setparam("parpkg.P4",not getparam("parpkg.P4"))

    end-model

## Namespaces

A namespace is a group of identifiers in a program that is distinguished by a common name (prefix). When working with mutiple packages it can be helpful to introduce namespaces in order to structure the data and to determine which model entities are accessible to other (all or preselected) packages or models.

A fully qualified entity name in Mosel is of the form

    nspc~ident

where nspc is a namespace name and ident an identifier in the namespace. Namespaces and their access are specified via specific compiler directives at the start of the model or package. The package example mynspkg1 below defines three namespaces ('ns1', 'ns3', and 'ns3∼ns31'), two of which are restricted to a namespace group that comprises a second package mynspkg2, and the namespace 'ns3' is visible to all packages and models. The package further states via the nssearch directive that any unqualified entity names employed in the package should be searched for in the namespace 'ns1', meaning that the names belonging to this namespace can be used without the namespace prefix ns1∼.

    package mynspkg1
     namespace ns1, ns3, ns3~ns31         ! This package defines 3 namespaces:
     nsgroup ns1: "mynspkg2"              !  * ns1 + ns3~ns31 restricted to pkg2
     nsgroup ns3~ns31: "mynspkg2"         !  * ns3 is visible to all
     nssearch ns1                         ! 'ns1' can be used without prefix

     declarations
       ns3~R = 1..10
       ns1~Ar: array(ns3~R) of integer    ! Array with index set in another namespace
       vi, ns3~vi, ns3~ns31~vi: integer   ! 3 different entities
     end-declarations

     public declarations
       vp: integer                        ! This entity is visible to all
     end-declarations

     procedure ns1~proc1(val:integer)     ! Subroutine in a namespace
       ns3~vi:=val; ns3~ns31~vi:=2*val; vi:=val; vp:=val
       Ar(5):=val                         ! No prefix: 'ns1' is in search list
       writeln(" In ns1~proc1: ", vi)
     end-procedure

     public procedure proc2(val:integer)  ! Public subroutine
       writeln(" In proc2: ", val)
     end-procedure

     procedure proc3(val:integer)         ! Private subroutine
       writeln(" In proc3: ", val)
     end-procedure
    end-package

The package mynspkg1 shows some examples of entity and subroutine defintions for the three cases: private (vi, proc3), in a namespace (ns3∼R, ns1∼Ar, ns3∼vi, ns3∼ns31∼vi, ns1∼proc1), and public (vp, proc2).

The second package mynspkg2 that uses functionality from mynspkg1 needs to state which namespaces are used, either via a namespace or a nssearch directive.

    package mynspkg2
     uses 'mynspkg1'
     namespace ns3~ns31                   ! Namespace used in this package
     nssearch ns1                         ! 'ns1' can be used without prefix

     public procedure frompkg2(val: integer)
       proc1(val)                         ! Procedure in namespace 'ns1'
       writeln("  frompkg2:",ns3~ns31~vi) ! Namespace 'ns3~ns31' is not searched
       writeln("  vp=", vp)               ! Public symbol of pkg1
       writeln("  Ar(5)=", Ar(5))         ! Contained in 'ns1' (prefix optional)
     end-procedure
    end-package

Any model or further package using the previous two packages can access the namespace 'ns3' and also define new namespaces of its own, but it is not allowed to access the other two namespaces that are restricted to this group of packages.

    model "mynstest"
     uses 'mynspkg1', 'mynspkg2'
     namespace ns2     ! A new namespace
     nssearch ns3      ! Symbols from 'ns3' can be used without prefix

     frompkg2(5)                           ! Public routine from package mynspkg1
     writeln("n3~vi:", vi, " vp:", vp)     ! Display values of n3~vi and vp

     proc2(4)                              ! Public subroutine from mynspkg1

    end-model

An interesting feature of namespaces is that an entire namespace can be saved via initializations to simply by indicating its name and the stored information can subsequently be used to initialize entities in some other namespace with matching names and types.

     declarations
       ns2~vi: integer
       I, ns2~R: range
     end-declarations

     ! Store contents of namespace 'ns3'
     initializations to "mem:mynsav"
       ns3
     end-initializations

     ! Initialize entities with matching names from the saved namespace
     initializations from "mem:mynsav"
       ns2 as "ns3"
     end-initializations
     writeln("ns2~vi:", ns2~vi)            ! Has received the value of ns3~vi

     ! Read an individual entity from the saved namespace
     initializations from "mem:mynsav"
       I as "ns3~R"
     end-initializations
     writeln("I:", I)

## Package version management

Packages, just like Mosel models, can use the version compiler directive to define a version number of the format MMM.mmm.ppp (that is, up to 3 digits for each, major, minor, and patch numbers). Dynamic package loading relies on this number to decide whether the available package version is compatible with the required package version information recorded in a BIM file using this package. Mosel applies as a default compatibility rule that the (available/found) package version ap.bp.cp is compatible with the required package version ar.br.cr if ar=ap and bp>=br. For many cases, this rule is too restrictive (in particular, if you are not using any newer package functionality, a model might be expected to continue working with more recent package versions than the one it has been compiled with, as long as newer package versions continue to provide the original functionality).

Consider the following example of a package file versionedpkg.mos with three versions that incrementally add new (public) subroutines.

Initial version (1.0):

    package versionedpkg
     version 1.0

    !@mc.version.since 1.0.0
     public procedure showpkgver
       writeln("Using version ", getparam("model_version"),
         " of package 'versionedpkg'.")
     end-procedure

    end-package

Second version (2.0):

    package versionedpkg
     version 2.0
    !@mc.version.compatible 1.0.0

    !@mc.version.since 2.0
     public procedure myproc2
      writeln("Output from proc2")
     end-procedure

    !@mc.version.since 2.0
     public procedure myoldproc
      writeln("This subroutine is deprecated with v3.0.1")
     end-procedure

    !@mc.version.since 1.0.0
     public procedure showpkgver
       writeln("Using version ", getparam("model_version"),
         " of package 'versionedpkg'.")
     end-procedure

    end-package

Current version (3.1):

    package versionedpkg
     version 3.1
    !@mc.version.compatible 1.0.0
    !@mc.version.atleast 3.0

    !@mc.version.since 2.0
     public procedure myproc2
      writeln("Output from proc2")
     end-procedure

    !@mc.version.since 3.0.2
     public procedure myproc3
      writeln("Output from proc3")
     end-procedure

    !@mc.version.deprecated 3.0.1
    !@mc.version.since 2.0
     public procedure myoldproc
      writeln("This subroutine is deprecated with v3.0.1")
     end-procedure

    ! Unversioned subroutine (defaults to current package version)
     public procedure mynewproc
      writeln("Output from newproc")
     end-procedure

    !@mc.version.since 1.0.0
     public procedure showpkgver
       writeln("Using version ", getparam("model_version"),
         " of package 'versionedpkg'.")
     end-procedure

    end-package

These three versions of the package 'versionedpkg' specify version management annotations to define version compatibility rules and deprecation markup for subroutines. (The concept of annotations is explained more in detailed in Chapter Annotations.) A Mosel program using package functionality might look as follows:

    model "test package versioning"
     uses "versionedpkg"

     ! Calling a subroutine defined since the initial package version
     showpkgver

    end-model

If we have used the initial package version (1.0.0) for compiling this model we shall see in the output of Mosel's exam command on the resulting BIM file versionedpkg_test.bim the following dependency information:

    Model `test package versioning' version 0.0.0
     file: .\versionedpkg_test.bim
     sys. com.: `versionedpkg_test.mos',mc6.4.0
    (...)
     pkg. req.: versionedpkg (1.0.0)

    Procedures and Functions:
     procedure showpkgver [reqmt]

This means, that the compiled model can be run with a BIM file generated from any of the package versions above, since all of them are marked as compatible with version 1.0.0. The actual package version that is in use when running the model file will be displayed by the routine 'showpkgver', for example, with the third package version we will see the output:

    Using version 3.1.0 of package 'versionedpkg'.

If we now recompile the model file with a BIM file generated with the third version (3.1.0), we see the required package version in the output from the exam command change to 3.0.0 (we are not using any functionality from this version, but this package is tagged as requiring at least version 3.0). If we now add a call to the subroutine 'myproc3' into the model, the minimum required version will be raised to 3.0.2. Using the subroutine 'mynewproc' that does not have any version annotation will further raise the minimum version requirement to the current package version (3.1.0).

If we call the subroutine 'myoldproc' along with 'myproc3' from our model file, we shall see a deprecation warning displayed since this routine is marked as deprecated since 3.0.1, which is in conflict with the minimum version 3.0.2 that is induced by the use of 'myproc3':

    Mosel: W-241 at line 39 of `versionedpkg_test.mos': Using deprecated subroutine `myoldproc'.

## 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.

- 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
      - control parameters
  - Module
    - extend the Mosel language with
      - constant symbols
      - subroutines
      - operators
      - types
      - control parameters
      - I/O 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.

Parent Topic Extensions and tools

© 2001-2026 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.