Mosel tips and tricks Last update 25 February, 2013 www.fico.com Make every decision count TM
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 type text (module mmsystem) Structuring models Using include and packages Paths: getcwd, runtime parameters, DSO search path Advanced data structures: records, lists And also: Working with TAR archives Modeling tricks: Counters, indicators and logical constraints, dot notation, dates and times Deployment via an Excel VB macro Output redirection Tip 1: Adding a file to a compressed TAR archive lsf: list of text origfname: text 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) origdir, origfname, origextn, timestmp: text! 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 in filestochange) 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 c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 1
The type text Tip 3: How and where to use the type text The type text is defined in module mmsystem may be generated from all objects that can be converted to a text supports the usual string operations (concatenation, formatting txtfmt) uses "mmsystem" t: text t:= "a text" inserttext(t, "short ", 3) writeln("_"*80)! => t = a short text! Draw a line of 80 characters text vs. string Structuring Mosel models every string object in a model is entered in the names dictionary, text objects are not saved use string for indexation, use text whenever manipulating texts text objects can be altered (e.g.changing a sequence of characters in a text), strings cannot text supports wider set of operations (like insertion, deletion, removing trailing blanks, search of substrings) than string implicit conversion from string to text (but not the reverse): a routine expecting a text as parameter may be used with a string instead 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, keyword model is replaced by package included with the uses statement compile in the same way as Mosel models, place BIM on DSO search path package name = name of the BIM file (package.bim) definition of new subroutines, constants, and types Alternative to packages: include inserts contents into a model to be compiled with the model File toolbox.mos (compile to toolbox.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 Use package in a Mosel model: uses "toolbox" c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 2
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 (with uses) 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) requirements blocks are a special kind of declaration blocks in which constants are not allowed but procedure/functions can be declared Package P1: uses "P2" public myct: integer procedure dosomething(txt: text) writeln(calcvalue(txt)) end-procedure! Load package P2! Call function from P2 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) cwd varies depending how the application is started up retrieve cwd with getcwd or getparam("work_dir") cwd can be changed with setparam("work_dir", mynewdir) default cwd can be redefined by calling application with XPRMsetdefworkdir 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 fopen(dir+"log.txt", F_OUTPUT+F_APPEND)! Redirect output to file c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 3
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 variable MOSEL_DSO Can also set DSO directory at run time using XPRMsetdsopath (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 L: list of integer M: array(range) of list of string 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 a field and is characterized by its name and its type arc = record Source,Sink: string Cost: real end-record ARC: array(arcset:range) of arc! Source and sink of arc! Cost coefficient ARC(1).Source:= "B" ARC(3).Cost:= 1.5 writeln(arc(1))! => [Source= B Sink= Cost=0] Counters Tip 10: Counters: using count The aggregate operator count returns the number of times that a test succeeds L: list of string L:= [ a, ab, abc, da, bc, db ] writeln("occurences of b in L: ", count(s in L findtext(s, b, 1)>0) ) c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 4
Tip 11: Counters: using as counter Use the construct as counter to specify a counter variable in a bounded loop (i.e., forall or aggregate operators such as sum): 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 variable b with a linear constraint C models an implication: if b = 1 then C, in symbols: b C, or if b = 0 then C, in symbols: b C (the constraint C is 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 (type mpvar) and a linear inequality constraint (type linctr) Specify the type of the implication (1 for b C and -1 for b C) The subroutine indicator returns a new constraint of type logctr that can be used in the composition of other logic expressions uses "mmxprs" C: linctr L: logctr x1, x2, b: mpvar b is_binary! Variable for indicator constraints C:= x2<=5 L:= indicator(1, b, x1+x2>=12) indicator(-1, b, C) C:=0! b=1 -> x1+x2>=12! b=0 -> x2<=5! Delete auxiliary constraint definition Tip 13: Logic constructs Package advmod defines type logctr for 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 operations and, or, xor, implies, and not Must include the package advmod instead of the Optimizer library mmxprs uses "advmod" x: array(1..3) of mpvar implies(x(1)>=10, x(1)+x(2)>=12 and not x(2)<=5) c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 5
p: array(r) of mpvar 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 menu Deploy Deploy..., select Visual Basic, then confirm with Next copy the displayed VB code into the clipboard Generate the BIM file Create a macro-enabled spreadsheet (.xlsm) Select Excel menu Developer Insert 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 menu Developer Visual Basic File Import File... add xprm.bas from the include subdirectory of Xpress to the project Select the button with right mouse key to edit its text If you do not see the Developer menu: Excel 2007: click on the round button top left then select Excel Options; under the Popular section, check the option Show Developer tab Excel 2010: on the File tab, choose Options, then choose Customize Ribbon and in the list of Main Tabs, select the Developer check box: a new tab of the ribbon menu will appear with a VBA option Output redirection to spreadsheet: Define a cell range Output (Excel 2010: select the desired area with you mouse, then use the menu Formulas Define Name to 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 Strip the extra newline character and print to sheet Range("Output").Cells(1, 1) = Mid(msg, 1, Len(msg) - 1) End Function c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 6
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 mmsystem defines types date, time, and datetime for handling date and time types conversion to/from numerical values, e.g., for use as indices (getasnumber) Data connector modules mmsheet, mmodbc and mmoci support 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 d: integer T: time Dates: array(1..5) of date writeln(datetime(sys_now)) setparam("timefmt", "%0H:%0M:%0S") setparam("datefmt", "%y-%0m-%0d")! Datetime returned by system! Set new time format! 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 Function getweek below returns the calendar week count for a given date. implementation: getasnumber calculates the Julian day number and getweekday 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 end-function c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 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 interactive session none, can be used remotely File creation for output no yes yes Output writing mechanism on-screen display without saving if application running, otherwise data saved into file data saved into file Named ranges yes yes no Multiple worksheets yes yes no VB Macros yes yes no none, can be used remotely data saved into file Parameters Tip 20: Accessing parameters with bitmap format Parameters that are encoded as bitmaps are accessed as integers The Mosel function bittest checks 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 setparam("xprs_cutselect", -8193)! All except bit 13 (-1-2^13 = -8193) c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 8
Using assert Tip 21: Using assert to validate input data The assert statement serves for checking input data (including model parameters) for correct types and values by default, assert is only executed for models compiled in debug mode (flages g or G ), this behaviour is changed by specifying option keepassert 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 assert(getfstat(datafile)=0, "Data file not found", 5) c Copyright 2001 2013 Fair Isaac Corporation. All rights reserved. page 9