SimLang Language
SimLang is a system dynamics-inspired modeling language created by Forio.
SimLang is designed for time-based models. Therefore, a project with a SimLang model has access to several operations that advance the model through time (e.g., step). Each step recalculates the model state.
A SimLang model is written as an equations file (*.eqn) that describes external conditions, user decisions, and the relationships between them. The EQN file can contain three types of elements in any order: decisions, variables, and properties. Each element is identified by a single-letter prefix.
Decision and variable definitions can include function calls, operators, loops, and conditionals.
In a SimLang model, you do not define your own functions. All functions used in the definition of a decision or variable are built into the language.
For a reference on the built-in functions, read SimLang Functions.
Decisions and variables
Decisions
A decision is a model element subject to end-user control. It is prefixed with D. Its equation sets the default value, calculated at the start of the simulation. After that, it takes its value from user input — unless the recalculate operation is called to reset it to its equation.
D Initial Savings = 5000
D Interest Rate = 10%
D Yearly Deposits = 1000
In your Epicenter application, decisions are typically bound to inputs such as sliders, text fields, or radio groups.
Variables
A variable is a model element prefixed with V. Its equation is automatically recalculated at every time step. A variable can also accept user input, but once set by the user it will not recalculate at each step until recalculate is explicitly called.
V Interest = Previous Year Savings * Interest Rate
V Total Savings = Previous Year Savings + Interest + Yearly Deposits
In your Epicenter application, variables are typically displayed using output elements such as line charts, results tables, or inline text.
Naming convention
The names of both decisions and variables must start with a letter. They can contain uppercase letters, lowercase letters, spaces, and numbers. Often, SimLang models follow the traditional system-dynamics convention of using multi-word variable names with spaces.
Scalers
Many decisions and variables are scalars, that is, single values. Scalar decisions and variables can be strings, boolean values, any kind of number (integers, floating-point), or mathematical formulas or equations.
Arrays
Arrays are sets of values that use the same equations. Both decisions and variables can be arrays.
To define a variable or decision as an array, you must specify both an equation and a range. To define a range, prefix if with an R.
For example, a sales model might have the variables Sales and Revenue, and the decision Price, each of which is split among Books, CDs, and Games. To define these, use an enumerated range.
Enumerated ranges
Enumerated ranges define meaningful labels for array dimensions:
R Products = Books, CDs, Games
D Price[Products] = {100, 150, 175}
Numeric ranges
Numeric ranges use a count or start..end notation (1-based):
D Price[3] = {100, 150, 175}
V Sales[1..3] = {100, 200, 150}
Multidimensional arrays
Multidimensional arrays use a comma in the range:
V MySales[5, 2] = {{100, 200}, {100, 200}, {100, 200}, {100, 200}, {100, 200}}
Default values
Default values simplify large array initialization:
# Define an array with 1st element 100, 2nd element 200, and all other elements 1000.
V MySales[10] = {100, 200, Default: 1000}
# Define an array with 5th element 100, 2nd element 200, and all other elements 1000.
V MySales[10] = {5: 100, 2: 200, Default: 1000}
# Define an array and set Pencils to 100, all other elements to 200.
R Products = Pencils, Markers, Crayons
V Sales[Products] = {Pencils: 100, Default: 200}
# Define an array and set the first five elements to 1000, and all other elements to 6000.
V MySales[10] = {1..5: 1000, Default: 6000}
Using expressions
Any array definition can include an expression:
V Other Sales[1..2] = {New Sales, New Sales + Repeat Sales}
You can also use a FOREACH loop to apply an expression to each array element:
# These two definitions are equivalent
V NewSales[10] = FOREACH(item, 10, item * 10)
V NewSales[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100}
Referencing arrays
You can define an array using another array of the same dimensions in an equation. For example:
R Products = Books, CDs, Games
D Price[Products] = {100, 150, 175}
V Sales[Products] = {100, 200, 150}
V Revenue[Products] = Sales * Price
Equations can also refer to individual elements of an array, either by numeric index or by enumerated index:
V MyBookProfit = Revenue[Books] - Cost[Books]
V Demand = NewSales[1]
You can also reference sub-dimensions:
V X[5, 2] = {{100, 200}, {100, 200}, {100, 200}, {100, 200}, {100, 200}}
# Y is a one-dimensional array of two elements
V Y[2] = X[1, *]
# Z is a two-dimensional array, but with three rows instead of five
V Z[3, 2] = X[1..3, *]
Array definitions can refer to themselves in equations, as long as they do not cause a circular reference error:
V Fib[1..5] = {1, 1, Fib[1] + Fib[2], Fib[2] + Fib[3], Fib[3] + Fib[4]}
Combining arrays
To combine arrays with different dimensions:
Often, you may want to combine arrays of different ranges. The way to do this is with a FOREACH statement.
R Products = Books, CDs, Games
R Market Segments = 1..2
V Market Size[Market Segments] = {1000, 2000}
V Market Share[Products, Market Segments] =
{{20%, 30%}, {22%, 33%}, {44%, 46%}}
V Our Market[Products, Market Segments] =
FOREACH(p, Products,
FOREACH(m, Market Segments,
Market Share[p, m] * Market Size[m]
)
)
The equation for Our Market is arrayed over Products and Market Segments. The two FOREACH statements construct that array, applying the given expression to each new array item. This can be expressed in English as "For each product p and each market segment m in the result, the equation is Market Share[p, m] multiplied by Market Size[m]".
Properties
Properties configure overall model behavior. Model-level properties are prefixed with M and can appear anywhere in the EQN file. Variable-level properties are prefixed with P and must appear after the variable they configure.
M StartTime = 2010
M EndTime = 2020
M TimeStep = 1
D Price = 100
P Price.ExecuteDecisionImmediately = false
The following properties are supported in SimLang on Epicenter:
| Property | Scope | Default | Description |
|---|---|---|---|
StartTime | Model | 0 | Starting time of the simulation |
EndTime | Model | 10 | Final time of the simulation |
TimeStep | Model | 1 | Time units advanced per step() call |
InitialSteps | Model | 0 | Steps to auto-advance on initialization |
ExecuteDecisionImmediately | Model or Decision | true | If true, a new decision value immediately affects variables |
ResetDecision | Model or Decision | false | If true, decisions reset to their equation value after each step |
Control flow
Models written in SimLang don't have control flow in the same sense as, say, a Julia or Python program does. However, within a variable or decision equation, you can use control flow in the form of conditionals and loops.
IF
Chooses a value conditionally:
V Profitable = IF(Profit > 0, true, false)
FOREACH
Loops over a range to build an array:
V NewSales[10] = FOREACH(item, 10, item * 10)