Initializing help system before first use

Statements

Four types of statements are supported by the Mosel language. The simple statements can be seen as elementary operations. The initialization block is used to load data from a file or save data to a file. Selection statements allow one to choose between different sets of statements depending on conditions. Finally, the loop statements are used to repeat operations.

Each of these constructs is considered as a single statement. A list of statements is a succession of statements. No particular statement separator is required between statements except if a statement terminates by an expression. In that case, the expression must be finished by either a line break or the symbol ';'.

Simple statements

Assignment

An assignment consists in changing the value associated to an identifier. The general form of an assignment is:

ident_ref := Expression
or
ident_ref += Expression
or
ident_ref -= Expression

where ident_ref is a reference to a value (i.e. an identifier or an array/record dereference) and Expression is an expression of a compatible type with ident_ref. The direct assignment, denoted := replaces the value associated with ident_ref by the value of the expression. The additive assignment, denoted +=, and the subtractive assignment, denoted -=, are basically combinations of a direct assignment with an addition or a subtraction. They require an expression of a type that supports these operators (for instance it is not possible to use additive assignment with Boolean objects).

The additive and subtractive assignments have a special meaning with linear constraints in the sense that they preserve the constraint type of the assigned identifier: normally a constraint used in an expression has the value of the linear expression it contains, the constraint type is ignored.

c:= 3*x+y >= 5
c+= y              ! Implies c is 3*x+2*y-5 >= 0
c:= 3*x+y >= 5
c:= c + y          ! Implies c is 3*x+2*y-5 (c becomes unconstrained) 

Assignment of structured types

The direct assignment := can also be used with sets, lists, arrays and records under certain conditions. For sets and lists, reference and value must be of the same type, the system performing no conversion on structures. For instance it is not possible to assign a set of integers to a set of reals although assigning an integer value to a real object is valid.

When assigning records, reference and value must be of the same type and this type must be assignment compatible: two records having identical definitions are not considered to be the same type by the compiler. In most cases it will be necessary to employ a user type to declare the objects. A record is assignment compatible if all the fields it includes can be assigned a value. For instance a record including a decision variable (type mpvar) cannot be used in an assignment: copying a value of such a type has to be performed one field at a time skiping those fields that cannot be assigned.

Two arrays can be used in an assignment if they have strictly the same definition and are assignment compatible (i.e. their type supports assignment).

About implicit declarations

Each symbol should be declared before being used. However, an implicit declaration is issued when a new symbol is assigned a value the type of which is unambiguous.

! Assuming A,S,SE are unknown symbols
A:= 1              ! A is automatically defined
                   !   as an integer reference
S:={1,2,3}         ! S is automatically defined
                   !   as a set of integers
SE:={}             ! This produces a parser error as
                   ! the type of SE is unknown 

In the case of arrays, the implicit declaration should be avoided or used with particular care as Mosel tries to deduce the indexing sets from the context and decides automatically whether the created array must be dynamic. The result is not necessarily what is expected.

A(1):=1            ! Implies: A:array(1..1) of integer
A(t):=2.5          ! Assuming "t in 1..10|f(t) > 0"
                   ! implies: A:dynamic array(range) of real 

The option noimplicit disables implicit declarations (see Section Directive options).

Inline initialization

Using inline initialization it is possible to assign several cells of an array in a single statement. The general form of an inline initialization is:

ident_ref ::[ Exp1 [, Exp2 ...] ]
or
ident_ref ::(Ind1 [, Ind2 ...] )[ Exp1 [, Exp2 ...] ]

where ident_ref is the object to initialize (array, set or list) and Expi are expressions of a compatible type with ident_ref. The first form of this statement may be used with lists, sets and arrays indiced by ranges: the list of expressions is used to initialize the object. In the case of lists and sets this operation is similar to a direct assignment, with an array, the first index of each dimension is the lower bound of the indexing range or 1 if the range is empty.

The second form is used to initialize regions of arrays or arrays indiced by general sets: each Indi expression indicates the index or list of indices for the corresponding dimension. An index list can be a constant, a list of constants (e.g. ['a','b','c']) or a constant range (e.g. 1..10) but all values must be known at compile time.

