SAPERE Incarnation Tutorial

An explanation of the basics of the SAPERE Incarnation is available here. A tutorial similar to the base tutorial, with increasingly rich examples, focused on the SAPERE incarnation. Reference descriptions of the SAPERE LSA language inside the simulator are available here

The tutorial can be found on GitHub. The README.md file of the project explains the use and the steps to follow.

CI CI

Hands-on tutorial with the Alchemist SAPERE incarnation

The goal of this tutorial is to showcase the usage of Alchemist-SAPERE, by a sequence of working examples and increasingly challenging exercises.

Introductory material to the simulation world and to the process that led to the creation of Alchemist and of its SAPERE incarnation are provided here.

More information on how to write simulations in Alchemist are provided on the official website.

Prerequisites

Alchemist requires a working installation of the Java Development Kit 11 or newer to run. We do recommend either OpenJDK or OpenJ9 from AdoptOpenJDK. Several architectures, operating systems, and JDK versions are tested for compatibility.

Prerequisites with docker

When running with docker, installing Java Development Kit is not needed. Docker and docker-compose are needed in order to run this project in container. To run on OS X and Windows machines additional X Window System program will be needed. Eg. xquarts for OS X and Xming for Windows. To run run project use docker-compose up. Simulation can be specified eg. in docker-compose.yml file.

Lanching simulations

The project is managed via the Gradle Build Tool. You do not need to install it, the launch script will download the correct version for you.

In order to launch a simulation named SIMNAME, a file named SIMNAME.yml must be in the src/main/yaml folder of the project. That's where the build script will look up. There will be one Gradle task for each simulation file, which can be executed as:

./gradlew SIMNAME

If an effects file named SIMNAME.json is present in the effects folder, it will be loaded automatically.

NOTE the environment variable CI is used to determined whether the task is running in a headless continuous integration environment. If you have CI=true in your environment, the graphical interface won't get pulled up.

Exercises

Using the provided simulation and the documentation provided on the official Alchemist website, and in particular in reference guide to the YAML simulations and in the SAPERE incarnation reference, and the graphical interface usage description available here, try to solve the following exercises:

  1. Add two nodes to an empty, continuous environment, and make them connected
  2. Create 10000 nodes randomly displaced inside a circle centered in (0,0) and radius 10
  3. Create a grid of nodes from (-5,-5) to (5,5), with nodes every (0.25,0.25) distance units, and no perturbance
  4. Create a perturbed grid from the example above
  5. Put some {token} LSAs in some nodes of the system
  6. Write a "dodgeball" program
  7. See how YAML can be used to write personalised sections and how they can be referred
  8. Modify the dodgeball program so that it counts in the LSA the number of passes
  9. Write an LSA diffusion program: after some time, every node of the network must have the {token} LSA. Use the * operator
  10. Look at the 10-math.yml file. Esperiment with it and try to move nodes around manually.
  11. Write a gradient, it should:
    1. convert a {source} to a {gradient, 0} (don't delete the source!)
    2. diffuse to neighbors the gradient, whose value is increased of #D
    3. if there are multiple copies of the gradient, keep only the lowest (immediately!)
    4. every some time "age" the information by increasing its value
    5. delete gradients whose value is higher than some threshold (e.g. 20).
  12. Take a look to 12-sets.yml, and see how the set arithmetic works. Run it, and see the result.
  13. Modify the program above by changing the time distribution, using a personalised one: a DiracComb with parameter 0.5
  14. Take a look to 14-yaml.vars.yml, and make sure to understand how the variables system works
  15. Take a look to 15-move.yml, run it and play with its variables
  16. Try to run 16-maps.yml (note: it can take some time on the first load). Get a glance of the possible complexity of advanced scenarios. Discuss the result, modify the example as you like.
Note

Something went wrong along the line? Drop us an issue report and we’ll get back to you.

LSAs

Syntax details are available in the reference. The following code creates an irregular grid of devices, of which those located around the center of such grid contain the tuple { token }:

incarnation: sapere

network-model:
  type: ConnectWithinDistance
  parameters: [0.5]
  
deployments:
  type: Grid
  parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1]
  contents: # A description of what will be included in the node
    - molecule: hello # Everywhere
    - in: # Restrict the area to...
        type: Rectangle # ...a class implementing Shape with this name...
        parameters: [-1, -1, 2, 2] # ...which can get built with these parameters
      molecule: token # Molecule to inject

