MAML -- Multi-Agent Modeling Language
000

[ Initiative ][ Introduction ][ Overview ][ Supported Swarm versions ][ Compiler Download Page ][ Compiler Usage Guide ][ Tutorial ][ Course Outline ][ Examples ][ Reference Manual ][ Papers ][ Comments for Swarmites ][ Technical Manual ] ][ About ]

MAML Reference Manual for (xmc) v0.03.1


[import] [define] [model/observe] [agent/extendAgent] [var/sub]
[plan/schedule] [create] [probe] [uses] [init] [example]


Table of Contents



Introduction

MAML stands for Multi-Agent Modeling Language and it was initiated for agent-based simulation purposes. In its current state it is heavily built upon Swarm functionalities, as its current compiler (xmc) generates  Swarm (v1.02 or v1.3) code which can be compiled again using the appropriate (gcc) compiler. The MAML compiler (xmc) is in version v0.03.1 and only fulfills the requirements of a macro-compiler, as the language itself is only in a pre-testing phase. In what follows, MAML lexical elements, including keywords and high level structures, will be presented. A final complex example and comments on MAML programming will be given. More details are presented in the MAML Technical Manual.

[Back to the Table of Contents]



MAML Lexical Elements and High Level Structures

At the moment the MAML language is composed of the lexical elements implemented in the (xmc) compiler. Thus in what follows everything has to be taken as a description of the compiler and not a description of the language. The accurate and official MAML language definition is going to be released later. In this section the MAML lexical elements and especially the MAML keywords are presented with some syntax and usage specifications.

[Back to the Table of Contents]



PrePro: The `Preprocessor Phase'

The MAML language is made up of two components: the MAML language itself and the PrePro preprocessor language. The latter has its own keywords and, as in many computer languages (e.g., C, Objective-C), is processed in a first step, called the preprocessor step, in which some modifications are made on the source code, which is based on preprocessor directives. This feature provides some macro-facilities, such as defining new words, introducing/removing parts of the source code based on newly defined/undefined words, and including external files.

The PrePro lexical elements are:

    $ , : ;
    import global local
    define undefine
These are to be extended with:
    ifdef ifndef elifdef elifndef else begin end
    error warning fatal
In any PrePro directive the first keyword is preceded by a `$' sign without any space between the `$' sign and the keyword. Within the `sentence' the keywords do not need to be preceded by the `$' sign and any `sentence' has to be closed with a `;' sign. In the present version of the compiler (and the language itself), only a limited set of PrePro keywords are implemented, but these are going to be extended in the near future.

In a MAML source code one can use C and C++ comment notation as any text coming after `//' to the end of line or enclosed between `/*' and `*/' will be eliminated in the preprocessor phase. Very long lines can be broken up into multiple ones by using the `\' sign. If the `\' sign stands at the end of a line, it will be eliminated and the next line will be joined to the current one.

In what follows, a short presentation of the implemented PrePro keywords will come. The most important are: import and define. We will focus on these in the next subsections.

[Back to the Table of Contents]



Importing External Files

Using the `import' keyword, the content of an external file can be introduced in the source code. There is a possibility of importing nested code (which means that the imported file can import new ones), but there is an upper limit on the number of nested files. This limit is set up by the system with a limited number of open files; but in typical cases, this limit is hard to be reached. The `import' mechanism is special because it detects recursive import structures, but the same file can be imported many times. Please note that the PrePro `import' is not an equivalent of C `include' or Objective-C `import' !

A typical example for the usage is: 

    $import "myfirst.maml.stub", "mysecond.maml.stub";