declarations
 T:array(1..10) of integer
 U:array(1..9,{'a','b','c'}) of integer
end-declarations
T::[2,4,6,8]           ! <=> T(1):=2; T(2):=4;...
T::(2..5)[7,8,9,19]    ! <=> T(2):=7; T(3):=8;...
U::([1,3,6],'b')[1,2,3]! <=> U(1,'b'):=1; U(3,'b'):=2;... 

Linear constraint expression

A linear constraint expression can be assigned to an identifier but can also be stated on its own. In that case, the constraint is said to be anonymous and is added to the set of already defined constraints. The difference from a named constraint is that it is not possible to refer to an anonymous constraint again, for instance to modify it.

10<=x; x<=20
x is_integer 

Procedure call

Not all required actions are coded in a given source file. The Mosel language comes with a set of predefined procedures that perform specific actions (like displaying a message). It is also possible to import procedures from external locations by using modules or packages (cf. Section The compiler directives).

The general form of a procedure call is:

procedure_ident
procedure_ident (Exp1 [, Exp2 ...])

where procedure_ident is the name of the procedure and, if required, Expi is the ith parameter for the call (note that parameters of procedures are evaluated from right to left). Refer to Chapter Predefined functions and procedures of this manual for a comprehensive listing of the predefined procedures.The modules documentation should also be consulted for explanations about the procedures provided by each module.

writeln("hello!")     ! Displays the message: hello!

Initialization block

The initialization block may be used to initialize objects (scalars, arrays, lists or sets) of basic type from files or to save the values of such objects to files. Scalars and arrays of external/user types supporting this feature may also be initialized using this facility.

The first form of an initialization block is used to initialize data from a file:

initializations from Filename
  item1 [ as Label1]
  or
  [itemT11, itemT12 [ ,IdentT13 ...]] as LabelT1
[
    item2 [ as Label2]
    or
    [itemT21, itemT22 [ ,IdentT23 ...]] as LabelT2
...]
end-initializations

where Filename, a string expression, is the name of the file to read, itemi any object identifier and itemTij an array identifier. Each identifier is automatically associated to a label: by default this label is the identifier itself but a different name may be specified explicitly using a string expression Labeli. If a given item is of a record type, the operation is permitted only if all fields it contains can be initialized. For instance, if one of the fields is a decision variable (type mpvar), the compilation will fail. Alternatively, the fields to be initialized can be listed using the following syntax as an item:

Identifier(field1 [ ,filedi ...])

If a given item is a namespace (see Section Namespaces) all the identifiers it includes at the time of parsing the statement are implicitly added to the block with the exception of namespaces and entities that are not compatible with initializations (like decision variables). The associated labels are the fully qualified names of the objects (i.e. the identifier prefixed by the namespace) unless a label is specified for this record: in this case it is used as a replacement for the default prefix when generating the per entity labels such that an empty string will remove entirely the prefix. Using the compiler option -wi makes it possible to get a list of included identifiers by means of a compiler warning (see Section Running Mosel).

When an initialization block is executed, the given file is opened and the requested labels are searched for in this file to initialize the corresponding objects. Several arrays may be initialized with a single record. In this case they must be all indexed by the same sets, have scalar types and the label is obligatory. After the execution of an initializations from block, the control parameter nbread reports the number of items actually read in. Moreover, if control parameter readcnt is set to true before the execution of the block, counting is also achieved at the label level: the number of items actually read in for each label may be obtained using function getreadcnt.

An initialization file must contain one or several records of the following form:

Label: value

where Label is a text string and value either a constant of a basic type (integer, real, string or boolean) or a collection of values separated by spaces and enclosed in square brackets. Collections of values are used to initialize lists, sets records or arrays — if such a record is requested for a scalar, then the first value of the collection is selected. When used for arrays, indices enclosed in round brackets may be inserted in the list of values to specify a location in the corresponding array.

