nextmv Docs

How Dash Dashes

How Dash Dashes

Dash projects what the future might look like for a given system using Discrete Event Simulation (DES). This section introduces some of the basic mechanics of how Dash works and how it represents the world. It does not cover simulation as a field. There are many excellent references that provide a thorough foundation in simulation, including the following text.

Averill M. Law. Simulation Modeling and Analysis. 5th ed. McGraw-Hill, 2014.

Simulator Mechanics

Dash is a simulation engine that runs a given model using a single set of inputs. This estimates how a single scenario might play out. Comparing different models or scenarios requires running multiple, often many, simulations.

At a high level, Dash reads JSON input describing the state of a system and constructs actors based on that state. It then simulates the behaviors and interactions of those actors through events. Actors maintain state and record measurements of values important to the system. In order to leverage this simulation engine, Dash requires the modeler to define actors and their decision and communication logic.

Dash provides a simulator type which is responsible for stepping through simulated time, scheduling actors, passing messages in the form of events, and tracking output measures the modeler wants from a simulation. To do this, a Dash simulator requires one or more actors.

An actor is a model-specific structure with a Run method. Dash calls Run with the current simulation time whenever an actor is next scheduled. The actor should then update its state based on the current simulation time and any events it has received, and return the next time it should be run and a boolean indicator stating whether it has anything left to do in the simulation.

Dash always runs the earliest scheduled actor first. Actors are scheduled when they are first added to a simulation, then by subsequent calls to their Run methods. These times must always move forward and never backward, otherwise history could be rewritten. Dash runs simulations until either there are no more actors left or it meets a simulated time duration limit.

How Dash Fits In

Similarly to Hop, once the modeler has codified actors and their guiding decision and communication rules, it's time to integrate with existing production systems. Typical Dash integration architecture involves real-time data flowing through to an "iteration wrapper," which is responsible for calling the Dash engine using the desired option settings. The wrapper will run Dash for n iterations and store the KPI performance from each run. A separate analysis process will typically receive the simulated KPIs, analyze performance against actuals, and recommend changes. This integration flow enables rapid, targeted experimentation without the operational risks typically involved in real-world experimentation.

dash-fits-in

Example: Single-Server Queue

Consider the single-server queue example. This model simulates an ordered set of customers entering a line and waiting for service. One server processes customers in a first-in-first-out manner. The primary measurement provided by the simulation is customer wait time in the queue.

There are a number of ways to model such a system. Using Dash, the most natural method is to represent customers and the server as actors. These actors maintain internal state and use events to signal and trigger state transitions. Let's walk through an example of what that looks like.

Say we are simulating two customers, with arrival time as the number of minutes after the start of the simulation that the customer arrives, and the service time being the time required to service them:

CustomerArrival TimeService Time
003
1110

At the start of the simulation, no customer has arrived and the server is idle. We have the following actor states:

ActorStateAttributes
ServerIdleQueue: []

At time 0, Dash calls customer 0's Run method, which publishes an arrival event. The server, subscribing to that event, adds customer 0 to their queue. Customer 0's arrival time is the current time in the simulation.

ActorStateAttributes
ServerIdleQueue: [Customer 0]
Customer 0WaitingArrival: 0

Dash then runs the server, which publishes a service event for customer 0. Since customer 0's service time is 3, the server is now busy for 3 minutes. Customer 0 does not have to wait in the queue for service, so their arrival and service times are the same. Customer 0 publishes a wait time measurement of 0. This results in the following states, still at simulation time 0:

ActorStateAttributes
ServerBusyQueue: []
Customer 0In ServiceArrival: 0, Service 0

Customer 1 arrives at time 1. The server is busy, so they wait to be served.

ActorStateAttributes
ServerBusyQueue: [Customer 1]
Customer 0In ServiceArrival: 0, Service 0
Customer 1WaitingArrival: 1

At time 3, the server finishes serving customer 0 and starts serving customer 1. Customer 1 publishes a wait time measurement of 2. Customer 0 exits the simulation.

ActorStateAttributes
ServerBusyQueue: []
Customer 1In ServiceArrival: 1, Service: 3

Finally, the server finishes with customer 1 at time 13 and they exit the simulation.

ActorStateAttributes
ServerIdleQueue: []

The tables above show the states of actors in our simulation. We can also examine the event log, which is maintained and made available by Dash. Events are just data, and can have attributes like actors.

TimePublisherEventAttributes
0Customer 0ArrivalCustomer: 0
0ServerServiceCustomer: 0
1Customer 1ArrivalCustomer: 1
3ServerServerCustomer: 1

The measure ledger for our example has just two records.

MeasurerMeasurementValue
Customer 0Wait Time0
Customer 1Wait Time2

These events make it possible to replay exactly what happens in the simulation, and how wait time measurements can be computed directly from them. It is fairly simple to add additional events and measures, such as customer departures and total time in the system.