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 Technical Manual


[model/observer] [agent] [var/sub] [plan/schedule] [extendPlan/extendSchedule] [create/createBegin/createEnd] [probe/buildProbes] [init] [uses]

Table of Contents


Programming in MAML

Regarding many programming techniques, MAML is close to Swarm, Objective-C, and C. For the moment any MAML code can contain Objective-C and Swarm sequences. In its current state, starting with a given MAML code, the (xmc) compiler generates Swarm code (v1.02 or v1.3) which, in order to build up an executable file, can be compiled again using appropriate compilers (e.g. gcc). The code generation process, programming techniques, and underlying Swarm structures will be presented in the following text. The next section may require the knowledge of MAML keywords and syntax, and some Swarm programming skills.

In its code generation process the MAML compiler generates a couple of Objective-C classes, methods, and variables. Many of these, which are generated with the `_MAML_' prefix, are for internal use only. There is no double-checking performed by the compiler, thus the names used in MAML code may conflict with internal names in Swarm code. To avoid this please do not use variable names and subroutines in your MAML code beginning with `_MAML_'. The internal structure of the generated Swarm code (the names with `_MAML_' prefix) won't be detailed here, as we will focus on structures generated by the compiler without the `_MAML_' prefix, which are accessible in MAML too.

The compiler in its current state supports two type of code generation. It can generate code for either Swarm v1.02 or v1.3. The difference between the two code generation alghoritms is not significant. All the examples without any specification are valid for both fo them.

[Back to the Table of Contents]


Model and Observer

From a MAML model and the appropriate observer, a single Objective-C class is generated which inherits from `GUISwarm' or `Swarm' (predefined Swarm classes), as the observer was a `gui' or a `batch' observer. By default, the `model class' has a `model' instance variable. This can be used in MAML code to access the model variables and subroutines. At Swarm level there is the maxTimeSteps integer variable which is used to specify at what time the model stops the execution of its `life cycle'. There are also two predefined schedules: stopSchedule and dispSchedule. The latter won't be generated in batch mode. The stopSchedule and the dispSchedule is used by the system to `schedule' both its execution loop and the actions taken by the graphical user interface. The MAML compiler generates the probe, stop, and go subroutines. By calling the probe subroutine, the probe windows will be brought up, whereas the stop subroutine stops the model's execution, and the go subroutine starts it again. These subroutines cannot be changed in MAML code, as they are not inherited subroutines.

The above mentioned variables are defined on Swarm level as:

    @public int maxTimeSteps;
    @protected id stopSchedule, dispSchedule;
and the subroutines as:
    - (id) go ;
    - (id) stop ;
    - (void) probe ;
The model structures on Swarm level are created in files which take the name of the MAML model with the `.m' and `.h' extensions. For example if the model was called `MyModel', a `MyModel.h' and a `MyModel.m' file will be generated.

[Back to the Table of Contents]


Agents

For MAML agents two Objective-C classes are generated. The first, taking the agent's name with a `MAML_' prefix (e.g. MAML_Agent), is a low-level object which incorporates some predefined functionalities. The second, taking the agents name (e.g. Agent), implements the MAML agent internal structures and inherits the first one. The `MAML_Agent' inherits the agent super class specified in the MAML code. If no agent super class was specified the `MAML_Agent' inherits the `SwarmObject' predefined Swarm class.

The `MAML_Agent' class adds the following subroutines to its super class:

    + (id) createBegin: (id) zone;
    + (id) createBegin;
    + (id) create;
This and many other inherited subroutines (see Swarm Reference Manual) can be accessed or even changed in MAML code, too.

The `Agent' class adds:

    - (void) probe ;
This subroutine brings up the probe windows.

The agent structures are created in files taking the agent's name, and the agent's name with the `MAML_' prefix and appropriate `.m' and `.h' extensions. For example, if in MAML code an agent was defined with `MyAgent' name, `MAML_MyAgent.h', `MAML_MyAgent.m', `MyAgent.h' and `MyAgent.m' files are generated.