The `global' and `local' keywords are related to the `import' keyword in that they are used to specify the search directory for the given file. They tell the compiler to look up the given file in the local current directory or in the global MAML `include' directory (e.g., /usr/include/MAML). This latter feature has not been implemented yet, and thus the global directory coincides with the local directory. A warning message ("Structure not supported yet") is sent every time a global import is used.

The usage for these is:

    $import local "myfirst.maml.stub", global "mysecond.maml.stub";
If one specified file cannot be imported, an error message will appear. There are multiple cases in which this may occure. If a file tries to import itself directly or indirectly (by means of other imported files), a  "Recursive import structure detected" error is sent.  When a file does not exist, is damaged, or cannot be opened, the "Couldn't open file" and the "Couldn't import file" errors are sent. Due to technical problems, the total number of imported files is limited. This limit is high enough, so that it should be difficult to reach it; but if it is reached, the "Compiler table limit exceeded" error will appear.

[Back to the Table of Contents]



Defining New Words

With the help of the `define' keyword, you can define new words that will be replaced in subsequent code sequences with a given character string. A definition can be removed using the `undefine' keyword. The implemented `define' technique does not fulfill the requirements of macro-definition in general as recursive definitions and macros with arbitrary parameters are not supported. (These features will be provided later.)

A simple definition looks like: 

    $define first_word : "FIRST WORD", second_word : "SECOND WORD", third_word;
The word you are going to define must be a C type identifier. This means that any word can be composed of upper or lower  case letters [A..Za..z], digits [0..9], and the '_' sign. The only limitation is that you cannot begin your word with a digit. After the identifier there may come the `:' sign and a string or a new word definition. A string is composed of any character except a new line and it must be enclosed between `"' signs. You can also use the C type notation of special characters (e.g., \\, \", \', \32, \n, \t, ..). The string may have any length and you can continue your string in the next line by finishing the current one with the `\' sign. (The latter won't be introduced in the string; to introduce a '\' character, you must use the '\\' notation.)

After a definition, any identifier matching the defined word will be replaced with the given string (without the `"' sign) as it would be printed using the C `printf' function. If the string is omitted, the word will be `defined' but won't be replaced in the subsequent text. This feature  was introduced to support `ifndef/ifdef' structures which take as an argument a word which could be either defined or undefined; but the definition itself (the string following the `:' sign), is unimportant. (The `ifndef/ifdef' structures have not been implemented yet, but will be implemented later.)

One can also use an `undefine' directive, which tells the compiler to forget the previously defined word and stop replacing it with some given string. The `undefine' directive can also take as an argument a word which wasn't previously defined, and it may come many times without limitations. A defined word cannot be redefined unless the definition is exactly the same as before, or it comes after an `undefine' (after which any word can take a new definition).

To undefine the `second_word' and the `third_word' one can enter: 

    $undefine second_word, third_word;
After a valid definition, the given word will be replaced with its definition anytime it is found in the code (except in comments). You should notice that there will be a replacement even in MAML strings. It was already mentioned, however, that the word definitions aren't recursive; thus replacements won't be made in `define' strings. This feature differs from the C `define' technique, in which the definitions are recursive and replacements are made only in expressions involving identifiers (but not in strings).

The error messages related to word definitions are: "Illegal redefinition of symbol", "Define string expected", "Invalid define string". The first is issued when a definition is repeated with different `define' string. The second specifies that at the given place a `define' string would be expected. This message typically appears when there is a discordance with the define syntax. The third is issued when there is something wrong with the `define' string (e.g., it contains a line break).

[Back to the Table of Contents]



Other Features

The `ifndef/ifdef' structures are used to introduce or remove a part of the code based on previous definitions. The `error/warning/fatal' structures can issue messages in the preprocessor phase. More about this will be written after their implementation.

[Back to the Table of Contents]



MAML: Keywords and High Level Structures

The MAML language contains a set of keywords and special structures, but there are no special MAML expressions at the moment. These expressions are borrowed from Objective-C (and Swarm) and in the current version of the compiler these are not even tested. The main idea was to set up special high-level structures for organizing the Swarm code more easily. Thus a MAML  code contains special lexical elements called `code' or `Swarm code' which are taken unchanged and introduced in the generated Swarm code. The MAML syntax must be refined by eliminating these untested code parts.  A short description of the MAML keywords and structures will be given below.

The MAML keywords and special signs are: 

    , : ; @ { } ( ) [ ] []
    model observe gui batch as agent extendAgent
    var sub inline private protected public static
    char int short long float double boolean string id void
    planDef addToPlan extendPlan seq con rnd plan to forEach
    schedule addToSchedule extendSchedule cyclic relative in
    create createBegin createEnd probe
    init initModel buildProbes uses
A MAML `sentence' must begin with the `@' sign and must be closed with either a `;' sign or a `{..}' block, whereas between `{' and `}' one may have other MAML `sentences'.

MAML also defines a few reserved variables, whose use will be discussed later. These variables have the following form:

maxTimeSteps
groupOf***
where `***' stands for the name of an agent class defined in the model. (If one has two classes defined A and B, then the corresponding variables are: groupOfA and groupOfB.)

[Back to the Table of Contents]



Creating Model and Observer

The MAML program structure is built up using the `model' and `observe' keywords. The basic idea underlying the keywords is that any simulation has two main parts: a so called `simulation engine' and a `visualization and control interface'. The first has to be implemented in a model and the second in an observe directive. These, usually need very different techniques, and the language controls it by its syntax. In the current version of MAML, each file can contain only one model and an optional observe directive, but in later versions, this will be extended introducing multiple model and observe directives and also sub-models. Each model and observe directive has a name. The observe directive's name is optional. For the observation, one can specify two visualization types: gui and batch. The first uses a graphical user interface with high-level design and visualization tools, whereas the second requires only a simple terminal. The gui mode suggests an interactive simulation; while batch suggests a so called batch mode simulation. The latter usually creates a large amount of data that has to be processed and evaluated later. Each of these are essential and fulfill different requirements. For presentations and fancy demos, you can use the so-called `foreground processing' (provided by the graphical user interface) but for real `measurements' you need fast `background processing' (provided by the batch mode).

A simple MAML program looks like: 

    @model MyModel {}
    @observe MyModel {}
Something more specific can look like:
    @model MyModel {}
    @observe MyModel as MyObserver {}
The latter example creates an `observer' called `MyObserver' of the previously defined model. The visualization mode (by default) is `gui' but one can change this as follows: 
    @model MyModel {}
    @observe MyModel batch as MyObserver {}
The `as' keyword must be followed by the observer's name but this `as-keyword' structure is optional:
    @model MyModel {}
    @observe MyModel batch {}
In the above examples instead of `batch' one can use `gui' for graphical visualization. Because the observer is optional these examples will work without their second line too. The two visualization modes differ in techniques and this is reflected by the MAML syntax as will be discussed later. Any specific `gui' or `batch' observer must use the suitable set of MAML substructures.

The MAML system provides the `model' variable name, which denotes the model defined in the current application. Any internal structure of the model can be accessed using the `model-><V/SN>' construct where `<V/SN>' denotes any variable or subroutine name. (In the model's instance-subroutines one can use `self' instead of `model'.)

In accordance with the MAML syntax the model name must be a C-identifier (as described earlier), otherwise the "Identifier expected" error message will be issued. If the model name is omitted in the `model' or `observe' directive, the "Model name expected" or the "Invalid extension of model" error will be sent. (The same error is sent if one tries to `observe' an undefined model.) If the `as' keyword is not followed by a valid observer name, the "Observer name expected" error is generated.

[Back to the Table of Contents]



Introducing and Extending Agents

The MAML language was initiated especially for multi-agent modeling thus the basic substructure of a model and observer is the agent. An agent can be implemented in MAML using of the `agent' keyword. You can use the `agent' keyword in both the model and the observer, but there will be slight differences between the model and the observer agents, as will be discussed later. The agent word in this context will always denote an `agent class', but later the same word will be used to denote an `instance' of an agent class.

Each agent has a name which has to be specified as follows: 

    @agent MyAgent {}
The above example is the simplest agent you could ever imagine, and by itself does nothing. In what follows, other MAML features are presented and you will be able to construct an internal structure for it and make it work (see next subsections). The agent's internal structure will be given in the `{...}' block.

In some computational aspects agents are `objects', thus MAML is going to be an OOP language but it will try to simplify and reorganize the OOP way of thinking by blurring the objects' boundaries, making them look more like `real agents'. As a typical OOP feature, an agent may inherit another agent as in the following example:

    @agent MySecondAgent : MyFirstAgent {}
The name after the `:' sign is the agent super-class for the given agent. Any agent is derived from a default class which contains many predefined functionalities. (This will be discussed later.)

Any agent can be extended unlimited times with the help of the `extendAgent' keyword. This keyword needs the agent's name to be extended:

    @extendAgent MyAgent {}
The extension of an agent is only a macro facility and not an `inheritance', but it becomes useful when one has to `refine' a model agent's capabilities  in the observer.

For any agent class, an agent list is generated automatically with the name of `groupOf<Agent Name>' where `<Agent Name>' denotes the agent's class name. Using this list any member of the agent class can be referenced in one `group'.

If an agent uses the name of a previously defined agent, the "Multiple declaration for agent" error will be generated. If one tries to extend an agent which wasn't defined, the "Invalid extension of agent" error will be issued. If something is wrong with the agent or agent super-class name, the "Identifier expected", "Agent name expected" or the "Invalid inheritance" errors will be issued.

[Back to the Table of Contents]



Introducing Variables and Subroutines

To define the internal structure of models and agents in computational aspects, you need variables and subroutines. For this MAML provides the `var' and `sub' keywords. There are some modifiers for these: `private', `protected', `public', `static' and `inline'.

The `private', `protected' and `public' keywords specify the protection type (in the OOP meaning) for agent variables and subroutines. Only one of these can be used for any variable or subroutine. The default value (if no protection type is specified) is `public'. This means that any agent (and the model) can access the given variable or subroutine. The `protected' and `private' ones can be accessed only within the agent's class, and the difference between them is that the `private' variables and subroutines cannot be accessed in any sub-class.

In the current version of the compiler, the `protected' and `private' subroutines are only partially supported due to restricted Objective-C capabilities. These modifiers lead to a warning message of the form: "Structure only partially supported".

Objective-C  introduces the so called `+/- subroutines' and the idea of instance, class variables, and methods. This idea finds its MAML equivalent in static variables and subroutines which are the class variables and subroutines. The  default type for these is `non-static'; thus, by default they are instance variables and subroutines. The static subroutines are the equivalent of the Objective-C `+ subroutines' and the non-static subroutines for the `- subroutines'. Like the `protected' and `private' subroutines, the `static' variables are only partially supported. The `static' modifier for variables leads to the already mentioned warning message.

In the current version, MAML and its compiler (xmc)  provides the `inline' modifier which defines any Objective-C variables and subroutines. (This keyword may disappear in later versions.) Without the `inline' modifier only restricted types of variable and subroutine definitions are allowed. These will be changed later to fulfill the requirements of a `real programming language' in a genuine MAML style.

The implemented, basic variable types are: `char', `int', `short', `long', `float', `double', `boolean', `string', `id'. In general these have been borrowed from C and Objective-C. The `string' and `boolean' types are defined as follows:

    typedef enum {false, true} boolean;
    typedef char string[256];
To denote the logical values of boolean variables, you can use the `false' and `true' names. (Objective-C uses the `BOOL' variable type and the `YES' and `NO' logical values. The usage of these is discouraged in MAML.)

A simple integer variable definition looks like: 

    @var: int x1, x2;
where x1, x2 are the defined variables of types `int'. Instead of `int', any other basic variable type could be used. To define agent instances, you may use the same syntax by using the `id' variable type or the
agent's name as the variable type. (One may use Swarm predefined types but in this case the latter is highly discouraged.) For defining arrays of variables or agents you can use the so-called `box' operator `[]' which `degenerates' the defined variable. (Technically it creates a pointer to a well defined variable type.) This means that the given variable must be created before usage (see the `create phase' later), and a specific value (stored in the `degenerated' variable) can be accessed by indexing. For defining arrays of arrays one may use multiple level of `degeneracy'.

Simple arrays of variables of type `int' can be defined as:

    @var: [] int x1, x2;
In code context (after the `creation phase'), you can access a particular value of the defined arrays with x1[i1] and x2[i2] where i1 and i2 are valid indexes (see later). For creating a more `degenerated' structure of array of arrays one can use the following:
    @var: [][] int y1, y2;
Any value stored in y1 and y2 can be accessed by y1[i1][j1] and y2[i2][j2]. The y1[i1] and y1[i2] will denote arrays of `int', and are equivalent with x1 and x2 from the previous example.

Using the `inline' modifier you can enter any C-like definition:

    @var inline: int (*f[10])(char *);
    @var inline: MyAgent * a;
    @var inline: id <List> l;
Without `inline' if extra variable definition is entered, the "Illegal variable type" error will appear.

If you use `inline' in variable declaration, any agent variable must be preceded by the `*' sign. (We will return to these with more details in the MAML Technical Manual.) As in the above example the modifiers may come between the var keyword and the `:' sign. No specific order is defined for the modifiers. For example:

    @var static protected: int x;
is equivalent to:
    @var protected static: int x;
If a modifier is used more than once or more than one `protected', `private', or `public' modifiers is used, an error message appears (usually "Syntax error").

Subroutines are defined in a very similar way to Objective-C methods. A subroutine headline looks like:
 

    (<RT>) <BN> : (<PT1>) <P1> <NE1> : (<PT2>) <P2> <NE2> : (<PT3>) <P3>
Where <RT> stands for <Return Type>, <BN> for <Base Name>, <PT> for <Parameter Type>, <P> for <Parameter>, and <NE> for <Name Extension>. The line may be continued without limitation in the given style. The name of such a subroutine will be: `<BN>:<NE1>:<NE2>:'. The name extensions may be empty which leads to: `<BN>:::'. (The subroutine names will be used in the `probing mechanism' that will be presented later.)  For <Return Type> and <Parameter Type> you can use the already presented variable types and the special `void' type, which is used only for <Return Type>, and denotes that the subroutine does not return any value.

Unlike Objective-C, the return and parameter types are obligatory. If they are omitted the following error messages are generated: "Subroutine return type expected", and "Subroutine parameter type expected". For return and parameter types, you can use the same constructs as for variable definition (e.g., [] int, [][] char). If the parameter types are incorrect, the following error messages will be generated: "Illegal subroutine return type", and "Illegal subroutine parameter type".

Some simple examples for these are:

    @sub: (void) skip {}
    @sub: (int) print: (string) {}
    @sub: (int) setFor: (int) i Name: (string) {}
    @sub: (int) setNameFor: (int) i: (string) {}
Using the `inline' modifier you can follow exactly the same syntax as in Objective-C. For example:
    @sub inline: setFor: i Name: (char *) t {}
Like the `var' keyword, the modifiers must go between the `sub' keyword and the `:' sign.
    @sub static protected: (void) skip {}
In the above examples, the subroutine body may appear in the `{...}' block although it was left out now. The question of what can appear between the `{' and `}' sign will be discussed later. Generally the subroutine body may contain any untested Objective-C statement and some special MAML constructs. In the `inline' case anything in the subroutine body will be treated as Objective-C statement and won't be tested. In later versions of the compiler (and the language itself), these untested statements will be replaced by tested MAML statements. The special MAML constructs, which can be used in a subroutine body, will be presented in the following subsections.

The names of the variables and subroutines must be unique in an agent or in the model. Different agents may use the same names, and the model and an agent can both have a variable or subroutine with the same name, but you cannot have a variable or a subroutine with the same name in the model or an agent. Variable and subroutine names are C-type identifiers (of the form discussed earlier). The names cannot be either keywords or reserved variables of Swarm, Objective-C, or C. (For reserved words, please contact your language manual.) MAML also provides reserved names (as was already mentioned); but you can use keywords as subroutine names, but you cannot use keywords for variable names.

[Back to the Table of Contents]



Planning and Scheduling

In agent-based modeling, planning and scheduling concepts are used to build sophisticated program structures. MAML provides the `planDef' and `schedule' keywords for these structures. Defined plans and schedules can be extended statically and dynamically with the help of `extendPlan', `extendSchedule' and the `addToPlan', and `addToSchedule' constructs. The static extension of plans and schedules are the same kind of macro-extensions as the extension of agents. The dynamic extension means that the plans and schedules can be extended run-time by `calling' the `addToPlan' and `addToSchedule' constructs in subroutines and initialization routines (as will be discussed later).

To define a plan, you must use the `planDef' keyword. Each plan has a name and an execution order. The latter can be of three different types: sequential, concurrent, and randomized. The `seq', `con' and `rnd' keywords are used to denote these types. The sequential type instructs the computer to execute the actions in the given plan sequentially in the specified order. For concurrent and randomized types, parallel and respectively randomized execution order will be used. The default value for the execution order (if nothing is specified) is sequential (i.e., seq). The current version of the (xmc) compiler cannot generate code for `concurrent' and `randomized' order, because there is no implementation for them in Swarm; thus it generates a warning message (Structure not supported yet) and any plan is created in `sequential' order.

An empty plan is defined as follows:

     @planDef myPlan {}
This plan, by default, will be sequential. To make `myPlan' randomized you can use:
    @planDef myPlan rnd {}
You can define a concurrent plan by using the `con' keyword instead of `rnd' in the above example.

You can insert actions in a plan by using the `plan', `to', `forEach', and `planDef' keywords. The `plan' keyword subscribes the execution of a plan that was defined elsewhere. The `to' and `forEach' keywords plan the execution of model and agent subroutines. The `to' keyword refers to the model or only one agent, while the `forEach' keyword refers to a list of agents. (A special agent list is created automatically for any agent class as was described earlier. But you can create any other agent list using Swarm tools.) The `planDef' keyword defines a new sub-plan which is automatically introduced in the current one. The `plan' keyword needs the name of a plan as an argument. The `to' and `forEach' keywords need an agent name, and an agent list name, and a valid subroutine name. The inner `planDef' keyword needs an optional plan name. If no name is specified, a name will be created automatically by the compiler, but this remains hidden and cannot be referenced anywhere else. The outer `planDef' always requires a name, because it has to be referenced in a schedule (see following text). Aside from the mentioned name problem, the inner `planDef' follows the same rules as the outer one, and  thus a recursive plan definition can be created. There is no limitation for the recursive plan's depth.

A simple example for this looks like:

    @planDef myPlan {
        @to myFirstAgent doSomething;
        @forEach myAgentList doSomethingElse;
        @plan myPreviousPlan;
        @planDef rnd {}
    }
In the above example, the `myFirstAgent' is an agent variable (not agent class name) and `myAgentList' is an agent list variable. The `doSomething' and `doSomethingElse' names are subroutines names. The `myPreviousPlan' is an already defined plan name. Any plan can reference only the plans defined earlier. The inner plan (with a generated name in the above example) will be a randomized plan.

A schedule differs from a plan in that for each action there is a time specification. For example:

    @schedule  mySchedule {
        1: @to myFirstAgent doSomething;
        3: @forEach myAgentList doSomethingElse;
        4: @plan myPreviousPlan;
        6: @planDef rnd {}
    }
The schedule name is optional, and  thus the above example works even without the `mySchedule' name specification. In the case of no name specification -- as for plans -- the compiler generates a name which later cannot be referenced in MAML code. A schedule, by default, is non-relative, non-cyclic and is activated in the global Swarm context, but it can be set relative or cyclic  and can be activated in another schedule too. This latter feature is not supported yet. For the moment, any schedule will be activated in global Swarm context. In the case of a specified activation, a warning message will be sent. In a relative schedule, the timesteps will progress relative to the schedule in which it was was activated. The cyclic schedule needs a time period, enclosed between `(' and `)', for one execution loop which will be repeated ad infinitum. Any cyclic schedule is relative by default, and we do not denote this in any special way. To create a relative or cyclic schedule, you may use the `relative' or  `cyclic' keywords, and for activating a schedule in another schedule by also using the `in' keyword.

An empty relative schedule and an empty cyclic schedule with a time period of 10 arbitrary units looks like:

    @schedule relative {}
    @schedule cyclic (10) {
        0: @to myFirstAgent doSomething;
        5: @forEach myAgentList doSomethingElse;
        9: @plan myPreviousPlan;
    }
In the case of a cyclic schedule the referenced time steps must be within [0..time_period-1] interval. (In the above example this is the [0..9] interval.) The mentioned rule is not tested in compilation time, and it can generate a run-time error.

A schedule may reference any plan in a MAML code even if this is defined later but can reference only the schedules defined earlier.

To extend a plan or a schedule, MAML provides the `extendPlan' and `extendSchedule' keywords. These keywords take as an argument the plan or schedule's name, which then has to be extended.
 

    @extendPlan myFirstPlan {}
    @extendSchedule myFirstSchedule {}
Inside the `{...}' block, anything works in exactly the same way as described above for the `planDef' and `schedule' keywords.

For dynamic extension of plans and schedules, you can use the `addToPlan' and `addToSchedule' keywords. These keywords -- as for static extension -- take a plan and a schedule name. 

    @addToPlan myFirstPlan {}
    @addToSchedule myFirstSchedule {}
Inside the `{...}' block, you can use the same syntax as for `planDef' and `schedule' except that, the inner `planDef' (i.e., a new plan definition) cannot be used. The `addToPlan' and `addToSchedule' constructs can be `called' in subroutines and model/observer initialization routines.

[Back to the Table of Contents]



The `Create Phase'

Any `degenerated' variable (declared with the means of a pointer) or agent instance has to be created before any reference is made on the stored information. For the so-called `creation phase', MAML provides the `create', `createBegin' and `createEnd' keywords. The `create' constructs can be used in subroutines and model/observer initialization routines.

To create an array of 10 integers and store the information in the x degenerated variable you can type: 

    @create [10] int x;
This assumes that x was defined (with any kind of modifiers) as:
    @var: [] int x;
You can set the initial values for the created integers in the following way:
    @create [10:i] int x { x[i]=0; }
This construct sets any of the integers to 0. In the `{..}' block any initialization code can appear which is considered a valid Objective-C (or Swarm) code and which has not been tested. (In the current version of the compiler, this kind of initialization code cannot contain any specific MAML construct.) In the above example, the initialization code will be executed 10 times while i takes values from the [0..9] interval and x[i] denotes one of the 10 integers, as MAML uses a C-like indexing starting from 0. The declared identifier i is valid only in the initialization code (i.e., it cannot be used outside the `{}' block) and can be either changed to any other identifier, or can be omitted. In the latter case the _i1_ identifier can be used as a default in the initialization code:
    @create [10] int x { x[_i1_]=0; }
To create an array of 10 arrays of 5 integers (i.e., 50 integers in total) and set their value to 0, do the following: 
    @create [10:i][5:j] int x { x[i][j]=0; }
If its decalration is omitted, you can use _i2_  instead of  j in the initialization code. The general rule for this is:    `_i<level of degeneracy>_'.

The syntax for the creation of agent variables is largely the same as presented above. To create a GoodGuy agent (defined previously with the agent keyword) you can use the following: 

    @create GoodGuy whoMomLikes { [whoMomLikes setName: "Joe"]; }
The creation phase can be split in three parts with `createBegin', `createEnd', and the initialization code located between them:
    @createBegin GoodGuy whoMomLikes;
    [whoMomLikes setName: "Joe"];
    @createEnd GoodGuy whoMomLikes;
Combining the above examples one can create a set of 10 GoodGuys:
    @create [10] GoodGuy whoMomLikes;
This latter example assumes a variable declaration of the form:
    @var: [] GoodGuy whoMomLikes;
You can also create multiple variables of the same type in one declaration. For example:
    @create [10] int x, y;
    @create [10] GoodGuy allMyFriends, otherPeople;
This rule works with `createBegin' and `createEnd', too.

The values in a created array can be accessed by indexing, but you must be careful with this because the current version of the compiler performs no check on the index range, and thus wrong indexing can generate run-time error.

MAML also provides the `create', `createEnd', and `createBegin' predefined subroutines for model and agents. These are inherited methods, and thus they can be changed (in OOP meaning). You can call these subroutines directly or use the create constructs, as presented above, which add more functionality. (The details for this can be found in the MAML Technical Manual.)

If the creation of a variable of a `non-degenerated' standard type (e.g. int, char, id, ..) is forced, the "Cannot create non-degenerated standard type" error will be issued. Aside from this problem, the same error messages are sent in the `create phase' as in the variable declaration that we disussed earlier.

[Back to the Table of Contents]



Probing Variables

For visualization and run-time setting of parameters, you can use the `probe' keyword in the observer of the model. You have notice that the `probe' keyword can be used only in the observer as the observer's duty is to visualize and set the model and agent parameters. If it is used in the model, an error will be generated ("Structure not supported here"). In the current state of the compiler (and the language), the `probe' keyword can be used only in `gui' (graphical user interface) mode but later versions will provide probing facilities for the `batch' mode, too. This means that in the current version, a warning message is issued for any `probe' defined in a batch observer  ("Structure not supported yet"). The `probe' keyword defines variable and subroutine names which must be probed. The probe definition must be completed by `calling' the `buildProbe' construct in the model/observer initialization routine (presented in the next subsection). The Swarm GUI system provides a graphical window environment for probes which can be called for the model or agents with the predefined `probe' subroutine.

One can use `probe' for either variables or subroutines in the following way:

    @probe: var "x1", sub "skip", var "x2", sub "setFor:Name:";
As in the above example, to specify whether a variable or a subroutine should probed, you have to use the `var' and the `sub' keywords. The order for the probed variables and subroutines is arbitrary, but this will set up the order in the Swarm probing window. The probing windows for the `model' and for the `myAgent' agent (after the `buildProbe' phase) can be `called' (in any subroutine or initialization routine) as in:
    [model probe];
    [myAgent probe];
The idea behind the `probe' definition phase and `buildProbe' were that before building the probing windows  in the second phase (and `calling' them in the third phase), you should build and initialize the variables which were selected as parameters in the first phase. The predefined `probe' subroutine is inherited and can be changed in the MAML code (e.g., by inserting more functionality).

[Back to the Table of Contents]



Using C, Objective-C, Swarm and Other Library Functions

MAML provides the `uses' keyword for accessing any external C, Objective-C or Swarm code by including the corresponding header files. The `uses' keyword takes as parameters file names (as C include) enclosed between either `<>' or `""' signs. In a `uses' directive, multiple files can be `used'. An example for this looks like:
    @uses <stdio.h>, "myCRoutines.h";
The `uses' keyword can be used in a model, observer, and any agent, but a file `used' in the model and/or observer will be automatically used in all model and observer agents. The difference between `<>' and `""' type file name notation is that in the first case the (Swarm) compiler looks for the specified file in some standard `include' directories, whereas in the second case it contacts only the current directory. (If the specified file is not found, an error message will be issued in the second compilation step, by the Swarm compiler.)

The "String or bracketed string expected" error will be generated if something is wrong with file names specified in a `uses' directive. In the current version of the compiler, the files denoted by the specified names are not tested. (Any potential error will be detected only in a Swarm compilation phase.)

[Back to the Table of Contents]



The `Initialization Phase'

Any simulation has a first step called the `initialization phase', in which the user must set the parameters of the model and agents, and build the data structures. This can contain the same type of code as any subroutine (e.g., create, createBegin, createEnd) and in addition there are other useful constructs. Both the model and the observer have an initialization routine. The model's initialization routine has to be called in the observer's initialization routine with the help of the `initModel' keyword. To create the probe windows the `buildProbes' construct has to be called in the observer's initialization routine, as described in the previous subsection. The initialization routines are optional.

To create an initialization routine you can use the example below:

    @model MyModel {
        @var: int x;
    @init:
        x=1;
    }

    @observe MyModel {
        @probe: var "x";
    @init:
       @initModel;
       @buildProbes;
       [model probe];
    }
     
     

This is the first complex example. A more detailed one will come in the next subsection.

MAML provides the `maxTimeSteps' variable to set the maximal timesteps of the model. This variable may be set in the initialization phase. By default its value is `-1' which means that there is no upper limit for executing timesteps. MAML also provides the `stop' predefined model subroutine, which (if it is called in either a subroutine or initialization routine) will hang up the simulation.

[Back to the Table of Contents]



Final Complex Example

In the previous subsections MAML keywords and special constructs were presented with some usage specification. Below is a complex example using the presented keywords:
    @model MyModel {
        @uses <stdio.h>, <stdlib.h>;

        @var: int x;
        @sub: (id) incX { x+=1; return self; }

        @agent MyAgent {
             @uses <stdio.h>;

             @var: int y;
             @sub: (id) incY { y+=1; return self; }
         }

        @var: MyAgent a1, a2;

        @planDef myPlan {
             @to a1 incY;
             @to a2 incY;
         }

        @schedule mySchedule cyclic (3) {
             0: @to model incX;
             1: @plan myPlan;
        }

    @init:
         model->x=0;
        @create MyAgent a1, a2 { a1->y=0; a2->y=0; }
    }

    @observe MyModel {
         @sub: (void) printX { printf("x: %d\n",x); }

         @extendAgent MyAgent {
              @sub: (void) printY { printf("y: %d\n",y); }

              @probe: var "y", sub "incY";
         }

         @extendPlan myPlan {
              @to a1 printY;
              @to a2 printY;
         }

        @extendSchedule mySchedule {
              2: @to model printX;
        }

        @probe: var "x", sub "incX";

    @init:
        @initModel;
        @buildProbes;
        [model probe];
        [a1 probe]; [a2 probe];
    }
     

The above example represents a general framework for creating MAML applications, but it lacks any functionality. It was created only as a demonstration. (For more detailed examples please consult the MAML Tutorial.)

[Back to the Table of Contents]



General Lexical Elements and Other Standard Names

In general MAML adopts the C-like lexical elements as they are related to identifiers, strings, and comments. Anywhere a name (e.g., define names, model, agent, plan, or schedule names) would be expected, a C-like identifier will be used. The length of identifiers is limited to 256 characters, which is much more, than you will ever use. Strings, in general, are enclosed between `"' and can contain any characters except a new line. In define strings (as was already mentioned) you can use the C notation for certain special characters (e.g., new line: `\n') and there is no length limitation. The comment notation is the same as for the C language. The current version of the compiler does not use lexical elements as number or character constants, but these will be introduced as genuine MAML expressions are defined.

In addition to the MAML keywords, C, Objective-C, and Swarm define keywords and standard names which can be used in MAML code. To avoid name conflicts, you must take this in consideration when creating your own (model, agent, variable, subroutine, plan, schedule, .. etc.) names. For these, please refer to the appropriate reference manuals.

[Back to the Table of Contents]
[Back to the Top of Page]


[import] [define] [model/observe] [agent/extendAgent] [var/sub]
[plan/schedule] [create] [probe] [uses] [init] [example]
copyright © 1999 agent-lab
Send comments to maml@maml.hu