MAML -- Multi-Agent Modeling Language

[ 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 Tutorial


This document was created to give a quick introduction to MAML. It does not contain the whole functionality of the language, but explains its basic structures and most of its capabilities. Note that some elementary knowledge of Objective-C (and thus C) is required, as only the new features of MAML are explained. Some knowledge of Swarm can also be helpful. (If you are interested, you can find references to the documentation of different versions of Swarm at the Swarm Home Page.)

The tutorial consists of a few small models, ranging from very elementary models to small, but already interesting, scientific ones. A short description of the succeeding model and a summary of the newly introduced language elements precede each step. Every model is commented upon, but because only the new features are explained, following the order in which the steps are presented may avoid confusion. 

The source code of the programs is available in two versions: one suitable for Swarm 1.3 (this version will be used throughout this document) and the other suitable for Swarm 1.0.2. There is only one exception: if you're using Swarm 1.4.1 or 2.1.1, you'd better get the source for steps 4.1 and 4.2 from here or here.


Step 0 -- The minimal model

This is the simplest model you can create in MAML (m0.maml). It merely defines a closed system (a model). Just take a look at it as a reference point, and continue your tutorial with the next step, in which we'll give you another simple, but more interesting model.


Step 1 -- A really dumb model

This model is one of the simplest agent-based models you can create. It contains two agents ('dumb', and 'dumber') of the class Dumb. After their creation, these agents 'subscribe' to the model (that is they produce some minimal 'sign of life').

In this step we introduce the most important MAML elements, which are the following:
Keyword Description
@model Starts a model. The model goes between curly braces.
@agent Starts the description of an agent.
@var Declares variables.
@sub Declares a subroutine (subprogram).
@init Denotes the beginning of the initialization code of the model (which is executed first).
@create Creates agents.

Here you can find the source code of this model (m1.maml). Let's compile it with the xmc compiler (for downloading information and usage guide refer to the XMC Download Page)!

By trying out the model you will find that it displays the common control panel of swarm simulation, but produces no other visible results. This is logical because we've just created a model (a system), and nothing else. To receive the results of its activities, we need to observe it by the means of an observational tool that 'crosses the boundary' of the closed system. For this we must extend our model, which is done in the following substeps that demonstrate what MAML provides in order to complete this task.


Step 1.1 -- Graphical observation of the first model

The model/observe pair presented here provides a simple graphical observation of the behavior in model 1. In this substep, the model itself hasn't changed, but an extension (a so called 'observe' section) has been added. This observe section describes what the interface of the model (which is a 'closed world') is to the user running the simulation. The interaction can be bidirectional. The parameters of the model can be set by the user: this is an 'input' to the simulation. The output of the simulation can be visualized or saved into files.
One way to monitor and modify the value of variables is to "probe" them: displaying them in a window on the screen. (With probing even subroutine calls can be inserted run time.) For the model (and for each agent class) we can set which variables (and subroutines) should be probed.
Keyword Description
@observe as Starts the observe section. The structure must include the name of the model being observed (the model with that name must be provided). The observe section also contains a section for initialization.
@probe Sets the probed variables (and subroutines) for the model (or an agent class, depending where the @probe is).
@buildProbes To be called before invoking [self probe] (or [anAgent probe] for an agent instance), which actually displays the probe window for the model (or anAgent). (It is possible that the @buildProbes keyword will be either removed or given additional functionality.)

source code m1.1.maml

Besides the control panel there is a "probe window" titled "m1" containing the probed variables of the model (in this case only one). The value corresponding to this variable is 0 at the beginning and becomes 2 after the 0th timestep.


Step 1.2 -- Batch mode observation of the first model

More than one observe section can be written for a specific model. Here we present another observation of model 1. This observation is not graphics-based: it simply writes output data into a file. This technique is
preferred when one runs a simulation off-line, "in batch mode". This is usually the case when the "parameter space" is investigated: that is, when multiple copies of the same simulation with different (initial) parameters are executed, often at the same time.
Term Description
@observe batch The "batch" modifier indicates that there is no need for a graphical interface (controlPanel).
@initModel Triggers the execution of the initialization section of the model. With this you can rule when the initialization of the model should happen. In the observe init you can execute a piece of code before it (this is the default if there is no @initModel) and another piece after it.
file-handling (C-language) For details of file handling in C language, please refer to your C Language Book.
source code m1.2.maml

If the execution of the simulation takes place in a user environment without graphical user interface (namely X Windows), the simulation should be started with the run -batchmode command instead of the simple run command. The absence of a graphical user interface results in the error: TkExtra (instance)run-time error message.

When executed, the output of the simulation (the value of numOfSubscribedAgents, which is 2) is written to the file named OUTPUT.


Step 2 -- A very simple counting 'model'

In this example the model contains one single instance of the agent class Counter. This agent counts how many times its "increase" subroutine was called. During the simulation the invocation of this subroutine is triggered in each timestep. The simulation lasts for 100 timesteps.
Keyword Description
@schedule cyclic (1) A schedule is an abstraction of a mechanism that can trigger certain events at certain timesteps. In this form the body of the construct (0: @to counter increase;), namely the invocation of the counter agent's increase subroutine, will be triggered in each timestep. The cyclic modifier means that the body should be executed not only once, but it should be restarted after a certain number of timesteps (here "1", in general "n"). The structure of this n timesteps is described in the body. For example, in the 0th timestep of each n length cycle the [counter increase] invocation takes place. (In this case this is the only timestep, as the length of the cycle equals 1.)
@to Used to set the agent that should receive a message.
@create{} When an agent is created, it can also be initialized.
@observe gui Here "gui" means that the observation is with graphical user interface (control panel, etc.). Gui is the default.
@extendAgent Adds new features to an agent class in the observation. (Note, this is not inheritance!) Here we define a probe to the agent class Counter. The probe window for the counter agent (the instance) will be displayed during the initialization of the observe section but after the initialization of the model (when the counter agent has already been created).
maxTimeSteps The number of timesteps the simulation runs. If this variable is not set (that is, it equals -1) there is no restriction on the length of the simulation. Changing the value of maxTimeSteps after the initialization of the model and that of the observe section has no effect. After reaching maxTimeSteps timesteps, the simulation terminates (and quits). The advantage of maxTimeSteps can be best exploited in batch mode.

source code m2.maml

When running the simulation in the counter probe window we can follow how the count value increases in each timestep.


Step 3 -- Race

In this model we have 10 agents of class Competitor. These agents jump ahead in each timestep with a random value (from 1 to 3), increasing the value of their "distance" attribute). In each timestep we monitor the currently leading agent in the observe section. The agents are identified by their "row" attribute.
Term Description
$define Assigns a (global) name to a certain value using this keyword. All occurance of the name in the source code will be replaced with the assigned value. The mechanism is similar to the #define in C: this is a macro definition expanded by the preprocessor (the first phase of the compiler).
array declaration In a @var construct (or in a parameter list of a subprogram) the [] signifies the declaration of an array. 
In this example we declare an array of Competitor agents.
array creation  (using index in initialization) Using the @create construct one can create and initialize an array of agents. In the initialization part the array index can also be referred.
@forEach This keyword, in a @schedule construct, indicates that the appropriate message should be sent to more agents at the same time. The argument of @forEach should be a collection of agents.
groupOf For each agent class a predefined collection variable is assigned: for agent class A the variable groupOfA. This collection variable contains all agent instances of the corresponding class.
no name needed for observe  The observe construct doesn't have to have an "as" clause. The observe doesn't have to have a separate name.
uniformIntRand (Swarm) For (pseudo)random number generation you can use the appropriate Swarm libraries.
inserting C code Standard C (Objective C or Swarm) code can be written in certain parts of the MAML code, for example in a subroutine body or in a @init part. See the body of subroutine searchForFront in the observe section.
Probing variables introduced in the observe section. Whenever you introduce a variable by the @var clause, the variable can be probed. Note that the variables 'row' and 'distance', (introduced in the observe section to monitor the currently leading agent) are also probed.

