Mosel tips and tricks
New and less known features of Mosel
• Selected new features
– Adding a file to a tar archive (new in Rel 7.3)
– Adding a timestamp into a file name (new in Rel 7.3)
– Text handling: How and where to use the typetext(modulemmsystem) • Structuring models
– Using include and packages
– Paths: getcwd, runtime parameters, DSO search path
– Advanced data structures: records, lists • And also:
– Modeling tricks: Counters, indicators and logical constraints, dot notation, dates and times
– Deployment via an Excel VB macro
– Output redirection
Working with TAR archives
Tip 1: Adding a file to a compressed TAR archive
declarations
lsf: list of text origfname: text
end-declarations
makedir(gettmpdir+"/tartemp") ! Create temporary directory
if getfstat(archivename)<>0 then ! Untar if archive exists untar("zlib.gzip:"+archivename, gettmpdir+"/tartemp")
end-if
! Copy file to temporary directory
origfname:=pathsplit(SYS_FNAME,filetoadd)
fcopy(filetoadd, ":"+ gettmpdir+"/tartemp/"+origfname)
! Rebuild the archive
findfiles(SYS_RECURS, lsf, gettmpdir+"/tartemp", "*")
newtar(0, "zlib.gzip:"+archivename, gettmpdir+"/tartemp", lsf) removefiles(SYS_RECURS, gettmpdir+"/tartemp", "*")
removedir(gettmpdir+"/tartemp") ! Delete temporary files
Timestamp
Tip 2: Inserting a time stamp into a file name
public procedure addtimestamp(filestochange: set of string)
declarations
origdir, origfname, origextn, timestmp: text
end-declarations
! Create a time stamp - redefining datetime format as to avoid use ! of ’:’ to prevent interpretation as I/O driver
usedfmt:=getparam("datetimefmt") ! Save present format setparam("datetimefmt", "%0d%0m%0yT%0H.%0M.%0S")
timestmp:= text(datetime(SYS_NOW))
setparam("datetimefmt", usedfmt) ! Reset to previous format
! Rename all files to include the time stamp in their name
forall(f infilestochange) do
origdir:=pathsplit(SYS_DIR,f) origfname:=pathsplit(SYS_FNAME,f)
origextn:=pathsplit(SYS_EXTN,origfname,origfname)
fmove(f, origdir + "/" + origfname + "-"+timestmp +"." +origextn)
end-do end-procedure
The type ’text’
Tip 3: How and where to use the typetext
• The typetextis defined in modulemmsystem
– may be generated from all objects that can be converted to a text
– supports the usual string operations (concatenation, formattingtxtfmt) uses "mmsystem"
declarations
t: text
end-declarations
t:= "a text"
inserttext(t, "short ", 3) ! => t = ’a short text’ writeln("_"*80) ! Draw a line of 80 characters • textvs. string
– everystringobject in a model is entered in the names dictionary,textobjects are not saved
⇒usestringfor indexation, usetextwhenever manipulating texts
– text objects can be altered (e.g.changing a sequence of characters in a text), strings cannot
– textsupports wider set of operations (like insertion, deletion, removing trailing blanks, search of substrings) thanstring
– implicit conversion fromstringtotext(but not the reverse): a routine expecting a text as parameter may be used with a string instead
Structuring Mosel models
Tip 4: Working with packages
• Package= Mosel library written in the Mosel language (as opposed to Mosel modules that are implemented in C)
– similar structure as models, keywordmodelis replaced bypackage – included with theusesstatement
– compile in the same way as Mosel models, place BIM on DSO search path
– packagename= name of the BIM file (package.bim)
– definition of new subroutines, constants, and types
• Alternative to packages: includeinserts contents into a model to be compiledwiththe model
• Filetoolbox.mos(compile totoolbox.bim) package toolbox
uses "mmsystem"
version 12.08.30
public procedure addtimestamp(filestochange: set of string) ...
end-procedure
! Overloaded version with different arguments
public procedure addtimestamp(filetochange: string) addtimestamp({filetochange})
end-procedure end-package
Tip 5: Package dependencies
• A package cannot be imported several times by a model and packages publish symbols of packages they use
– example: if package P1 imports package P2, then a model using P1 cannot import explicitly P2 (withuses) but has access to the functionality of P2 via P1.
• Requirements= symbols a package requires for its processing but does not define
– the symbols must be defined either in the model or in another package (but not in a module)
– requirementsblocks are a special kind of declaration blocks in which constants are not allowed but procedure/functions can be declared
• Package P1:
uses "P2" ! Load package P2
declarations
public myct: integer end-declarations
procedure dosomething(txt: text)
writeln(calcvalue(txt)) ! Call function from P2
end-procedure • Package P2:
requirements
myct: integer
procedure dosomething(txt: text) ! Can now use subroutine from P1
end-requirements
function calcvalue(txt: text): integer
myct += 1 ! Use a symbol defined in P1 returned:= ...
File and DSO paths
Tip 6: Paths in Mosel models
• Files referred to in Mosel models will be sought relative to the current working directory (cwd)
– cwdvaries depending how the application is started up
– retrievecwdwithgetcwdorgetparam("work_dir")
– cwdcan be changed withsetparam("work_dir", mynewdir)
– defaultcwdcan be redefined by calling application withXPRMsetdefworkdir
• ⇒Use absolute paths or provide a path root via a model parameter for all files to avoid problems
parameters
DIR="./"
FILENAME="mydata.xls"
end-parameters
setparam("work_dir", getparam("tmpdir")) ! Set Mosel’s temp. dir. as cwd writeln(getcwd) ! Display new cwd
initializations from "mmsheet.xls:"+DIR+FILENAME ...
end-initializations
Tip 7: DSO search paths
• DSOs and packages of the Mosel distribution are found automatically if the full Xpress installation process followed
• Additional DSO or package locations can be specified by setting the environment variableMOSEL_DSO
• Can also set DSO directory at run time usingXPRMsetdsopath(in calling application) or in the calling model (setting does not apply to the model itself!)
! Set MOSEL_DSO to the default location of DSOs setenv("MOSEL_DSO", getenv("XPRESSDIR") + "/dso")
Advanced data structures
Tip 8: Advanced data structures: lists
• List= collection of objects of the same type • A list may contain the same element several times • The order of the list elements is specified by construction
declarations
L: list of integer
M: array(range) of list of string end-declarations
L:= [1,2,3,4,5]
M:: (2..4)[[’A’,’B’,’C’], [’D’,’E’], [’F’,’G’,’H’,’I’]] L2:= gethead(L,3) ! => L2=[1,2,3]
reverse(L) ! => L=[5,4,3,2,1] cuttail(L,2) ! => L=[5,4,3] Tip 9: Advanced data structures: records
• Record= finite collection of objects of any type
• Each component of a record is called afieldand is characterized by its name and its type declarations
arc = record
Source,Sink: string ! Source and sink of arc Cost: real ! Cost coefficient
end-record
ARC: array(ARCSET:range) of arc
end-declarations
ARC(1).Source:= "B" ARC(3).Cost:= 1.5
writeln(ARC(1)) ! => [Source=’B’ Sink=’’ Cost=0]
Counters
Tip 10: Counters: usingcount
• The aggregate operatorcountreturns the number of times that a test succeeds declarations
L: list of string end-declarations
L:= [’a’, ’ab’, ’abc’, ’da’, ’bc’, ’db’]
writeln("Occurences of ’b’ in L: ",
Tip 11: Counters: usingas counter
• Use the constructas counterto specify a counter variable in a bounded loop (i.e.,
forallor aggregate operators such assum): at each iteration, the counter is incremented
S:= {1, 5, 8, -1, 4, 7, 2} cnt:=0.0
writeln("Number of odd numbers in S: ", count(i in S | isodd(i)) ) writeln("Average of odd numbers in S: ",
(sum(cnt as counter, i in S | isodd(i)) i) / cnt)
Indicator and logical constraints
Tip 12: Indicator constraints
• Indicator constraint= global entity that associates a binary variablebwith a linear constraintC
– models an implication:
’ifb= 1 thenC’, in symbols:b→C, or ’ifb= 0 thenC’, in symbols: ¯b→C
(the constraintCis active only if the condition is true)
• ⇒Use indicator constraints for the formulation of logic expressions in the place of big-M constructs
Tip 12: Indicator constraints in Mosel
• Need a binary variable (typempvar) and a linear inequality constraint (typelinctr) • Specify the type of the implication (1 forb→Cand -1 for ¯b→C)
• The subroutineindicatorreturns a new constraint of typelogctrthat can be used in the composition of other logic expressions
uses "mmxprs" declarations C: linctr L: logctr x1, x2, b: mpvar end-declarations
b is_binary ! Variable for indicator constraints
C:= x2<=5
L:= indicator(1, b, x1+x2>=12) ! b=1 -> x1+x2>=12 indicator(-1, b, C) ! b=0 -> x2<=5
C:=0 ! Delete auxiliary constraint definition Tip 13: Logic constructs
• Packageadvmoddefines typelogctrfor defining and working with logic constraints in MIP models
• Implementation of these constraints is based on indicator constraints
• Build logic constraints with linear constraints using the operationsand,or,xor,
implies, andnot
• Must include the packageadvmodinstead of the Optimizer librarymmxprs
uses "advmod"
declarations
x: array(1..3) of mpvar end-declarations
declarations
p: array(R) of mpvar end-declarations
forall(i in R) p(i) is_binary
! Choose at least one of projects 1,2,3 (option A) ! or at least two of projects 2,4,5,6 (option B)
p(1) + p(2) + p(3) >= 1 or p(2) + p(4) + p(5) + p(6) >= 2
! Choose either option A or option B, but not both
xor(p(1) + p(2) + p(3) >= 1, p(2) + p(4) + p(5) + p(6) >= 2)
Deployment via an Excel VB macro
Tip 14: Deployment via an Excel VB macro
• Generate VB code using the IVE deployment wizzard
– menuDeployDeploy ..., selectVisual Basic, then confirm withNext
– copy the displayed VB code into the clipboard • Generate the BIM file
• Create a macro-enabled spreadsheet (.xlsm) • Select Excel menuDeveloperInsert
– select the button object and position it using the mouse
– assign a new macro to the button and paste the VB code from clipboard into the macro
• Using Excel menuDeveloperVisual BasicFileImport File...addxprm.basfrom theincludesubdirectory of Xpress to the project
• Select the button with right mouse key to edit its text • If you do not see theDevelopermenu:
– Excel 2007: click on the round button top left then selectExcel Options; under thePopularsection, check the optionShow Developer tab
– Excel 2010: on theFiletab, chooseOptions, then chooseCustomize Ribbonand in the list ofMain Tabs, select theDevelopercheck box:
– a new tab of the ribbon menu will appear with a VBA option • Output redirection to spreadsheet:
– Define a cell rangeOutput
(Excel 2010: select the desired area with you mouse, then use the menuFormulas
Define Nameto enter the range name)
– Edit the macro (after XPRMinit):
Call XPRMsetdefstream(0, XPRM_F_WRITE, XPRM_IO_CB(AddressOf OutputCB)) ...
Public Function OutputCB(ByVal model As Long, ByVal info As Long, ByVal msg As String, ByVal size As Long) As Long ’ Process windows messages so Excel GUI responds
DoEvents
Output redirection
Tip 15: Output redirection
• Redirection within a Mosel model:
! tee: Dedouble output to file + default output (screen) fopen("tee:mylogfile.txt&", F_OUTPUT+F_APPEND)
writeln(...) fclose(F_OUTPUT)
• Redirect streams for submodels from master model (corresponding library function
XPRMsetdefstream):
! null: Discard all output; tmp: Mosel’s temporary directory setdefstream("mysubmod.mos", F_OUTPUT, "null:")
setdefstream("mysubmod.mos", F_ERROR, "tmp:errlog.txt")
Dates and times
Tip 16: Dates and times
• mmsystemdefines typesdate,time, anddatetimefor handling date and time types
– conversion to/from numerical values,e.g., for use as indices (getasnumber)
• Data connector modulesmmsheet,mmodbcandmmocisupport these types for reading and writing data
– representation of date and time information within databases is different from one product to another and may not be compatible with Mosel’s default format⇒ adapt format settings
declarations
d: integer T: time
Dates: array(1..5) of date
end-declarations
writeln(datetime(SYS_NOW)) ! Datetime returned by system
setparam("timefmt", "%0H:%0M:%0S") ! Set new time format setparam("datefmt", "%y-%0m-%0d") ! Set new date format
! Convert date created from string to number (JDN) d:= getasnumber(date("2012-12-25")))
initializations from "mmodbc.odbc:datetime.mdb" T as "Time1"
Dates as "noindex;Dates"
end-initializations
Tip 17: Calculating the calendar week number
• Functiongetweekbelow returns the calendar week count for a given date.
– implementation: getasnumbercalculates the Julian day number andgetweekday
returns the week day number for a date
– usage:wnum:= getweek(date(2012,2,29))
function getweek(d:date): integer
firstday:=date(getyear(d-getweekday(d)+4),1,3) returned:= (getasnumber(d) - getasnumber(firstday) +
getweekday(firstday+1)+5) div 7
Lower/upper case conversions
Tip 18: How to convert a text into lower (upper) case
• Note: The following routine supposes ASCII encoding
! Turn upper case letters into lower case
public function makelowercase(t: text): text returned:=t
forall(i in 1..t.size) do
v:=getchar(t,i)
if (v>=65 and v<=90) then ! lower to upper: v>=97 and v<=122 setchar(returned, i, v+32) ! lower to upper: v-32
end-if end-do end-function
! Overloaded version for ’string’
public function makelowercase(t: string): string
returned:=string(makelowercase(text(t)))
end-function
Spreadsheet IO drivers
Tip 19: Comparison of spreadsheet drivers
excel xsl/xslx csv
File type physical file physical file extended file
Supported platforms Windows Windows, Linux, Mac all Xpress platforms
Requirements Excel + open inter-active session
none, can be used remotely
none, can be used remotely
File creation for output no yes yes
Output writing mecha-nism
on-screen display without saving if application run-ning, otherwise data saved into file
data saved into file
data saved into file
Named ranges yes yes no
Multiple worksheets yes yes no
VB Macros yes yes no
Parameters
Tip 20: Accessing parameters with bitmap format
• Parameters that are encoded as bitmaps are accessed as integers • The Mosel functionbittestchecks whether a bit is set
! Turn on bits 0, 1, and 4, all else off (2^0 + 2^1 + 2^4 = 1+2+16 = 19) setparam("XPRS_HEURSEARCHTREESELECT",19)
! Modify the current setting: turn off bit 5 (2^5 = 32) presolveops:= getparam("XPRS_PRESOLVEOPS")
if bittest(presolveops,32)=32 then presolveops-=32; end-if
setparam("XPRS_PRESOLVEOPS", presolveops)
! The value of a signed integer with all bits equal to 1 is -1 setparam("XPRS_CUTSELECT", -1) ! Enable all features
Using ’assert’
Tip 21: Usingassertto validate input data
• Theassertstatement serves for checking input data (including model parameters) for correct types and values
– by default,assertis only executed for models compiled in debug mode (flages ’g’ or ’G’), this behaviour is changed by specifying optionkeepassert
– the default error code returned by ’assert’ is 8, an alternative value can be specified as the optional third argument
options keepassert ! Always apply ’assert’
parameters
A=10
DATAFILE="mydata.dat"
end-parameters
assert(A in 1..20, "Wrong parameter value") (! Same as:
if A not in 1..20 then
writeln("Wrong parameter value") exit(8)
end-if !)
! If file not found, return exit code 5