MAML
Reference Manual for (xmc) v0.03.1
[import]
[define] [model/observe]
[agent/extendAgent] [var/sub]
[plan/schedule]
[create] [probe]
[uses]
[init] [example]
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:
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:
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:
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:
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:
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:
This plan, by default, will be sequential. To make `myPlan'
randomized you can use:
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:
This assumes that x was defined (with any kind of modifiers) as:
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:
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]
|