[Back to the Table of Contents]


Variables and Subroutines

The inline MAML variables and subroutines are copied in the Swarm code as they are. The complex variables (i.e., variables defined with the box operator or agent variables) will be preceded by `*' signs in their Swarm level declaration which in C means that they become pointers to structures defined by the corresponding variable types. Each box operator preceding the MAML type will be changed to a `*' preceding each variable name in the declaration list. In the case of agent variables, a supplementary `*' is introduced. The non-static variables are declared as instance variables in the corresponding model or agent class, while the static ones are declared as global variables. The public static variables are also exported to other files (i.e., a C `extern' directive is introduced in the appropriate `.h' file). The MAML subroutine headlines will change as the return and parameter types are changed, as described above for variable declaration. The subroutine bodies will be changed as the MAML constructs are `introduced'. How the MAML constructs are `introduced' will be presented in the next subsections.

[Back to the Table of Contents]


Plans and Schedules

The plans and schedules are generated in the model and agent `buildActions' methods defined as:
    - (void) _MAML_buildActions_
and respectively
    + (void) _MAML_buildActions_: (id) zone
An empty plan from its MAML form:
    @planDef planA {}
is generated in Swarm v1.02 as:
     {
        planA = [ActionGroup createBegin: _MAML_zone_];
        [planA setDefaultOrder: Sequential];
        planA = [planA createEnd];
    }
In Swarm v1.3 code generation the line containing the 'setDefaultOrder' is not generated. This is true for any of the following examples.

By default any plan is sequential (see: seq MAML keyword) but it can also be set to randomized (see: rnd) or concurrent (see: con). In MAML this looks like:

    @planDef planA rnd {}
    @planDef planB con {}
which is compiled as:
    {
        planA = [ActionGroup createBegin: _MAML_zone_];
        [planA setDefaultOrder: Randomized];
        planA = [planA createEnd];
    }

    {
        planB = [ActionGroup createBegin: _MAML_zone_];
        [planB setDefaultOrder: Concurrent];
        planB = [planB createEnd];
    }

The plan in the following simple example:
    @planDef planA {
        @to agent mehod;
        @forEach agentList method;
        @plan planB;
    }
will be translated as:
    {
        planA = [ActionGroup createBegin: _MAML_zone_];
        [planA setDefaultOrder: Sequential];
        planA = [planA createEnd];

        [planA createActionTo: agent message: M(mehod)];
        [planA createActionForEach: agentList message: M(method)];
        [planA createAction: planB];
    }

A subplan:
    @planDef planA {
        @planDef planB {}
    }
has its Swarm equivalent in:
    {
        planB = [ActionGroup createBegin: _MAML_zone_];
        [planB setDefaultOrder: Sequential];
        planB = [planB createEnd];
    }

    {
        planA = [ActionGroup createBegin: _MAML_zone_];
        [planA setDefaultOrder: Sequential];
        planA = [planA createEnd];

        [planA createAction: planB];
    }

The empty schedule:
    @schedule scheduleA {}
in Swarm looks like:
    {
        scheduleA = [Schedule createBegin: _MAML_zone_];
        scheduleA = [scheduleA createEnd];
    }
A relative schedule:
    @schedule acheduleA relative {}
in Swarm will be:
    {
        acheduleA = [Schedule createBegin: _MAML_zone_];
        [acheduleA setRelativeTime: YES];
        acheduleA = [acheduleA createEnd];
    }
A cyclic schedule:
    @schedule acheduleA cyclic (10) {}
in Swarm:
    {
        acheduleA = [Schedule createBegin: _MAML_zone_];
        [acheduleA setRepeatInterval: (10)];
        acheduleA = [acheduleA createEnd];
    }
A more complex example:
    @schedule scheduleA {
        0: @to agent method;
        1: @forEach agentList method;
        2: @plan planA;
        3: @planDef planB {}
      }
in Swarm has the form of:
    {
        planB = [ActionGroup createBegin: _MAML_zone_];
        [planB setDefaultOrder: Sequential];
        planB = [planB createEnd];
    }

    {
        scheduleA = [Schedule createBegin: _MAML_zone_];
        scheduleA = [scheduleA createEnd];

        [scheduleA at: (0) createActionTo: agent message: M(method)];
        [scheduleA at: (1) createActionForEach: agentList message: M(method)];
        [scheduleA at: (2) createAction: planA];
        [scheduleA at: (3) createAction: planB];
    }

The schedules (any model and agent schedule) are activated in the model's `activateIn' method defined as:
    - (id) _MAML_activateIn_: (id) swarmContex
For a schedule with name `scheduleA', the following line will appear in the `activateIn' method:
      [scheduleA activateIn: self];
The extendPlan/addToPlan and extendSchedule/addToSchedule structures on Swarm level are generated in a way as the above presented planDef and schedule structures. The only difference is that the `create part' is not generated.

This example:

    @extendPlan planA {
        @to agent method;
        @forEach agentList method;
        @plan planB;
     }
is compiled as:
    {
        [planA createActionTo: agent message: M(method)];
        [planA createActionForEach: agentList message: M(method)];
        [planA createAction: planB];
    }
For an addToPlan the same code is generated, but is introduced in the model's buildObjects subroutine defined as:
    - (void) _MAML_initModel_
or it is introduced in the corresponding model or agent subroutine in which it was `called' in the MAML code. If the extendPlan contains a new plan definition:
    @extendPlan planA {
        @planDef planC {}
    }
the generated code looks like:
    {
        planC = [ActionGroup createBegin: _MAML_zone_];
        [planC setDefaultOrder: Sequential];
        planC = [planC createEnd];
    }

    {
         [planA createAction: planC];
    }

In an addToPlan structure a planDef is prohibited. This is controlled by the compiler, and thus there is no code generation problem for this.

An extendSchedule structure:

    @extendSchedule schA {
        1: @to agent method;
        3: @forEach agentList method;
        2: @plan planB;
    }
is compiled as:
    {
        [schA at: (1) createActionTo: agent message: M(method)];
        [schA at: (3) createActionForEach: agentList message: M(method)];
        [schA at: (2) createAction: planB];
    }
An addToSchedule is compiled exactly the same way except that it will be generated in the internal buildObjects subroutine or in the appropriate subroutine defined in the MAML code.

If there is a new plan definition inside an extendSchedule:

    @schedule schA {}
    @extendSchedule schA {
        4: @planDef planC {}
    }
the compiled code will be:
    {
        planC = [ActionGroup createBegin: _MAML_zone_];
        [planC setDefaultOrder: Sequential];
        planC = [planC createEnd];
    }

    {
        schA = [Schedule createBegin: _MAML_zone_];
        schA = [schA createEnd];
    }

    {
        [schA at: (4) createAction: planC];
    }

As it can be seen from the above examples, the plans are always generated first, then followed by the schedules. The plans and schedules are generated in the order in which they were defined.

In the above examples the `_MAML_zone_' variable is set in the following form:

     _MAML_zone_=[self getZone];
This means that any plan or schedule is created in the same zone in which the model or the agents are created.

[Back to the Table of Contents]


Create Structures

The create structures are generated in subroutines or initialization codes. A simple MAML `create' directive which creates an array of characters, such as:
    @create [10:i] char n { n[i]=' '; }
is generated in Swarm in the form of:
    {
        int _MAML_i1_;

        {
          n=(char*)malloc((10)*sizeof(char));
        }

        for(_MAML_i1_=0;_MAML_i1_<(10);_MAML_i1_++)
        {
          int i;
          i=_MAML_i1_;

        {
            n[i]=' ';
        }

        }
    }

The creation of an agent:
    @create Guy badguy { [badguy setName : "Joe"]; }
in Swarm looks like:
    {

        {
          badguy=[Guy createBegin: _MAML_zone_];
        }

        {

        {
            [badguy setName : "Joe"];
        }

        }

        {
          badguy=[badguy createEnd];
        }

    }

From the MAML line which `creates' an array of arrays of arrays for n and m CHAR agent variables and call the appropriate `set' subroutine, such as:
    @create [10:i][20:j][30:k] CHAR n, m { [n[i][j][k] set: ' ']; }
the following lines are generated:
    {
        int _MAML_i1_, _MAML_i2_, _MAML_i3_;

        {
          n=(CHAR****)malloc((10)*sizeof(CHAR***));
          m=(CHAR****)malloc((10)*sizeof(CHAR***));
        }

        for(_MAML_i1_=0;_MAML_i1_<(10);_MAML_i1_++)
        {
          n[_MAML_i1_]=(CHAR***)malloc((20)*sizeof(CHAR**));
          m[_MAML_i1_]=(CHAR***)malloc((20)*sizeof(CHAR**));
        }

        for(_MAML_i1_=0;_MAML_i1_<(10);_MAML_i1_++)
        for(_MAML_i2_=0;_MAML_i2_<(20);_MAML_i2_++)
        {
          n[_MAML_i1_][_MAML_i2_]=(CHAR**)malloc((30)*sizeof(CHAR*));
          m[_MAML_i1_][_MAML_i2_]=(CHAR**)malloc((30)*sizeof(CHAR*));
        }

        for(_MAML_i1_=0;_MAML_i1_<(10);_MAML_i1_++)
        for(_MAML_i2_=0;_MAML_i2_<(20);_MAML_i2_++)
        for(_MAML_i3_=0;_MAML_i3_<(30);_MAML_i3_++)
        {
          n[_MAML_i1_][_MAML_i2_][_MAML_i3_]=
               [CHAR createBegin: _MAML_zone_];
          m[_MAML_i1_][_MAML_i2_][_MAML_i3_]=
               [CHAR createBegin: _MAML_zone_];
        }

        for(_MAML_i1_=0;_MAML_i1_<(10);_MAML_i1_++)
        for(_MAML_i2_=0;_MAML_i2_<(20);_MAML_i2_++)
        for(_MAML_i3_=0;_MAML_i3_<(30);_MAML_i3_++)
        {
          int i, j, k;
          i=_MAML_i1_; j=_MAML_i2_; k=_MAML_i3_;

            {
              [n[i][j][k] set: ' '];
            }

        }

        for(_MAML_i1_=0;_MAML_i1_<(10);_MAML_i1_++)
        for(_MAML_i2_=0;_MAML_i2_<(20);_MAML_i2_++)
        for(_MAML_i3_=0;_MAML_i3_<(30);_MAML_i3_++)
        {
          n[_MAML_i1_][_MAML_i2_][_MAML_i3_]=
               [n[_MAML_i1_][_MAML_i2_][_MAML_i3_] createEnd];
          m[_MAML_i1_][_MAML_i2_][_MAML_i3_]=
               [m[_MAML_i1_][_MAML_i2_][_MAML_i3_] createEnd];
        }

    }

This example shows how much easier it is to implement the creation phase in MAML.

The create directives can be split in createBegin/createEnd parts. The following lines:

    @createBegin [3] Guy goodguy;
    @createBegin Guy myfriend;
    @createEnd Guy myfriend;
    @createEnd [3] Guy goodguy;
 are translated as:
    {
        int _MAML_i1_;

        {
          goodguy=(Guy**)malloc((3)*sizeof(Guy*));
        }

        for(_MAML_i1_=0;_MAML_i1_<(3);_MAML_i1_++)
        {
          goodguy[_MAML_i1_]=[Guy createBegin: _MAML_zone_];
        }

    }

    {

        {
          myfriend=[Guy createBegin: _MAML_zone_];
        }

    }

    {

        {
          myfriend=[myfriend createEnd];
        }

    }

    {
        int _MAML_i1_;

        for(_MAML_i1_=0;_MAML_i1_<(3);_MAML_i1_++)
        {
          goodguy[_MAML_i1_]=[goodguy[_MAML_i1_] createEnd];
        }

    }
     

There is no specific checking performed on the order in which one `calls' the createBegin/createEnd structures but, there is an `unwritten' rule of beginning with a createBegin and ending with a createEnd for any create directive.

The `_MAML_zone_' variable in any subroutine and initialization routine will take the appropriate value. In `+' Swarm subroutines it will take the globalZone value (see Swarm Reference Manual) and in `-' Swarm routines it will take the zone value, in which the model or agent itself was created, by calling [self getZone].

[Back to the Table of Contents]


Probes

From a line in a MAML observer which extends agent `A' and defines probes for agent `A' and the model `M':
      @extendAgent A { @probe: var "i", sub "look"; }
      @probe: var "x", sub "skip";
the following model `M' method is generated in Swarm:
    - (void) _MAML_buildProbeMap_ {
      id _MAML_zone_; _MAML_zone_=[self getZone];
      {
        [(MAML_ProbeLibrary *)probeLibrary removeProbeMapFor: [M class]];
        {
          ProbeMap * probeMap = [EmptyProbeMap createBegin: _MAML_zone_];
          [probeMap setProbedClass: [M class]];
          probeMap = [probeMap createEnd];
          [probeMap addProbe: [probeLibrary getProbeForVariable: "x" inClass: [M class]]];
          [probeMap addProbe: [probeLibrary getProbeForMessage: "skip" inClass: [M class]]];
          [probeLibrary setProbeMap: probeMap For: [M class]];
        }
      }
    }
and in the agent `A':
    + (void) _MAML_buildProbeMap_: (id) zone {
      id _MAML_zone_; _MAML_zone_=zone;
      {
        [(MAML_ProbeLibrary *)probeLibrary removeProbeMapFor: [A class]];
        {
          ProbeMap * probeMap = [EmptyProbeMap createBegin: _MAML_zone_];
          [probeMap setProbedClass: [A class]];
          probeMap = [probeMap createEnd];
          [probeMap addProbe: [probeLibrary getProbeForVariable: "i" inClass: [A class]]];
          [probeMap addProbe: [probeLibrary getProbeForMessage: "look" inClass: [A class]]];
          [probeLibrary setProbeMap: probeMap For: [A class]];
        }
      }
    }
To build up the probes, you have to `call' the buildProbes construct in the observer's init subroutine:
    @buildProbes;
which is translated as the buildProbe subroutines are called for the model and any agent:
      [model _MAML_buildProbeMap_];
      [A _MAML_buildProbeMap_: _MAML_zone_];
For calling the probe windows,  you can use the probe subroutine defined as:
    - (void) probe {
       [probeDisplayManager createProbeDisplayFor: self];
    }
This can be called in any subroutine or initialization code:
    [model probe];
    [agent probe];
In the above example the `agent' name denotes an agent variable.

[Back to the Table of Contents]


Init

The model and observer initialization codes are generated in the already mentioned model buildObjects subroutine. The model initialization code is generated where the initModel directive is placed:
    `@initModel;'
The buildObjects subroutine also calls the inherited Swam or GUISwarm buildObject subroutine:
    [self buildObjects];
In the model one can also call buildProbes or create directives as was already mentioned.

[Back to the Table of Contents]


Uses

From the MAML line of the form:
    @uses <stdio.h>, <stdlib.h>;
 the following Swarm code is generated
    #import <stdio.h>
    #import <stdlib.h>
These lines are inserted in the corresponding `.h' file. For example, if the MAML line was used in an agent called `MyAgent', the Swarm lines are introduced at the beginning of the `MyAgent.h' file.

[Back to the Table of Contents]


The Default MAML Library

The default MAML library in its current version is generated by the compiler any time a new application is created. The `MAML.h', `MAML_ProbeLibrary.h' and `MAML_ProbeLibrary.m' files are created. In the `MAML.h' file the string and boolean MAML types are defined:
    typedef char (string)[256];
    typedef enum {false, true} (boolean);
In the `MAML_ProbeLibrary.h' and `MAML_ProbeLibrary.m' files the  MAML_ProbeLibrary class is created which inherits from the Swarm ProbeLibrary and adds the removeProbeMapFor subroutine:
    - removeProbeMapFor: (Class) aClass {
       if ([classMap at: aClass] != nil) [classMap removeKey: aClass];
       return self;
    }
This subroutine was already used in examples presented in Probes section. A more complex MAML library will be created later. For the moment the Swarm, Objective-C and C tools in MAML programming techniques are also regarded as part of the MAML library later this will be replaced with genuine MAML tools.

The `MAML.h' imports the following C standard library tools:

    #import <stdio.h>
    #import <stdlib.h>
    #import <signal.h>
    #import <string.h>
    #import <ctype.h>
The Swarm v1.3 code generation in addition imports in `MAML.h' the Swarm random library's header file:
    #import <random.h>
The following examples are valid for Swarm v1.02 code generation. In Swarm v1.3 code generation the only difference is that 'swarmobject' changed to 'objectbase' and in case of 'gui' observer `simtools' changed to `simtoolsgui'.

The `MAML_ProbeLibrary.h' imports Swarm library tools in the following files:

    #import <swarmobject/ProbeLibrary.h>
    #import <collections.h>
The model header file (e.g., `MyModel.h') imports:
    #import <simtools.h>
and (for a gui observer) the:
    #import <simtools/GUISwarm.h>
or (for a batch observer) the:
    #import <swarmobject/Swarm.h>
The agent header file (e.g. `MyAgent.h') imports:
    #import <swarmobject/SwarmObject.h>
Any programming tool defined in these files can be used in MAML programming. For details please contact the appropriate Swarm, Objective-C and C Reference Manuals.

[Back to the Table of Contents]


The `main.m' and the `Makefile' files

For any MAML code a `main.m' and a `Makefile' file is created.

The main program of any generated application looks like:

    int main(int argc, char ** argv) {
      signal(SIGTERM,&_MAML_sighandler_);
      initSwarm(argc, argv);

      model = [MyModel createBegin: globalZone];
        [model _MAML_initModel_];
        model->maxTimeSteps = -1;
      model = [model createEnd];

      [model _MAML_buildObjects_];
      [model _MAML_buildActions_];
      [model _MAML_activateIn_: nil];
      [model go]; return 0;
    }

A special signal handler is installed for the SIGTERM signal which if is called stops the execution of the model. The Swarm system is started, the model and the agents are created. The _MAML_initModel subroutine calls special internal agent subroutines defined for an agent `A' as:
    + (void) _MAML_initAgent_: (id) zone {
      groupOfA = [List create: zone];
    }
This subroutine creates the `groupOfA' agent list which will contain all agents created within the `A' agent class. The maxTimeSteps is set to -1 which means that by default there is now upper time limit for the execution, this may be redefined in the MAML model initialization code to any appropriate value. The buildObjects, buildActions and activateIn and finally the go subroutine is called. This later one launches the execution of the application which will stop either reaching the maxTimeSteps number of life cycles or forced by the user.

The `Makefile' was created for Linux systems but also works with the Swarm NT version. It includes the Swarm `Makefile.appl' and defines the rules for creating the application. The default name for the application is 'run'. The `Makefile' adds the Swarm space library and a special `it' rule which after creating the executable deletes the `.o' object files. Any application can be compiled and started on Swarm level using the following command:

    make it ; run
In older versions of the compiler the default application name (and thus the name of the generated executable) was the observer's name, but the `it' make rule renamed the executable file to `run', and thus the above command had the same effect. This was changed because of a problem with the Swarm NT version in which the generated executable got a `.exe' extension (e.g., run.exe).

[Back to the Table of Contents]


[model/observer] [agent] [var/sub] [plan/schedule] [extendPlan/extendSchedule] [create/createBegin/createEnd] [probe/buildProbes] [init] [uses]
copyright © 1999 agent-lab
Send comments to maml@maml.hu