Create reusable variables
Declaring variables
The variables
section lists variable simulation values.
A variable defines some kind of value that can be referenced in the simulation file.
There are two kinds of variables: free and dependent variables. Free variables are meant to provide support for running batches of simulations with varying parameters; dependent variables are either single valued or can be computed from the values of other variables (free or dependent), and they are designed to simplify the simulation code.
Free variables
Free variables define a set of values and a default. Their main scope is enabling Alchemist to run a set of simulations with different parameters (values of variables) without the need to duplicate the simulation code. When used in this mode (called “batch mode”), Alchemist by default produces the cartesian product of all the variables values’ selected for the batch, and runs a simulation for each combination. If the simulation is not executed as batch, then the default value is used.
Linear variables
A variable generating values in a range, starting from a minimum value, and increasing by some step.
Represented by LinearVariable
.
Examples
incarnation: sapere
variables:
myvar: &myvar
type: LinearVariable
parameters: [0, 0, 1, 0.2]
incarnation: sapere
variables:
rate: &rate
type: GeometricVariable
parameters: [2, 0.1, 10, 9]
size: &size
type: LinearVariable
parameters: [5, 1, 10, 1]
mSize: &mSize
formula: -size
sourceStart: &sourceStart
formula: mSize / 10
sourceSize: &sourceSize
formula: size / 5
network-model:
type: ConnectWithinDistance
parameters: [0.5]
_send: &grad
- time-distribution: *rate
program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}"
- program: >
{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}
deployments:
type: Grid
parameters: [*mSize, *mSize, *size, *size, 0.25, 0.25, 0.1, 0.1]
contents:
type: Rectangle
parameters: [*sourceStart, *sourceStart, *sourceSize, *sourceSize]
molecule: token, 0, []
programs: *grad
incarnation: protelis
variables:
zoom: &zoom
formula: 0.1 # Must be a valid Groovy snippet
image_name: { formula: "'chiaravalle.png'" }
image_path: &image_path
language: kotlin # Pick whatever JSR223 language you like and add it to the classpath
formula: | # The following is pure Kotlin code. Other variables can be referenced!
import java.io.File
fun File.findImage(): String? = walkTopDown().find { image_name in it.name }?.absolutePath
fun File.findImageRecursively(): String = findImage() ?: File(this, "..").findImageRecursively()
File(".").findImageRecursively()
timeout: 5000
# Linear free variable
walking_speed: &walk-speed { default: 1.4, min: 1, max: 2, step: 0.1 }
seed: &seed { default: 0, min: 0, max: 99, step: 1 } # 100 samples
scenario_seed: &scenario_seed { formula: (seed + 31) * seed } # Variable-dependent
people_count: &people_count
type: GeometricVariable # A variable scanning a space with geometric segmentation
parameters: [300, 50, 500, 9] # default 300, minimum 50, maximum 100, 9 samples
seeds: { simulation: *seed, scenario: *scenario_seed}
export:
type: CSVExporter
parameters:
fileNameRoot: "snippet-variables-export"
data:
- time
- molecule: "default_module:default_program"
aggregators: [ mean, max, min, variance, median ] # From Apache's UnivariateStatistic
value-filter: onlyfinite # discards NaN and Infinity
environment: { type: ImageEnvironment, parameters: [*image_path, *zoom] }
network-model: { type: ObstaclesBreakConnection, parameters: [50] }
deployments:
type: Rectangle
parameters: [*people_count, 62, 15, 95, 200]
programs:
- time-distribution: 1
program: >
import protelis:coord:spreading
let source = [110, 325]
let vector = self.getCoordinates() - source
let distance = hypot(vector.get(0), vector.get(1))
distanceTo(distance < 50)
- program: send
- { type: Event, time-distribution: 1, actions: { type: LevyWalk, parameters: [*walk-speed] } }
incarnation: protelis
variables:
seed: &seed # You can give the anchor any name, assigning the name of the variable is convenient, though
{min: 0, max: 1, step: 1, default: 0} # This variable ranges in [0, 9], steps of 1, defaulting to 0
network-model: { type: ConnectWithinDistance, parameters: [10] }
_program-pools:
compute-gradient: &gradient
- { time-distribution: 1, program: "advanced:converge" }
- program: send
move: &move
- time-distribution: { type: ExponentialTime, parameters: [1] }
type: Event
actions: { type: MoveToTarget, parameters: [destination, 1] }
deployments: { type: Circle, parameters: [50, 0, 0, 5], programs: [*gradient, *move] }
terminate: { type: AfterTime, parameters: [20] }
variables:
testVar: &testVar
min: 0
max: 10
step: 1
default: 2
incarnation: protelis
seeds:
scenario: 1
simulation: *testVar
_molecules:
testref: &testRef test
network-model:
type: ConnectWithinDistance
parameters: [1.5]
environment:
type: Continuous2DEnvironment
_pool: &program
- time-distribution: *testVar
program: test
- time-distribution: null
program: send
- time-distribution: 1
type: Event
conditions: []
actions:
- type: BrownianMove
parameters: [1]
- time-distribution:
type: Trigger
parameters: [1]
type: Event
conditions: []
actions:
- type: BrownianMove
parameters: [1]
_contents:
- source: &content
in:
type: Rectangle
parameters: [-0.2, -0.2, 2.4, 2.4]
molecule: source
concentration: true
- test: &test
molecule: *testRef
concentration: *testVar
deployments:
- type: Circle
parameters: [100, 0, 0, 2.8]
contents:
- *content
- *test
programs:
- *program
terminate:
- type: StepCount
parameters: 2000
incarnation: protelis
variables:
time: &time
type: Flag
parameters: [false]
small: &small
type: Flag
parameters: [false]
n: &n
formula: 100
range: &range
formula: 30
width: &w
formula: 200
height: &h
formula: 20
freq: &freq
formula: 1
sp:
formula: 0.1
bp:
formula: 0.5
retain: &retain
formula: 1 / minfreq
fc:
formula: "time ? (small ? sp : bp) : 0"
minfreq: &minfreq
formula: "freq * (1 - fc)"
maxfreq: &maxfreq
formula: "freq * (1 + fc)"
speed: &speed
language: kotlin
formula: "if (time as Boolean) 0 else 1"
seed: &seed
min: 0
max: 199
step: 1
default: 0
seeds:
scenario: *seed
simulation: *seed
network-model:
type: ConnectWithinDistance
parameters: [*range]
_pools:
- pool: &program
- time-distribution:
type: RandomDiracComb
parameters: [*minfreq, *maxfreq]
type: Event
actions:
- type: RunProtelisProgram
parameters: ["1", *retain]
- time-distribution: null
program: send
- pool: &program2
- time-distribution: 1
program: tomacs
- time-distribution: null
program: send
- pool: &move
- time-distribution: 10
type: Event
actions:
- type: MoveToTarget
parameters: [target, *speed]
deployments:
- type: Rectangle
parameters: [*n, 0, 0, *w, *h]
contents:
- molecule: time
concentration: *time
- molecule: speed
concentration: *speed
- molecule: small
concentration: *small
programs:
- *program
- *move
incarnation: sapere
variables:
category:
subcategory:
- anothercategory:
- three: &three
formula: 3
_formula: &formula
type: JSR223Variable
parameters: [groovy, *three]
*three: &max
<<: *formula
min: &min
formula: three * 0
language: kotlin
myvar: &myvar
type: LinearVariable
parameters: [0, *min, *max, 1]
mydepvar:
formula: 10 / myvar
incarnation: sapere
variables:
rate: &rate
type: GeometricVariable
parameters: [1, 0.1, 10, 9]
size: &size
min: 1
max: 10
step: 1
default: 5
mSize: &mSize
formula: -size
sourceStart: &sourceStart
formula: mSize / 10
sourceSize: &sourceSize
formula: size / 5
network-model:
type: ConnectWithinDistance
parameters: [0.5]
_send: &grad
- time-distribution: *rate
program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}"
- program: >
{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}
# Age information
- time-distribution:
type: DiracComb
parameters: [0.1]
program: >
{token, def: N>0, L} --> {token, N + 1, L}
# Cleanup old information
- program: >
{token, def: N>30, L} -->
_move: &move
time-distribution: 0.5
type: Event
actions:
- type: BrownianMove
parameters: [0.1]
deployments:
type: Grid
parameters: [*mSize, *mSize, *size, *size, 0.25, 0.25, 0.1, 0.1]
contents:
in:
type: Rectangle
parameters: [*sourceStart, *sourceStart, *sourceSize, *sourceSize]
molecule: token, 0, []
programs:
- *grad
- *move
incarnation: sapere
network-model:
type: ConnectWithinDistance
parameters: [0.4]
variables:
seed: &seed
min: 0
max: 9
step: 1
default: 0
speed: &speed
type: ArbitraryVariable
parameters: [0.1, [0.1, 0.1, 1]]
latencies:
formula: "[0.001, 0.01, 0.1, 1]"
tolerances:
formula: "[0, 0.01, 0.03, 0.1, 0.3, 1, 3]"
controlParameters: &control
formula: GroovyCollections.combinations(latencies, tolerances) + [[Double.NaN, Double.NaN]]
algorithm:
type: ArbitraryVariable
parameters: [[0.1, 0.01], *control]
network_mean_latency: &network_mean_latency
formula: algorithm[0]
tolerance: &tolerance
formula: algorithm[1]
Geometric variables
A variable generating geometrically-distributed samples across a range.
Ideal for exploring non-linear phenomena, or for exploring very large ranges of values whose effect is unknown.
Implemented as GeometricVariable
.
Examples
incarnation: sapere
variables:
var0:
type: GeometricVariable
parameters: [0.5, 1, 1, 1]
incarnation: protelis
variables:
zoom: &zoom
formula: 0.1 # Must be a valid Groovy snippet
image_name: { formula: "'chiaravalle.png'" }
image_path: &image_path
language: kotlin # Pick whatever JSR223 language you like and add it to the classpath
formula: | # The following is pure Kotlin code. Other variables can be referenced!
import java.io.File
fun File.findImage(): String? = walkTopDown().find { image_name in it.name }?.absolutePath
fun File.findImageRecursively(): String = findImage() ?: File(this, "..").findImageRecursively()
File(".").findImageRecursively()
timeout: 5000
# Linear free variable
walking_speed: &walk-speed { default: 1.4, min: 1, max: 2, step: 0.1 }
seed: &seed { default: 0, min: 0, max: 99, step: 1 } # 100 samples
scenario_seed: &scenario_seed { formula: (seed + 31) * seed } # Variable-dependent
people_count: &people_count
type: GeometricVariable # A variable scanning a space with geometric segmentation
parameters: [300, 50, 500, 9] # default 300, minimum 50, maximum 100, 9 samples
seeds: { simulation: *seed, scenario: *scenario_seed}
export:
type: CSVExporter
parameters:
fileNameRoot: "snippet-variables-export"
data:
- time
- molecule: "default_module:default_program"
aggregators: [ mean, max, min, variance, median ] # From Apache's UnivariateStatistic
value-filter: onlyfinite # discards NaN and Infinity
environment: { type: ImageEnvironment, parameters: [*image_path, *zoom] }
network-model: { type: ObstaclesBreakConnection, parameters: [50] }
deployments:
type: Rectangle
parameters: [*people_count, 62, 15, 95, 200]
programs:
- time-distribution: 1
program: >
import protelis:coord:spreading
let source = [110, 325]
let vector = self.getCoordinates() - source
let distance = hypot(vector.get(0), vector.get(1))
distanceTo(distance < 50)
- program: send
- { type: Event, time-distribution: 1, actions: { type: LevyWalk, parameters: [*walk-speed] } }
incarnation: sapere
variables:
rate: &rate
type: GeometricVariable
parameters: [2, 0.1, 10, 9]
size: &size
type: LinearVariable
parameters: [5, 1, 10, 1]
mSize: &mSize
formula: -size
sourceStart: &sourceStart
formula: mSize / 10
sourceSize: &sourceSize
formula: size / 5
network-model:
type: ConnectWithinDistance
parameters: [0.5]
_send: &grad
- time-distribution: *rate
program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}"
- program: >
{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}
deployments:
type: Grid
parameters: [*mSize, *mSize, *size, *size, 0.25, 0.25, 0.1, 0.1]
contents:
type: Rectangle
parameters: [*sourceStart, *sourceStart, *sourceSize, *sourceSize]
molecule: token, 0, []
programs: *grad
incarnation: sapere
variables:
rate: &rate
type: GeometricVariable
parameters: [1, 0.1, 10, 9]
size: &size
min: 1
max: 10
step: 1
default: 5
mSize: &mSize
formula: -size
sourceStart: &sourceStart
formula: mSize / 10
sourceSize: &sourceSize
formula: size / 5
network-model:
type: ConnectWithinDistance
parameters: [0.5]
_send: &grad
- time-distribution: *rate
program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}"
- program: >
{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}
# Age information
- time-distribution:
type: DiracComb
parameters: [0.1]
program: >
{token, def: N>0, L} --> {token, N + 1, L}
# Cleanup old information
- program: >
{token, def: N>30, L} -->
_move: &move
time-distribution: 0.5
type: Event
actions:
- type: BrownianMove
parameters: [0.1]
deployments:
type: Grid
parameters: [*mSize, *mSize, *size, *size, 0.25, 0.25, 0.1, 0.1]
contents:
in:
type: Rectangle
parameters: [*sourceStart, *sourceStart, *sourceSize, *sourceSize]
molecule: token, 0, []
programs:
- *grad
- *move
Arbitrary-valued variables
Generates an ArbitraryVariable
spanning on an arbitrary set of values.
Examples
incarnation: protelis
variables:
foo: &foo
formula: 1
bar: &bar
formula: 5 * foo
baz:
type: ArbitraryVariable
parameters: [0, [1, 2, 3, 4, 5]]
fiz:
type: ArbitraryVariable
parameters: [0, [1, 2, 3, 4, 5]]
incarnation: sapere
network-model:
type: ConnectWithinDistance
parameters: [0.4]
variables:
seed: &seed
min: 0
max: 9
step: 1
default: 0
speed: &speed
type: ArbitraryVariable
parameters: [0.1, [0.1, 0.1, 1]]
latencies:
formula: "[0.001, 0.01, 0.1, 1]"
tolerances:
formula: "[0, 0.01, 0.03, 0.1, 0.3, 1, 3]"
controlParameters: &control
formula: GroovyCollections.combinations(latencies, tolerances) + [[Double.NaN, Double.NaN]]
algorithm:
type: ArbitraryVariable
parameters: [[0.1, 0.01], *control]
network_mean_latency: &network_mean_latency
formula: algorithm[0]
tolerance: &tolerance
formula: algorithm[1]
Dependent variables
Some variables are combination of other variables.
Let’s suppose that we want to deploy on a circle,
but for some reason
(e.g. because it is required by the constructor of some Action
)
we need to compute and have available radius and perimeter.
We don’t need to control both of them: the perimeter can be computed from the radius
(or vice versa).
To favor reusability and
apply the DRY principle, the simulator allows defining variables whose values
possibly depend on values of other variables through JSR223Variable
.
Their values can be expressed, by default, in Groovy, but any JSR-223-compatible language can be used, in principle.
If a compatible JSR-223 implementation of the language is available in the classpath,
Alchemist will load and use it transparently.
By default, groovy
, kotlin
(or kts
), and scala
are available as scripting languages for dependent variables.
Info
The JSR-223 specification defines mechanisms allowing scripting language programs to access information developed in the Java Platform.
Many languages (including Groovy, Python (Jython), Kotlin, and Scala provide bindings for JSR-223).
Variables can be defined in any order.
Alchemist figures out the dependencies automatically, as far as there are no cyclic dependencies (e.g. variable a
requires b
, and b
requires a
).
Please note that the simulator variable dependency resolution system is not designed to solve mathematical systems,
so even though the problem has a well-formed mathematical solution, the actual variable resolution may fail;
e.g. if a
is defined as 2 * b + 1
, and b
is defined as 4 - a
, the system won’t bind a
to 3
and b
to 1
,
but will simply fail complaining about circular dependencies.
Multiline programs
Sometimes data manipulation can get tricky and trivial scripting may no longer be enough.
In such cases, and especially with modern languages that allow for a reduced usage of cerimonial semicolons
(such as Kotlin and Scala), it can be useful to write multiline programs.
This can be achieved in YAML by using the pipe |
operator, as exemplified in the following snippet:
multiline-string: |
note that the string
needs to be indented.
Newlines will be preserved!
Examples
incarnation: sapere
network-model:
type: ConnectWithinDistance
parameters: [0.4]
variables:
seed: &seed
min: 0
max: 9
step: 1
default: 0
speed: &speed
type: ArbitraryVariable
parameters: [0.1, [0.1, 0.1, 1]]
latencies:
formula: "[0.001, 0.01, 0.1, 1]"
tolerances:
formula: "[0, 0.01, 0.03, 0.1, 0.3, 1, 3]"
controlParameters: &control
formula: GroovyCollections.combinations(latencies, tolerances) + [[Double.NaN, Double.NaN]]
algorithm:
type: ArbitraryVariable
parameters: [[0.1, 0.01], *control]
network_mean_latency: &network_mean_latency
formula: algorithm[0]
tolerance: &tolerance
formula: algorithm[1]
incarnation: sapere
variables:
var0:
formula: 2
var1:
formula: 2
_program: &program
- time-distribution: 1
program: "{A, 1}-->{A, 1}"
deployments:
type: Rectangle
parameters: [10, 0, 0, 10, 10]
contents:
- molecule: path
concentration: true
- molecule: interestThr
concentration: 0.2
- molecule: veryInterestThr
concentration: 0.5
- molecule: estimationK
concentration: 0.5
programs:
- *program
incarnation: sapere
variables:
var: &var
language: scala
formula: List(5, 3, 4).min
var2: &var2
language: scala
formula: List(10, 3, 4).max
deployments:
- type: Point
parameters: [*var, *var2]
variables:
a:
formula: 22 + 1
language: kts
test:
formula: |
import it.unibo.alchemist.boundary.Loader
import kotlin.collections.listOf
val b = 5.5
listOf(bindings["a"], b)
language: kotlin
test2:
formula: |
val b = 5.5
listOf("a", b)
language: kotlin
test3:
formula: test + test2
incarnation: sapere
incarnation: sapere
variables:
myvar: &myvar
formula: 1
myvar2: &myvar2
formula: myvar * 100
environment:
type: Continuous2DEnvironment
parameters: []
network-model:
type: it.unibo.alchemist.test.util.DummyRule
parameters: [[*myvar, *myvar2], [*myvar, *myvar2]]
incarnation: sapere
variables:
var0:
formula: 2
var1:
formula: 2
incarnation: protelis
variables:
zoom: &zoom
formula: 0.1 # Must be a valid Groovy snippet
image_name: { formula: "'chiaravalle.png'" }
image_path: &image_path
language: kotlin # Pick whatever JSR223 language you like and add it to the classpath
formula: | # The following is pure Kotlin code. Other variables can be referenced!
import java.io.File
fun File.findImage(): String? = walkTopDown().find { image_name in it.name }?.absolutePath
fun File.findImageRecursively(): String = findImage() ?: File(this, "..").findImageRecursively()
File(".").findImageRecursively()
timeout: 5000
# Linear free variable
walking_speed: &walk-speed { default: 1.4, min: 1, max: 2, step: 0.1 }
seed: &seed { default: 0, min: 0, max: 99, step: 1 } # 100 samples
scenario_seed: &scenario_seed { formula: (seed + 31) * seed } # Variable-dependent
people_count: &people_count
type: GeometricVariable # A variable scanning a space with geometric segmentation
parameters: [300, 50, 500, 9] # default 300, minimum 50, maximum 100, 9 samples
seeds: { simulation: *seed, scenario: *scenario_seed}
export:
type: CSVExporter
parameters:
fileNameRoot: "snippet-variables-export"
data:
- time
- molecule: "default_module:default_program"
aggregators: [ mean, max, min, variance, median ] # From Apache's UnivariateStatistic
value-filter: onlyfinite # discards NaN and Infinity
environment: { type: ImageEnvironment, parameters: [*image_path, *zoom] }
network-model: { type: ObstaclesBreakConnection, parameters: [50] }
deployments:
type: Rectangle
parameters: [*people_count, 62, 15, 95, 200]
programs:
- time-distribution: 1
program: >
import protelis:coord:spreading
let source = [110, 325]
let vector = self.getCoordinates() - source
let distance = hypot(vector.get(0), vector.get(1))
distanceTo(distance < 50)
- program: send
- { type: Event, time-distribution: 1, actions: { type: LevyWalk, parameters: [*walk-speed] } }
incarnation: protelis
environment:
type: ContinuousPhysics2DEnvironment
variables:
group1: &group1
formula: it.unibo.alchemist.model.cognitive.groups.GroupFactory.friends()
language: kotlin
group2: &group2
formula: it.unibo.alchemist.model.cognitive.groups.GroupFactory.friends()
language: kotlin
deployments:
- type: Circle
parameters: [10, 0, 0, 20]
properties:
- type: Pedestrian
- type: Perceptive2D
- type: CircularArea
- type: Social
parameters: [*group1]
- type: Circle
parameters: [15, 0, 0, 20]
properties:
- type: Pedestrian
- type: Perceptive2D
- type: CircularArea
- type: Social
parameters: [*group2]
incarnation: protelis
variables:
danger: &danger
formula: "\"danger\""
environment:
type: ContinuousPhysics2DEnvironment
layers:
- type: BidimensionalGaussianLayer
molecule: *danger
parameters: [0.0, 0.0, 20.0, 15.0]
_reactions: &behavior
- time-distribution:
type: DiracComb
parameters: [1.0]
type: CognitiveBehavior
actions:
- type: CognitiveAgentAvoidLayer
parameters: [*danger]
deployments:
- type: Circle
parameters: [100, 0, 0, 50]
properties:
- type: Human
parameters: ["adult", "female"]
- type: Perceptive2D
- type: CognitivePedestrian
- type: Cognitive2D
- type: CircularArea
programs:
- *behavior
incarnation: protelis
variables:
initial_latitude: &initial_latitude
formula: 12.613
initial_longitude: &initial_longitude
formula: 43.715
final_latitude:
formula: 12.663
final_longitude:
formula: 43.738
latitude_space: &latitude_space
formula: final_latitude - initial_latitude
longitude_space: &longitude_space
formula: final_longitude - initial_longitude
environment:
type: OSMEnvironment
parameters:
- maps/urbino.pbf
- true
- true
network-model:
type: ConnectIfInLineOfSigthOnMap
parameters: [1000]
deployments:
- type: Point
parameters: [43.719368, 12.623865]
- type: Point
parameters: [43.718901, 12.623047]
- type: Rectangle
parameters:
- 100
- *initial_longitude
- *initial_latitude
- *longitude_space
- *latitude_space
contents:
- in:
type: Rectangle
parameters: [-6, -6, 2, 2]
molecule: source
concentration: true
incarnation: sapere
variables:
category:
subcategory:
- anothercategory:
- three: &three
formula: 3
_formula: &formula
type: JSR223Variable
parameters: [groovy, *three]
*three: &max
<<: *formula
min: &min
formula: three * 0
language: kotlin
myvar: &myvar
type: LinearVariable
parameters: [0, *min, *max, 1]
mydepvar:
formula: 10 / myvar
incarnation: sapere
variables:
rate: &rate
type: GeometricVariable
parameters: [2, 0.1, 10, 9]
size: &size
type: LinearVariable
parameters: [5, 1, 10, 1]
mSize: &mSize
formula: -size
sourceStart: &sourceStart
formula: mSize / 10
sourceSize: &sourceSize
formula: size / 5
network-model:
type: ConnectWithinDistance
parameters: [0.5]
_send: &grad
- time-distribution: *rate
program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}"
- program: >
{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}
deployments:
type: Grid
parameters: [*mSize, *mSize, *size, *size, 0.25, 0.25, 0.1, 0.1]
contents:
type: Rectangle
parameters: [*sourceStart, *sourceStart, *sourceSize, *sourceSize]
molecule: token, 0, []
programs: *grad
incarnation: sapere
variables:
rate: &rate
type: GeometricVariable
parameters: [1, 0.1, 10, 9]
size: &size
min: 1
max: 10
step: 1
default: 5
mSize: &mSize
formula: -size
sourceStart: &sourceStart
formula: mSize / 10
sourceSize: &sourceSize
formula: size / 5
network-model:
type: ConnectWithinDistance
parameters: [0.5]
_send: &grad
- time-distribution: *rate
program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}"
- program: >
{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}
# Age information
- time-distribution:
type: DiracComb
parameters: [0.1]
program: >
{token, def: N>0, L} --> {token, N + 1, L}
# Cleanup old information
- program: >
{token, def: N>30, L} -->
_move: &move
time-distribution: 0.5
type: Event
actions:
- type: BrownianMove
parameters: [0.1]
deployments:
type: Grid
parameters: [*mSize, *mSize, *size, *size, 0.25, 0.25, 0.1, 0.1]
contents:
in:
type: Rectangle
parameters: [*sourceStart, *sourceStart, *sourceSize, *sourceSize]
molecule: token, 0, []
programs:
- *grad
- *move
incarnation: protelis
variables:
zoom: &zoom
formula: 0.1 # Must be a valid Groovy snippet
image_name: { formula: "'chiaravalle.png'" }
image_path: &image_path
language: kotlin # Pick whatever JSR223 language you like and add it to the classpath
formula: | # The following is pure Kotlin code. Other variables can be referenced!
import java.io.File
fun File.findImage(): String? = walkTopDown().find { image_name in it.name }?.absolutePath
fun File.findImageRecursively(): String = findImage() ?: File(this, "..").findImageRecursively()
File(".").findImageRecursively()
timeout: 5000
# Linear free variable
walking_speed: &walk-speed { default: 1.4, min: 1, max: 2, step: 0.1 }
seed: &seed { default: 0, min: 0, max: 99, step: 1 } # 100 samples
scenario_seed: &scenario_seed { formula: (seed + 31) * seed } # Variable-dependent
people_count: &people_count
type: GeometricVariable # A variable scanning a space with geometric segmentation
parameters: [300, 50, 500, 9] # default 300, minimum 50, maximum 100, 9 samples
seeds: { simulation: *seed, scenario: *scenario_seed}
export:
type: CSVExporter
parameters:
fileNameRoot: "snippet-variables-export"
data:
- time
- molecule: "default_module:default_program"
aggregators: [ mean, max, min, variance, median ] # From Apache's UnivariateStatistic
value-filter: onlyfinite # discards NaN and Infinity
environment: { type: ImageEnvironment, parameters: [*image_path, *zoom] }
network-model: { type: ObstaclesBreakConnection, parameters: [50] }
deployments:
type: Rectangle
parameters: [*people_count, 62, 15, 95, 200]
programs:
- time-distribution: 1
program: >
import protelis:coord:spreading
let source = [110, 325]
let vector = self.getCoordinates() - source
let distance = hypot(vector.get(0), vector.get(1))
distanceTo(distance < 50)
- program: send
- { type: Event, time-distribution: 1, actions: { type: LevyWalk, parameters: [*walk-speed] } }