Equations and Formulas

The diagram of a model defines its structure: which stocks, flows, and variables exist and how they are connected. Equations define how each of those parts behaves. Every valued primitive (a Stock, Flow, Variable, or Converter) has an equation that Insight Maker evaluates as the simulation runs.

The equation editor allows you to type in an equation. On the right of the editor are a list of primitives this primitive can reference and a list of functions built into Insight Maker. You can click on one of these to insert it into the equation.

Basic Arithmetic

At their simplest, equations are arithmetic. Insight Maker supports the standard mathematical operators:

Operator Meaning Example Result
+ Addition 1 + 2 3
- Subtraction 5 - 2 3
* Multiplication 2 * 3 6
/ Division 9 / 3 3
^ Exponentiation 2^4 16
mod Remainder 13 mod 5 3

Operators follow the standard order of operations: exponents bind tighter than multiplication and division, which bind tighter than addition and subtraction. Try removing the parentheses in the second example below to see the result change:

2 + 3 * 4^2
(2 + 3) * 4^2

Numbers may be written with decimals (3.14), or in scientific notation (1.5e3 is 1,500):

1.5e3 + 1

Referencing Other Primitives

Equations become models when they reference other primitives. Square brackets refer to the value of another primitive in your model:

Sin(Years()*2) + [Rain Flow]^0.05

This example displays a number of features that the Insight Maker equation engine supports:

  • Years refers to the current simulation time as measured in years.
  • [Rain Flow] refers to the value of another primitive. Primitives can reference each other using this square-bracket notation.
  • Sin applies the trigonometric sine function.
  • +, *, and ^ are all standard mathematical operators representing addition, multiplication and exponentiation respectively.

A primitive can only reference primitives it is connected to. You can connect primitives using Links. Flows are automatically connected to the stocks they fill and drain.

In the model below, the Births flow references both the Population stock and the Birth Rate variable, and Deaths does the same with Death Rate. Try changing either rate:

{ "engine": "SIMULATION_PACKAGE", "name": "Population Growth Model", "simulation": { "algorithm": "RK1", "time_start": 0, "time_length": 50, "time_step": 0.5, "time_units": "YEARS" }, "elements": [ { "type": "STOCK", "name": "Population", "behavior": { "initial_value": "1000", "non_negative": true } }, { "type": "VARIABLE", "name": "Birth Rate", "behavior": { "value": "0.03" }, "display": { "interactive": true, "interactive_min": 0, "interactive_max": 0.06 } }, { "type": "VARIABLE", "name": "Death Rate", "behavior": { "value": "0.01" }, "display": { "interactive": true, "interactive_min": 0, "interactive_max": 0.06 } }, { "type": "FLOW", "name": "Births", "from": null, "to": "Population", "behavior": { "value": "[Population] * [Birth Rate]", "non_negative": true } }, { "type": "FLOW", "name": "Deaths", "from": "Population", "to": null, "behavior": { "value": "[Population] * [Death Rate]", "non_negative": true } }, { "type": "LINK", "from": "Birth Rate", "to": "Births" }, { "type": "LINK", "from": "Death Rate", "to": "Deaths" } ], "visualizations": [ { "name": "Population", "type": "TIME_SERIES", "elements": [ "Population" ] }, { "name": "Births", "type": "TIME_SERIES", "elements": [ "Births" ] }, { "name": "Deaths", "type": "TIME_SERIES", "elements": [ "Deaths" ] } ] }

Comparisons and Logic

Equations can compare values and combine the results with logical operators. Comparisons return the Boolean values true or false:

Operator Meaning
= Equal to
<> or != Not equal to
<, > Less than, greater than
<=, >= Less than or equal, greater than or equal
and True if both sides are true
or True if either side is true
not Inverts a Boolean
10 > 5
10 >= 10 and 2 < 1
not (1 = 2)

When used in arithmetic, true is treated as 1 and false as 0, which is useful for switching terms of an equation on and off.

Making Decisions

The IfThenElse function selects between two values based on a condition:

IfThenElse(20 > 10, "High", "Low")

For more complex logic, Insight Maker also supports multi-line If-Then-Else statements with as many Else If clauses as you need:

temperature <- 22 If temperature > 25 Then "Hot" Else If temperature < 15 Then "Cold" Else "Moderate" End If

See Advanced Equations for the full set of programming constructs including loops, error handling, and object-oriented programming.

Built-in Functions

Insight Maker includes a large library of built-in functions for mathematics, statistics, time, randomness, vectors, strings, and agent-based modeling. A few examples:

Round(3.6)
Sqrt(16) + Factorial(5)

Function names, like other variables in Insight Maker equations, are case-insensitive: Round, round, and ROUND are the same function. The complete function list, with descriptions and examples, is in the Built-in Functions reference.

Vectors

Vectors collect multiple values in a single value. They are important to vectorized models and agent-based modeling:

Mean({12, 9, 14, 8})

See the Vectors documentation for a more on working with vectors.

Time in Equations

Insight Maker re-evaluates equations at every step of the simulation, not just once.

The following equations are time-dependent and will return different results and different points in the simulation:

Years()
IfThenElse(Time() > {7 Years}, 1, 0)

Various functions can help you work with time. For instance Step for sudden changes, Ramp for gradual ones, Pulse for one-off or repeating spikes, and Seasonal for annual cycles:

Step({10 Years}, 5)
Ramp({5 Years}, {15 Years}, 100)
Pulse({5 Years}, 10, 1, {5 Years})
{"time_units": "MONTHS", "time_length": 36} Seasonal({6 Months})

Randomness

Random number functions let you model uncertainty. Rand() returns a uniform random number between 0 and 1 (or between a minimum and maximum you provide), and functions like RandNormal, RandTriangular, and RandPoisson draw from other distributions. Because equations are re-evaluated each time step, a random function produces a new value at every step:

RandNormal(10, 1)

Use SetRandSeed() in your model's Macros to make random simulations reproducible, and see Sensitivity Testing for running many random simulations to understand the resulting distribution of outcomes.

Units

You may also use units within equations. You can add units to a number by surrounding the number and units with curly brackets "{" "}". Insight Maker automatically converts between compatible units and reports an error if your equations combine incompatible units:

{1 kilometer} + {100 meters}
{2000 Liters} / {25 Liters/Minute}

The Units documentation covers units in depth, including how to declare them on the primitives of a model.

Multi-line Equations

An equation may span multiple lines. Intermediate results can be stored in local variables with the <- operator, and the value of the last statement is the result of the equation (you can also use an explicit return statement):

principal <- 1000 rate <- 0.05 years <- 10 principal * (1 + rate)^years

Local variables exist only within the equation being evaluated. To share values or functions across all the equations in a model, use Macros and Globals.

Defining Your Own Functions

You can define reusable functions directly within an equation. A single-line form:

double(x) <- x * 2 double(21)

And a multi-line form:

Function Square(x) x^2 End Function Square(5)

Functions defined in an equation are local to that equation. Define them in your model's Macros to make them available throughout the model. Learn about more capabilities in the Advanced Equations section.