Upgrading from Mosel 4 to Mosel 5
Topics covered in this section:
- Dynamic package loading
- Array handling
- Stricter syntax checks
- Compilation options
- Notes for Insight users
The new language features introduced by Mosel 5 are largely incremental to the existing functionality and language syntax. However, a few points may require updates to existing Mosel source code.
Dynamic package loading
Packages are now handled like native modules: they are loaded dynamically at runtime when the model is loaded into memory.
In models
In order to maintain the same behaviour with Mosel 5 as with Mosel 4, employ imports in place of uses for all packages that are not part of the Xpress distribution
- Make sure to always start with the imports statements, and then the uses statements (this is important if the same package is loaded several times, e.g. directly via a uses and indirectly through a dependency via imports).
- If you do decide to work with dynamic packages these must be made available at run time (in particular, this also concerns the BIM files in Insight apps).
In packages
Specify the complete list of uses for all descendants that are used directly by this package.
Example: pkga uses pkgb, pkgb uses pkgc and pkgd
If pkga uses directly some functionality from pkgc it now needs to load this package explicitly, but there is no need for pkga to load pkgd if it does not use it.
- Do not use imports in packages.
mmjobs
If a model or package loads a package via the mmjobs routine load (e.g. to inspect its annotations) you should now specify the option 'l' for lazy loading to load and inspect only the package itself without any dependencies.
Paths
Previously it was sufficient to specify BIM locations (e.g. via the BIM prefix -bx) for compilation, now these files are also required for loading a model (that is, at runtime) if the packages are loaded dynamically:
- Use the new environment variable MOSEL_BIM or set the control parameter 'bimprefix' within a model:
setparam("bimprefix", "./") ! Package BIMs are in the model's working directory
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=[]
Stricter syntax checks
Stricter syntax checks may reveal programming errors in certain cases.
Requirement for the public qualifier
The requirement for the public qualifier is now made strict.
- The Mosel postprocessing API (C, C#, Java etc.) function XPRMfindident no longer works for entities that are not explicitly declared as public.
- When a user (record) type definition is public, all types used for fields in this record definition must be public (even if the fields themselves possibly are not public).
Duplicate use of loop indices
The duplicate use of loop indices is no longer possible. For example, in place of
forall(f in union(f in Lsf) {f})
you now need to use
forall(f in union(ff in Lsf) {ff})
Package names
Package names (that is, the name of the package BIM file) are identifiers. Whilst these names were previously not actively used, employing the same name for a package and for an entity, type, or subroutine is no longer possible.
Compilation options
The Mosel compiler now uses by default the strip (-s) compilation and the previous default mode that was keeping private entities has been removed.
There will be no change in behaviour if you are using the -s compilation option for deployment/generation of production versions of your Mosel models following the standard recommendations for application deployment. However, if you have been working with the default compilation settings this new version might reveal cases where the explicit public qualifier is missing for entities that need to be visible to external programs (this includes Mosel subroutines employed as callbacks for Xpress Solvers and also any model entities that are accessed from Xpress Insight).
Typical error messages in this case may look as follows:
XPRS: wrong procedure type for callback xxx Kalis: Invalid function name passed to xxx
Notes for Insight users
Xpress Insight 4.11.2 or later is compatible with Mosel 5.
App models compiled with Mosel 4.2 or more recent can be run with Mosel 5. However, although they have been compiled with an older release, they will be executing on the new architecture and their behavior may change due to the refactoring of the array handling (see Section Array handling).
If you re-compile the App model with Mosel 5, be aware of the following:
- All declarations of Insight entities need to be prefixed with the public qualifier (a quick workaround is to compile with the -g debug compilation option which preserves all global entities).
- Insight 4.x does not support dynamic packages. Use the imports keyword instead of uses to statically link in packages.
- Insight 4.x does not support the new namespaces feature.
- Mosel 5 introduces some changes to the handling of arrays (see Section 'Array handling') which may impact your model. The symptom is that a previously (implictly) dynamic array is now dense and this is best diagnosed by asserting whether the size of arrays and/or their dependencies such as problem matrix dimensions are changed.
Note for Workbench users: Workbench now compiles BIM files into an output folder in the project, by default out, and copies the main BIM file into the root of the archive only on publish or download app. Therefore any legacy BIM file in the root of a project is obsolete and should be deleted to avoid confusion.
© 2001-2025 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.