Note also that:

  • no particular formatting is required: spaces, tabulations, and line breaks are just normal separators
  • the special value '*' implies a no-operation (i.e. the corresponding entity is not initialized)
  • single line comments are supported (i.e. starting with '!' and terminated by the end of the line)
  • Boolean constants are either the identifiers false (FALSE) and true (TRUE) or the numerical constants 0 and 1
  • all text strings (including the labels) may be quoted using either single or double quotes. In the latter case, escape sequences are interpreted (i.e. use of '\').

By default Mosel expects that initialization files are encoded in UTF-8 and it can handle UTF-16 and UTF-32 when a BOM (Byte Order Mark) is used. To process files in another encoding, a special encoding comment line must be put at the beginning of the file (see section Source file character encoding). For instance a data file encoded with CP1252 should start with the following comment line:

!@encoding:CP1252

The second form of an initialization block is used to save data to a file:

initializations to Filename
  item1 [as Label1]
  or
  [itemT11, itemT12 [ ,IdentT13 ...]] as LabelT1
[
    item2 [ as Label2]
    or     [itemT21, itemT22 [ ,IdentT23 ...]] as LabelT2
...]
end-initializations

In this form, any itemi can be replaced by the value of an expression using the following construct (Labeli is mandatory in this case):

evaluation of expression

When this second form is executed, the value of all provided labels is updated with the current value of the corresponding identifier—A copy of the original file is saved prior to the update (i.e. the original version of fname can be found in fname ∼).— in the given file. If a label cannot be found, a new record is appended to the end of the file and the file is created if it does not yet exist.

For example, assuming the file a.dat contains:

! Example of the use of initialization blocks
t:[ (1 un) [10 11] (2 deux) [* 22] (3 trois) [30 33]]
t2:[ 10 (4) 30 40 ]
'nb used': 0 

consider the following program:

model "Example initblk"
declarations
 nb_used:integer
 s: set of string
 ta,tb: dynamic array(1..3,s) of real
 t2: array(1..5) of integer
end-declarations

initializations from 'a.dat'
 [ta,tb] as 't'   ! ta=[(1,'un',10),(3,'trois',30)]
                  ! tb=[(1,'un',11),(2,'deux',22),(3,'trois',33)]
 t2               ! t2=[10,0,0,30,40]
 nb_used as "nb used" ! nb_used=0
end-initializations

nb_used+=1
ta(2,"quatre"):=1000

initializations to 'a.dat'
 [ta,tb] as 't'
 nb_used as "nb used"
 s
end-initializations
end-model 

After the execution of this model, the data file contains:

! Example of the use of initialization blocks
t:[(1 'un') [10 11] (2 'deux') [* 22] (2 'quatre') [1000 *]
  (3 'trois') [30 33]]
t2:[ 10 (4) 30 40 ]
'nb used': 1
's': ['un' 'deux' 'trois' 'quatre'] 

In case of error (e.g. file not found, corrupted data format) during the processing of an initialization block, the execution of the model is interrupted. However if the value of control parameter ioctrl is true, executions continues. It is up to the user to verify whether data has been properly transfered by checking the value of control parameter iostatus.

About automatic finalization

During the execution of an initializations from block all sets are automatically finalized just after having been initialized (unless they have been explicitly declared as dynamic). This also applies to sets indirectly initialized through the non-dynamic arrays for which they are index sets. In addition, such an array is created as a static array if it has not been used before the initialization block.

This behaviour is controled by the autofinal control parameter which value may be changed using the setparam procedure (i.e. it is therefore possible to have automatic finalization active for only some initializations blocks). The compiler option noautofinal (see section Directive options) allows to disable this feature from the beginning of the model (although it can be re-enabled as required using the control parameter).

Selections

If statement

The general form of the if statement is:

if Bool_exp_1
then Statement_list_1
[
  elif Bool_exp_2
  then Statement_list_2
...]
[ else Statement_list_E ]
end-if

The selection is executed as follows: if Bool_exp_1 is true then Statement_list_1 is executed and the process continues after the end-if instruction. Otherwise, if there are elif statements, they are executed in the same manner as the if instruction itself. If, all boolean expressions evaluated are false and there is an else instruction, then Statement_list_E are executed; otherwise no statement is executed and the process continues after the end-if keyword.

if c=1
then writeln('c=1')
elif c=2
then writeln('c=2')
else writeln('c<>1 and c<>2')
end-if 

Case statement

The general form of the case statement is:

case Expression_0 of
Expression_1: Statement_1
or
Expression_1: do Statement_list_1 end-do
[
  Expression_2: Statement_2
  or
  Expression_2: do Statement_list_2 end-do
...]
[ else Statement_list_E ]
end-case

The selection is executed as follows: Expression_0 is evaluated and compared sequentially with each expression of the list Expression_i until a match is found. Then the statement Statement_i (resp. list of statements Statement_list_i) corresponding to the matching expression is executed and the execution continues after the end-case instruction. If no matching is found and an else statement is present, the list of statements Statement_list_E is executed, otherwise the execution continues after the end-case instruction. Note that, each of the expression lists Expression_i can be either a scalar, a set or a list of expressions separated by commas. In the last two cases, the matching succeeds if the expression Expression_0 corresponds to an element of the set or an entry of the list.

case c of
  1     : writeln('c=1')
  2..5  : writeln('c in 2..5')
  6,8,10: writeln('c in {6,8,10}')
  else writeln('c in {7,9} or c >10 or c <1')
end-case 

Loops

Forall loop

The general form of the forall statement is:

forall (Iterator_list) Statement
or
forall (Iterator_list) do Statement_list end-do

The statement Statement (resp. list of statements Statement_list) is repeated for each possible index tuple generated by the iterator list (cf. Section Aggregate operators).

forall (i in 1..10, j in 1..10 | i<>j) do
  write(' (' , i, ',' , j, ')')
  if isodd(i*j) then s+={i*j}
  end-if
end-do 

While loop

The general form of the while statement is:

while (Bool_expr) Statement
or
while (Bool_expr) do Statement_list end-do

The statement Statement (resp. list of statements Statement_list) is repeated as long as the condition Bool_expr is true. If the condition is false at the first evaluation, the while statement is entirely skipped.

i:=1
while(i<=10) do
  write(' ',i)
  if isodd(i) then s+={i}
  end-if
  i+=1
end-do 

Repeat loop

The general form of the repeat statement is:

repeat
Statement1
[ Statement2 ...]
until Bool_expr

The list of statements enclosed in the instructions repeat and until is repeated until the condition Bool_expr is true. As opposed to the while loop, the statement(s) is (are) executed at least once.

i:=1
repeat
  write(' ',i)
  if isodd(i) then s+={i}
  end-if
  i+=1
until i>10 

break and next statements

The statements break and next are respectively used to interrupt and jump to the next iteration of a loop. The general form of the break and next statements is:

break [n|label]
or
next [n|label]

where n is an optional integer constant: n-1 nested loops are stopped before applying the operation. This optional argument may also be a label (in the form an identifier or a string constant): in this case the loop to consider is identified by a label that must be defined just before the corresponding loop using the following syntax:

label :

The label can be either an identifier (that is not associated to any entity) or a constant string. The scope of each label is limited to the loop it identifies.

! in this example only the loop controls are shown
L1:                 ! 1: Define label "L1"
repeat              ! 2: Loop L1
 forall (i in S) do ! 3: Loop L2
  while (C3) do     ! 4: Loop L3
   break 3          ! 5: Stop the 3 loops and continue after line 12
   next             ! 6: Go to next iteration of L3 (line 4)
   next 2           ! 7: Stop L3 and go to next 'i' (line 3)
  end-do            ! 8: End of L3
  next "L1"         ! 9: Stop L2, go to next iteration of L1 (line 12)
  break             !10: Stop L2 and continue after line 11
 end-do             !11: End of L2
until C1            !12: End of L1 

with statement

The general syntax of this statement is:

with ident_1=exp_1 [, ident_2=exp_2...] do
  Statement
  [ Statement ...]
end-do

Although the with statement is not a loop it is handled like a single iteration forall loop such that it is possible to use the break statement within the block of instructions. The identifiers ident_i are defined as local symbols to the block.

! in this example LR is an array of records
with r=LR(10) do
 r.x:=10         ! update LR(10).x
 r.y:=20         ! update LR(10).y
end-do

© 2001-2020 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.