The relevant part here is molecule: token. If we wanted to inject the tuple { foo, 1, bar, 2 }, we could have written molecule: foo, 1, bar, 2.

Eco-Laws

Nodes can be programmed with Eco-Laws as follows:

incarnation: sapere

network-model:
  type: ConnectWithinDistance
  parameters: [0.5]

deployments:
  type: Grid
  parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1]
  contents:
    - in:
        type: Rectangle
        parameters: [-0.5, -0.5, 1, 1]
      molecule: token
  programs: # A list of the sets of reactions programming the node
    - 
      - time-distribution: 1 # Frequency. If the class is not specified, the implementation to use is chosen by the incarnation. The SAPERE incarnation automatically loads ExponentialTime, which takes a number representing the Markovian rate.
      # program lets the incarnation choose the class implementing Reaction, and passes down a string that, when parsed, produces the program
        program: > # ">" begins a multiline string (quote mode)
          {token} --> {firing}
      # If the time distribution is unspecified, the SAPERE incarnation assumes a "ASAP" behavior (rate = Infinity)
      - program: "{firing} --> +{token}"

Eco-Laws can be programmed to send LSAs to neighbors, as well as to look into neighboring nodes for getting LSAs. In order to do so, the LSA template in the Eco-Law must be preceded by a neighbor operator, either + or *.

+ means in a neighbor: if used on the left hand side, it considers the condition satisfied if at least one neighbor has at least one LSA matching the provided template; if used on the right hand side, sends the LSA to one random neighbor.

* means in all neighbors: if used on the left hand side, it considers the condition satisfied if all neighbors have at least one LSA matching the provided template; if used on the right hand side, sends a copy of the LSA to all neighbors.

The following code exemplifies a diffusion program: when { token } is present locally, it is copied into neighboring nodes once per second; and as soon as two copies of { token } are present, one gets removed.

incarnation: sapere
network-model:
  type: ConnectWithinDistance
  parameters: [0.5]
_send: &send
  - time-distribution: 1
    program: >
      {token} --> {token} *{token}      
  - program: >
      {token}{token} --> {token}      
deployments:
  type: Grid
  parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1]
  contents:
    in:
      type: Rectangle
      parameters: [-0.5, -0.5, 1, 1]
    molecule: token
  programs: *send

Rates

The time distribution with which reactions should get scheduled can be controlled by thinkering with the yaml specification as per every reaction in Alchemist. If no TimeDistribution is specified, the Eco-Law is assumed to run “as soon as possible” (ASAP).

This may lead to unwanted behaviour. For instance, programming a single node with: --> { foo } will cause the simulation to schedule a reaction producing { foo } at time zero, and at each execution the time will remain zero: the simulator will be producing copies over copies of the tuple, never advancing in time (Alchemist is a discrete event simulator), and possibly going on until the JVM memory limit is reached.

If a number is specified as time distribution, using the time-distribution key, then it will be interpreted as the Markovian rate of an exponentially distributed time.

Other distributions found at it.unibo.alchemist.model.timedistributions can be used leveraging the arbitrary class loading system.

In the following example, two Eco-Laws are configured, and one of them is bound to an ExponentialTime with rate 1, namely, when the reaction can be executed (the left hand LSAs have local matches), it will execute at an average of once per second (with a variance of 1 s²).

incarnation: sapere

network-model:
  type: ConnectWithinDistance
  parameters: [0.5]

deployments:
  type: Grid
  parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1]
  contents:
    - in:
        type: Rectangle
        parameters: [-0.5, -0.5, 1, 1]
      molecule: token
  programs: # A list of the sets of reactions programming the node
    - 
      - time-distribution: 1 # Frequency. If the class is not specified, the implementation to use is chosen by the incarnation. The SAPERE incarnation automatically loads ExponentialTime, which takes a number representing the Markovian rate.
      # program lets the incarnation choose the class implementing Reaction, and passes down a string that, when parsed, produces the program
        program: > # ">" begins a multiline string (quote mode)
          {token} --> {firing}
      # If the time distribution is unspecified, the SAPERE incarnation assumes a "ASAP" behavior (rate = Infinity)
      - program: "{firing} --> +{token}"

Exercise

To better grasp details of the incarnation, we recommend looking at the examples available on the Alchemist SAPERE Incarnation tutorial on GitHub.

Besides examples with growing complexity, there are a number of proposed exercises that should help you get acquainted with the SAPERE way of writing self-organizing behaviors.