The Ferryman
A wild river, one boat only, and a patient ferryman transporting batches of passengers across the body of water.
Covers:
Stanhope Forbes - A Ferryman at Flushing (oil on canvas, CC0 1.0)
Simulation
To form groups of passengers before passing the waters, we use batch()
in the ferryman's process definition. It has multiple arguments:
- A mandatory queue with elements of type
<T>
to be consumed - The size of the batch to be created. A positive integer is expected here.
- An optional timeout describing how long it shall wait before forming an incomplete/empty batch
batch
will return a list of type <T>
of size batchSize
or lesser (and potentially even empty) if timed out before filling the batch.
////Ferryman.kts
package org.kalasim.examples
import org.kalasim.*
import org.kalasim.monitors.NumericStatisticMonitor
import org.kalasim.plot.kravis.display
import kotlin.time.Duration.Companion.minutes
createSimulation {
class Passenger : Component()
val fm = object : Component("ferryman") {
val left2Right = ComponentQueue<Passenger>()
val right2Left = ComponentQueue<Passenger>()
val l2rMonitor = NumericStatisticMonitor()
val r2lMonitor = NumericStatisticMonitor()
override fun process() = sequence {
val batchLR: List<Passenger> = batch(left2Right, 4, timeout = 10.minutes)
l2rMonitor.addValue(batchLR.size)
hold(5.minutes, description = "shipping ${batchLR.size} l2r")
val batchRL: List<Passenger> = batch(right2Left, 4, timeout = 10.minutes)
r2lMonitor.addValue(batchRL.size)
hold(5.minutes, description = "shipping ${batchRL.size} r2l")
// we could also use an infinite while loop instead of activate
activate(process = Component::process)
}
}
ComponentGenerator(uniform(0, 15).minutes) { Passenger() }
.addConsumer { fm.left2Right.add(it) }
ComponentGenerator(uniform(0, 12).minutes) { Passenger() }
.addConsumer { fm.right2Left.add(it) }
run(10000.minutes)
fm.l2rMonitor.display("Passengers left->right")
fm.r2lMonitor.display("Passengers right->left")
}
Analysis
The ferryman tries to max out his boat with 4 passengers, but after 10 minutes he will start anyway (even if the boat is entirely emtpy). kalasim
will suspend execution when using batch()
until timeout
or indefinitely (if timeout
is not set).
Since both banks have different arrival distributions, we observe different batch-size patterns:
Right→Left
Since passengers on the right bank arrive with a higher rate (that is shorter inter-arrival time between 0
and 12
), the ferry is usually packed with people. Only occasionally the ferryman traverses from left to right banks with less than 4 passengers.
Left→Right
Because of a slightly higher inter-arrival time (up to 15
minutes) on the left banks, it often happens that the ferry starts its journey across the river with some seats unoccupied. On average, just 3
seats are taken. However, at least during this simulation we did not encounter a passing with just the ferryman and his thoughts.