source code m3.maml

During each timestep, the observe section receives a searchForFront message that finds out which agent has the largest distance attribute. This value and the row attribute of the "winner" agent is shown in the probe window of the model. In another probe window, the attributes of the first competitor (with row number 0) are displayed.

Exercise: Modify both the model m3 and the observe section by removing the row attribute from the Competitor agent class. Use the index of agents in the competitors array to identify the agents.


Step 3.1 -- A variant of 3

The searchForFront subroutine of the observe section can be replaced with a new subroutine in the extension of the Competitor agent class (which is invoked in every timestep). Thus, each step of the loop statement in searchForFront is replaced with the execution of the appropriate Competitor agent's "subscribe" subroutine. The subscribe subroutine sends the agent's row and distance to the observe section through the invocation of the newJumpOf:To: subroutine. A new schedule is introduced that will trigger the subscribe subroutine of each Competitor agent in each timestep.

source code m3.1.maml

Step 3.1.1 -- A variant of 3.1

In 3.1 the Competitor agents send the subscribe message to "the observe section". In 3.1.1 a new agent is introduced for this purpose. This agent, an instance of FrontLiner, is defined in the observe section. This illustrates that not only a model, but also an observation can be written in an "agent-based" manner.

source code m3.1.1.maml

(Another variant of 3.1.1 is being developed...)

