Initializing help system before first use

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

The basic types are:

  • 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.

  • mpvar: a decision variable
  • linctr: a linear constraint

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