Since version 2.0.0, Alchemist uses YAML as primary mean for writing simulations. Historically, it relied on XML instead, but the system has since be deprecated, due to its verbosity and human-unfriendliness. Some resources on how to write a proper Alchemist XML are still available here. Keep in mind, however, that such method is now deprecated and unmaintained, and it is likely to get dropped if any major breakage occurs. If you are new to Alchemist, we recommend to follow the remainder of this page, and learn about the wonders of YAML.
As a first step, we recommend learning the YAML basics. The language is so simple and human readable that there is probably no better way to learn it than to read it directly. My suggestion is to use the tutorial “Learn X in Y minutes where X = YAML”, it should provide a good YAML guide (surely sufficient to follow the tutorial):
The Alchemist YAML
Alchemist expects a YAML map as input. In the following, we’ll discuss which keys it expects. Of course, users are free to use all the YAML features (e.g. anchors) to organize their code and reduce duplication.
Class loading with the Alchemist YAML
One important aspect of the Alchemist YAML is the ability to let the user control which actual Java classes should be loaded inside a simulation, and which constructor should be used to do so. Almost every entity of an Alchemist simulation can be instanced using arbitrary Java classes that implement the required interfaces. When the alchemist YAML parser encounters an entity that is a YAML Map providing the keys
parameters, it tries to resolve the value of the value associated to
type to a class name, then tries to create the object with the constructor better suiting the provided
Class name resolution
The value associated with
type must be a string representing a valid Java identifier. If the value contains one or more
. characters, then it will be interpreted as a fully qualified name. If no such character is included, then the default package for the desired alchemist entity will be prefixed. In no case Alchemist will attempt loading a class situated in the default package (but I am sure good people like you don’t put stuff there, do you?).
If the class gets correctly loaded (namely if a class is present in the classpath with the fully qualified name as passed or as guessed by Alchemist), then its constructors get sorted based on the number and type of parameters. The system tries to build an object with all the constructors, in order, until one of them provides an instanced object, considering both the current context (namely, the entities that have already been instanced) and the value of
For instance, imagine that you are trying to build an instance of a Reaction, whose only constructor requires an Environment, a Node, an
int and a
String. In this case, an Environment and a Node must have already been created (or the YAML loader won’t be at this point). As a consequence, the first two parameters are automatically inferred by the current context and passed to the constructor. The other two parameters can not be inferred this way; as such the value associated to
parameters is used to extract the proper values (if possible). In this case, this would have been a valid
As you can easily infer, the value of
parameters must be a YAML list.
Don’t despair if the class loading system is still unclear: it is used pervasively and it will get clearer and clearer with the examples in the next sections.
incarnation is mandatory.
It expects a string value, and does not support the class loading mechanism. Such string will be used to get the most similarly named incarnation (the algorithm may vary), namely the subclass of Incarnation whose simple name is closest to the string. The (obvious) suggestion is to use an existing incarnation name, such as
protelis. New incarnations may (and will) be available in future.
Note: this is also the most minimal valid alchemist specification
variable section lists variable simulation values. A custom variable is defined in a Java class which implements the Variable interface. If no fully qualified variable name is provided for class loading, Alchemist uses the package variables to search for the class.
seed section may contains two optional values:
simulation. The former is the seed of the pseudo-random generator used during the creation of the simulation. For instance, perturbating grid nodes in the
displacement section. The latter is the seed of the pseudo-random generator used during the simulation. For instance, handling events concurrency (which event occurs before another).
Examples Setting seeds with integer values.
Setting seeds with variables.
environment key is used to load the Environment implementation. It is optional, defaults to a continuous bidimensional space. If no fully qualified environment name is provided for class loading, Alchemist uses the package environments to search for the class.
The following simulations are equivalent, and load the default environment (which is incarnation independent, here
protelis is picked, but it works for any other incarnation as well):
The following simulation loads data from an Openstreetmap file (OSM XML and PBF formats are supported) located in the classpath in the folder
The following simulation loads data from a black and white raster image file located in the classpath in the folder
images , interpreting the black pixels as obstacles (areas where the nodes should can not get):
The following simulation loads a personalized class named
my.package.FooEnv implementing Environment, whose constructor requires a String and a double:
More about the environments shipped with the distribution here.
position section list the coordinate types of the simulation. Actually, only one value is taken into account. Each type implements the interface Position. If no fully qualified position name is provided for class loading, Alchemist uses the package positions to search for the class.
position should reflect the simulation physical features. For instance, when a city map is considered Continuous2DEuclidean distance might be no longer suitable. Given two points A e B,
distance(A, B) may differ from
network-model key is used to load the implementation of linking rule to use in the simulation. It relies on the class loading mechanism, it is optional, and if not specified defaults to NoLinks (nodes in the environment don’t get connected). Omitting such key is equivalent to writing any of the following (they are equivalent):
If no fully qualified linking rule name is provided for class loading, Alchemist uses the package linkingrules to search for the class.
displacement sections lists the node locations at the beginning of the simulation. Each displacement type extends the interface Displacement. If no fully qualified displacement name is provided for class loading, Alchemist uses the package displacements to search for the class.
A single point located in (0, 0).
10000 nodes, displaced in a circle with center in (0, 0) and radius 10.
Nodes are randomly located in a square with a 0.1 distance units long side, centered in the point where the node was previously placed.
It is possible to set the content of the nodes inside a given region. Only the nodes inside the
Rectangle area contain the
randomSensor molecules (global variables).
Nodes can execute a list of protelis programs.
export section lists which simulation values are exported into the
folder specified with the
-e path/to/folder argument. Data aggregators are statistically univariated. Valid aggregating functions extend AbstractStorelessUnivariateStatistic.
Extending the simulation
It is possible to enrich the simulation with custom classes (variable types, displacements, etc). The latter have to be included in the simulation classpath and have to implement (extend) the respective interfaces ([abstract] classes).