Step 3.1.2 -- A variant of 3.1

This model is almost the same as 3.1, but instead of introducing a new schedule to trigger the subscribe subroutine calls, we extend an existing schedule. The schedule that will be extended should be supplied with a name.

source code m3.1.2.maml


Step 4 -- Party Preferences

Civilians change their preferred party over time as parties change what they offer.

In this model there are two types of agents: parties and civilians. Each civilian belongs to one of the parties. In each timestep they reconsider which party is the best for them. The decision is based on what the parties offer to their members. The basic rules are the following:

  • There are a number (numOfOffers) of aspects to be considered, represented as integer values in the range 0..maxOffer. These values are different for each party (stored in the party's offer attribute).
  • Each civilian has a weight to describe to what extent an aspect i is important to him. These weights are integer values in the range 0..maxWeight, stored by each civilian in the weights attribute.
  • The overall advantage a party can supply is the basis of the decision: in each timestep the agent chooses the "best" party for him. This overall advantage is the weighted sum of the offers of that party.
  • In each timestep the offers of a party are modified with a random number in the range of -changeInOffer..changeInOffer. (This modification represents how the goals of the party in that aspect came true.)
  • The offer is also modified according to the current size of the party. The number of the party's members is divided by membersQuotient. This result is added to the offer.
  • The civilians are loyal to their formal parties. The overall advantage of a civilian's current party is increased by the product of the number of timesteps during which the civilian is in that party (fidelity attribute) and the fidelityFactor.
The parameters of the model are: the number of parties and civilians (numOfParties and numOfCivilians, respectively), numOfOffers, maxOffer, changeInOffer, maxWeight, membersQuotient and fidelityFactor.

The goal of the model is to examine the size of the parties and their changes over time. We expect that the size of the leading parties will be stable after a while.

Initially the offers of the parties are set equally and the weights of the offers in the civilians are set randomly. The initial distribution of the civilians among the parties is also randomly chosen. During each timestep, the parties calculate their modified offers and then the civilians make their decision about their favourite parties.
Term Description
declaration-creation-initialization of (int) array variables The declaration, creation and initialization of arrays of values is analogous to those of arrays of agents. There are arrays of int values presented in this model. We can use [] in @var constructs and subroutine parameter lists to declare arrays. We can use the @create construct to create arrays (of dynamic size), and even give an initialization part as the body of the @create.
@planDef This keyword defines a plan. Such a definition contains a number of actions to be performed in a certain order: sequentially (seq: this is the default, and currently the only supported), concurrently (con), or in random order (rnd). The actions are subroutine invocations with a certain target, e.g., an agent or a collection of agents.
@plan This keyword activates a plan. Such an activation can take place in an @schedule structure. The plan is executed in a certain timestep; in other words, the plan's actions are executed in the specified order.
parametrization The following demonstrates an easy way to parametrize a simulation. The parameters are variables in the model. They are initialized at the beginning of the @init part of the observe section. Then a probe window for the model containing the parameter variables is created and displayed. The user now is able to reset the parameters. After that, he/she starts the simulation by pressing Go or Time Step on the control panel. At this point the initialization of the model (according to the parameters) takes place: @initModel. At the end of the init part of the observe section, probes on certain agents of the model can be added, as well as other observational tools (see the next examples).
[controlPanel setStateStopped] This message call stops the simulation in a GUI observer. The simulation can later be reactivated by the user, hitting the 'Go' or 'Timestep' button on the program's graphical interface. This line is used when we stop the simulation to allow the user to alter the model parameters, after the probes with the default values have been displayed.

When you start the program, first the control panel and the probe display of the model appear. At this point you can reset the parameters of the simulation run. Pressing the Time Step button on the control panel results in starting the simulation: the probe windows for all parties are displayed containing the size of the appropriate party.

source code m4.maml


Step 4.1 -- A more sophisticated graphical observer for 4

Instead of displaying the size of the parties in probe windows this application draws a histogram in each timestep. Each coloumn in the histogram corresponds to the size of a party.

Because the probing mechanism is very time consuming, replacing it with the histogram results in that the speed of the simulation is increased.
Term Description
@uses This keyword is used to make library units (like <stdio.h> or "my_definitions.h") visible. In this example <analysis.h> is made visible. (The @uses mechanism is like importing/including header files in Objective C  or C to make the definition of types and subprograms visible.)
analysis.h One of the library units in the Swarm package. It contains (among others) the EZBin protocoll. (EZBin class in Swarm 1.0.2)
EZBin A protocol in Swarm. (It is a class in Swarm 1.0.2) It is used to display histograms. See the source, regarding the steps to initialize and update the histogram.
@planDef in @schedule One way to use @planDef is inside a @schedule. The result is similar to what we saw in Step 4.

source code for 2.1.1, for 1.4.1 and for 1.3: m4.1.maml


Step 4.2 -- Another graphical observer based on 4.1

We introduce an additional graphical observer tool to 4.1. Using a graph, we record how many civilians have changed parties in each timestep. (Notice that this is not equal to the changes in the sizes of the parties.)
Term Description
EZGraph Another protocol in Swarm, again from <analysis.h>. It is used to display graphs. See the source regarding the steps to initialize and update a graph. (Again, it is a class in Swarm 1.0.2)
@extendPlan Keyword to add new actions to the plan, thus extending a plan definition in the observe section.

source code for 2.1.1, for 1.4.1 and for 1.3: m4.2.maml


Step 5 -- Thomas Schelling's famous Segregation Model.

This simulation is based on a model published by T. Schelling, and consists of agents living in a 2d grid. The agents are either blue or red, and remain at a given location only if a specified limit is less than the ratio of the number of their neighbors having the same color and the total number of neighbors. It is interesting if this limit is fairly low (appr. 0.5), because this fairly tolerant behaviour leads to surprisingly high rate of segregation on the global level.
Term Description
 $import This keyword includes the specified file in the MAML source code at the location where it appears. This keyword's main use allows for separating the model into distinct files, enhancing the model's readibility. 
If the file to be included was already imported by a previous use of this keyword, then the keyword is ignored. (That is, you can only import a file once in a model, although it is not reported as an error.)
boolean A MAML type for truth values. It has two legal values: true and false.
@schedule cyclic (displayFrequency) Note that in the observer we use a variable (namely the 'displayFrequency' variable) to specify the length of the schedule cycle.
nil (Objective-C) Constant that denotes the non-existing agent. (e.g., in the case of a grid holding agents, you find this constant at an empty location.
M(drawSelfOn:) (Swarm) The way to specify a message in Swarm, and thus in MAML. Usually this is used when specifying which message should be sent by certain tools, such as the Object2dDisplay tool (described below). The format is the following: 
Note the colon at the end of the message name in this example. This is to specify that this message has one argument to pass with. 
The following features are tools coming from Swarm:  
space.h A Swarm library to handle 2d grids of different kind.
Discrete2d One of the grids from the space.h library. It can hold objects (agents) on a 2d grid with discrete coordinates.
collections.h Another Swarm library which provides several data structures that store collections of agents.
List One of the simplest collections from the collections.h library. It stores a list of agents. You can dynamically extend or reduce the list.
analysis.h A Swarm library we've already used during the course of this tutorial. (Check out step 4.1!)
ZoomRaster A tool from the library analysis.h, to display a zoomable window containing graphics. (We use it now to show the 'Segregation World' inside it.)
Object2dDisplay A tool to display a collection of agents on a graphics window. A specified method is called on each member of the collection: that method draws the mark corresponding to the given agent onto the window specified.
XColormap (Swarm 1.0.2) or Colormap (Swarm 1.3) An object holding a color palette (or scale) that can be used when drawing.

First the control panel pops up and the probe display of the model: here the user can reset the parameters of the simulation. Pressing the Time Step or the Go button on the control panel results in starting the simulation: the display of the world is displayed under continuous change as the simulation runs.

This is the first model which consists of more than one files. Please, check them all.

main source file (the observer which takes the model) Segregation.maml
the model's file (which takes the agents) m5.maml
the agents' source resident.maml.stub

copyright © 1999 agent-lab
Send comments to