The declaration block
The role of the declaration block is to give a name, a type, and a structure to the entities that the processing part of the program/model will use. The type of a value defines its domain (for instance integer or real) and its structure, how it is organized, stored (for instance a reference to a single value or an ordered collection in the form of an array). The declaration block is composed of a list of declaration statements enclosed between the instructions declarations and end-declarations.
declarations Declare_stat [ Declare_stat ...] end-declarations |
Several declaration blocks may appear in a single source file but a symbol introduced in a given block cannot be used before that block. Once a name has been assigned to an entity, it cannot be reused for anything else.
Elementary types
Elementary objects are used to build up more complex data structures like sets or arrays. It is, of course, possible to declare an entity as a reference to a value of one of these elementary types. Such a declaration looks as follows:
ident1 [, ident2 ...]: type_name |
where type_name is the type of the objects to create. Each of the identifiers identi is then declared as a reference to a value of the given type. The type name may be either a basic type (integer, real, string, boolean), an MP type (mpvar, linctr), an external type or a user defined type (see section User defined types). MP types are related to Mathematical Programming and allow declaration of decision variables and linear constraints. Note that the linear constraint objects can also be used to store linear expressions. External types are defined by modules (the documentation of each module describes how to use the type(s) it implements).
declarations i,j: integer str: string x,y,z: mpvar end-declarations
Basic types
- integer: an integer value between -2147483648 and 2147483647
- real: a real value between -1.7e+308 and 1.7e+308.
- string: some text.
- boolean: the result of a Boolean (logical) expression. The value of a Boolean entity is either the symbol true or the symbol false.
After its declaration, each entity receives an initial value of 0, an empty string, or false depending on its type.
MP types
Two special types are provided for mathematical programming.
Sets
Sets are used to group an unordered collection of elements of a given type. Set elements are unique: if an element is added several times it is only contained once in the set. Declaring a set consists of defining the type of elements to be collected.
The general form of a set declaration is:
ident1 [, ident2 ...] : set of type_name |
where type_name is one of the elementary types. Each of the identifiers identi is then declared as a set of the given type.
A particular set type is also available that should be preferred to the general form wherever possible because of its better efficiency: the range set is an ordered collection of consecutive integers in a given interval. The declaration of a range set is achieved by:
ident1 [, ident2 ...] : range [set of integer] |
Each of the identifiers identi is then declared as a range set of integers. Every newly created set is empty.
declarations s1: set of string r1: range end-declarations
Lists
Lists are used to group a collection of elements of a given type. An element can be stored several times in a list and order of the elements is specified by construction. Declaring a list consists of defining the type of elements to be collected.
The general form of a list declaration is:
ident1 [, ident2 ...] : list of type_name |
where type_name is one of the elementary types. Each of the identifiers identi is then declared as a list of the given type.
Every newly created list is empty.
declarations l1: list of string l2: list of real end-declarations
Arrays
An array is a collection of labelled objects of a given type. A label is defined by a list of indices taking their values in domains characterized by sets: the indexing sets. An array may be either of fixed size or dynamic. For fixed size arrays, the size (i.e. the total number of objects it contains, or cells) is known when it is declared. All the required cells (one for each object) are created and initialized immediately. Dynamic arrays are created empty. The cells are created explicitly (cf. procedure create) or when they are assigned a value (cf. Section Assignment) and the array may then grow `on demand'. It is also possible to delete some or all cells of a dynamic array using the procedure delcell. A cell that has not been created can be identified using the exists function and its value is the default initial value of the type of the array. The general form of an array declaration is:
ident1 [, ident2 ...] : [dynamic] array(list_of_sets) of type_name |
where list_of_sets is a list of set declarations/expressions separated by commas and type_name is one of the elementary types. Each of the identifiers identi is then declared as an array of the given type and indexed by the given sets. In the list of indexing sets, a set declaration can be anonymous (i.e. rs:set of real can be replaced by set of real if no reference to rs is required) or shortened to the type of the set (i.e. set of real can be replaced by real in that context).
declarations e: set of string t1:array ( e, rs:set of real, range, integer ) of real t2:array ( {"i1","i2"}, 1..3 ) of integer end-declarations
An array is of fixed size if all of its indexing sets are of fixed size (i.e. they are either constant or finalized (cf. procedure finalize)). If the qualifier dynamic is used, the array is dynamic and created empty. Otherwise (at least one indexing set is not constant), the array is created with as many cells as possible (i.e., the array is empty if one of the indexing sets is not initialized) and may grow if necessary. Such an array is not the same as a dynamic array even if it is created empty: Mosel may use a dedicated internal representation through which the creation of a single cell (via an assignment for instance) may induce the creation of a row of adjacent cells. Also, if no cell can be created at declaration time, the array is effectively allocated when it is first accessed. As a consequence, if all its indexing sets are finalized at that time, the array is created as a fixed size array. The following example shows the different behaviour of an array that is simply declared with unknown index set (a and c) and an explicit dynamic array (b).
declarations r,u: range a: array(r) of integer ! a is created empty b: dynamic array(r) of integer ! b is created empty c: array(u,r) of integer ! c is created empty end-declarations r:=1..3 finalize(r) ! now the index set is known and constant a(2):=1 ! 'a' becomes a fixed size array b(2):=1 ! b(2) is the only entry of b c(1,2):=1 ! here entries c(1,1) and c(1,3) are also created
Note that once a set is employed as an indexing set, Mosel makes sure that its size is never reduced in order to guarantee that no entry of any array becomes inaccessible. Such a set is called fixed.
Special case of dynamic arrays of a type not supporting assignment
Certain types do not have assignment operators: for instance, writing x:=1 is a syntax error if x is of type mpvar. If an array of such a type is defined as dynamic or the size of at least one of its indexing sets is unknown at declaration time (i.e. empty set), the corresponding cells are not created. In that case, it is required to create each of the relevant entries of the array by using the procedure create since entries cannot be defined by assignment.
Records
A record is a finite collection of objects of any type. Each component of a record is called a field and is characterized by its name (an identifier) and its type. The general form of a record declaration is:
ident1 [, ident2 ...] : record field1 [, field2 ...]: type_name [...] end-record |
where fieldi are the identifiers of the fields of the record and type_name one of the elementary types. Each of the identifiers identi is then declared as a record including the listed fields.
Example:
declarations r1: record i,j:integer r:real end-record end-declarations
Each record declaration is considered unique by the compiler. In the following example, although r1 and r2 have the same definitions, they are not of the same type (but r3 is of course of the type of r2):
declarations r1: record i,j:integer end-record r2,r3: record i,j:integer end-record end-declarations
Constants
A constant is an identifier for which the value is known at declaration time and that will never be modified. The general form of a constant declaration is:
identifier = Expression |
where identifier is the name of the constant and Expression its initial and only value. The expression must be of one of the basic types, a set or a list of one of these types.
Example:
declarations STR='my const string' I1=12 R=1..10 ! constant range S={2.3,5.6,7.01} ! constant set L=[2,4,6] ! constant list end-declarations
The compiler supports two kinds of constants: a compile time constant is a constant which value can be computed by the compiler. A run time constant will be known only when the model is run.
Example:
parameters P=0 end-parameters declarations I=1/3 ! compile time constant J=P*2 ! run time constant end-declarations
User defined types
Naming new types
A new type may be defined by associating an identifier to a type declaration. The general form of a type definition is:
identifier = Type_def |
where Type_def is a type (elementary, set, list, array or record) to be associated to the symbol identifier. After such a definition, the new type may be used wherever a type name is required.
Example:
declarations entier=integer setint=set of entier i:entier ! <=> i:integer s:setint ! <=> s:set of integer end-declarations
Note that only compile time constant or globally defined sets are allowed as indices to array types:
declarations ar1=array(1..10) of integer ! OK ar2=array(range) of integer ! incorrect R:range ar3=array(R) of integer ! OK end-declarations
Combining types
Thanks to user defined types one can create complex data structures by combining structures offered by the language. For instance an array of sets may be defined as follows:
declarations typset=set of integer a1:array(1..10) of typset end-declarations
In order to simplify the description of complex data structures, the Mosel compiler can generate automatically the intermediate user types. Using this property, the example above can be written as follows (both arrays a1 and a2 are of the same type):
declarations a2:array(1..10) of set of integer end-declarations