Docs / AI Agents / Expression Schema

Expression Schema

The canonical JSON Schema for the Modellus expression language — the LaTeX-based mathematical notation used inside Expression shapes. Covers statement types, operator precedence, built-in functions, and AST node definitions.

View the full Expression Schema JSON — JSON Schema (Draft-07), 1480 lines.

Overview

The expression field of each ExpressionShape stores a \displaylines{} LaTeX block. Lines are separated by \\. Each line is parsed as one statement by the LatexMath grammar.

Statement Types

KindPatternTerm Type Produced
differential\frac{dx}{dt} = exprDIFFERENTIAL — requires initial value
functionname = exprPARAMETER (constant RHS) or FUNCTION (depends on other terms)
functionSubscriptx_{n} = f(x_{n-1})RECURRENCE — discrete-time iteration
functionSubscriptDigitx_0 = valuePARAMETER — initial/reference value
functionIndependentf(t) = exprFUNCTION — explicit argument form
conditionalname = \begin{cases}...\end{cases}FUNCTION — piecewise definition (≥ 2 rows)
domainx \in {1,2,3}PARAMETER — a scalar restricted to the listed values
namedDomain\text{domain} Color = {\text{red},\text{green}}None — a declaration, never a term
displayexpr (no assignment)None — visual display only

Expression Nodes (AST)

The right-hand side of any statement is a MathExpr — a tree of these node types:

NodeDescriptionExample LaTeX
BinaryOpTwo operands with operator (+, -, ·, /)a + b
UnaryMinusNegation prefix-x
PowerExponentiationx^{2}
FractionDivision as \frac{}{}\frac{a}{b}
SqrtSquare root\sqrt{x}
FunctionCallBuilt-in function application\sin\left(x\right)
ComparisonRelational operatorx > 0
Logical\lor or \landa \lor b
TermReferenceReference to a named termv, \omega
NumberLiteralNumeric constant9.8
Constant\pi or e\pi
DeltaFinite difference operator\Delta x
SubscriptRefSubscript term accessx_{n-1}
AbsoluteAbsolute value bars|x|
EnumLiteralCategorical value of a declared domain; compares only\text{red}

Built-in Functions

CategoryFunctions
Trigonometric\sin, \cos, \tan, \cot, \sec, \csc
Inverse Trig\arcsin, \arccos, \arctan
Hyperbolic\sinh, \cosh, \tanh
Logarithmic\ln, \log
Two-argument\max(a,b), \min(a,b), \mod(a,b)
Utilitysign(x), rnd(x), irnd(x), int(x), round(x) — written with no backslash, and drawn upright: the editor writes them back as \mathrm{round}\left(x\right), which reads the same as the plain spelling
Other\det(x), \sqrt{x}

Operators & Precedence

PrecedenceOperatorsAssociativity
1 (lowest)\lor, \landLeft
2=, >, <, \ge, \le, \neqLeft
3+, -Left
4\cdot, /, implicit multiplicationLeft
5 (highest)^{}, ! (factorial), \sqrt{}Right

Factorial: Use postfix notation (n!). Factorial is intended for non-negative integer values.

Integral notation: LaTeX integral forms such as \int_{a}^{b} f\left(x\right)\,\mathrm{d}x are valid expression syntax. For integer-part behavior, use int(x).

Domains

A domain says which values a scalar term may take. x \in {1,2,3} leaves x a single selectable number: it does not make x a set, and it is not a true/false membership test. Constrain a term with \in; the = form means the same thing but is only read as a domain when the right-hand side is something no ordinary expression could be, so x={1} and x=Color stay assignments.

WrittenMeans
{1, 2, 3}Finite domain — exactly the values 1, 2 and 3
[1, 5]Continuous interval — every real value from 1 to 5
[1..5]Discrete inclusive range — {1, 2, 3, 4, 5}
[0..10..2]Discrete range with a step — {0, 2, 4, 6, 8, 10}
A \cup BUnion — a value belonging to A or to B
x \in DConstrains the scalar term x to the domain D

A comma between two bounds is a continuous interval and two dots are a discrete range, so [1,5] and [1..5] are different domains. A range is inclusive at both ends when the step reaches the endpoint: [0..10..3] is {0, 3, 6, 9}.

Every delimiter is read in four spellings — plain, sized, named and sized named — because the editor keeps whichever one was typed: \{ \}, \left\{ \right\}, \lbrace \rbrace, \left\lbrace \right\rbrace for braces, and likewise \lbrack \rbrack and \lparen \rparen for brackets and parentheses. Write the plain form; the others are accepted so a row keeps working whichever way it was written.

The principal example. x \in {1,2,3} \cup [6,7]x may equal 1, 2 or 3, or any real value in the closed interval from 6 to 7. Nothing between 3 and 6 is allowed.

At the top level of a domain a comma is a union operator too, so x = {1},{2},{3},[6..7] normalizes to x \in {1,2,3,6,7}. Commas inside a set, inside an interval and inside a function call keep their own meaning, so \max\left(a,b\right) is unaffected.

Categorical domains

Write categorical values as \text{red}, both where the domain is declared and where it is compared:

color \in {\text{red},\text{green},\text{blue}}
is\_red = \begin{cases}1 & color=\text{red}\\0 & \text{otherwise}\end{cases}

These values are enum literals, not references to terms called red or green, and they never appear in the term list. They compare with = and \neq and combine with \land, \lor and \lnot. Arithmetic on one is refused with a type diagnostic rather than treated as a number, and a value belonging to no declared domain is refused rather than read as a term.

Built-in domains

WrittenMeans
\mathbb{R}Every finite real value the engine can represent
\mathbb{Z}Integers, of either sign
\mathbb{N}Non-negative integers, zero included
\mathbb{B}{false, true}, stored as 0 and 1
\mathbb{Q}Accepted, but behaves exactly like \mathbb{R}: values are floating-point numbers, so exact rational membership cannot be decided

Named domains

\text{domain} Color = {\text{red},\text{green},\text{blue}}
foreground \in Color
background \in Color

The keyword is the word domain, written \text{domain} so the editor draws it upright. A named domain is a declaration, never a calculation term: it never appears in the term list, in the value rows or on a plot. It resolves globally, works inside a union, and may not be defined in terms of itself.

Choosing a value at random

Assigned to a constrained term, rnd reads its argument as a count of domain values rather than as an upper bound:

z \in {\text{green},\text{blue},\text{red}}
z = rnd\left(3\right)

z becomes one of the three labels, each equally likely; rnd\left(2\right) would only ever choose green or blue, because the argument counts from the start of the domain in declared order. This is the only way to pick a categorical value at random — the numbers the labels are stored as are internal and must never be written into a model. It works the same for a numeric domain: n \in [0..10..2] with n = rnd\left(6\right) picks one of 0, 2, 4, 6, 8, 10.

Everywhere else rnd keeps its usual meaning, a number between 0 and its argument: when the term has no domain, when the domain is infinite, and when rnd is only part of the assigned expression as in m = n + rnd\left(3\right). irnd is unchanged.

Initial values and enforcement

A constrained term starts on an explicitly supplied initial value when the domain accepts it, otherwise on the first value of a finite domain, the start of a range, the lower bound of an interval, 0 for the numeric built-ins and false for \mathbb{B}. Values are never clamped or rounded: an update outside the domain is refused and a computed term that leaves its domain becomes undefined for that step, each with a DOMAIN_VIOLATION diagnostic naming the term, the rejected value and the domain.

A term constrained to a set of labels is edited by its labels everywhere the user meets it: the scenarios table and the table of values show green rather than the number behind it, and a cell is changed by choosing from the list of the domain's values instead of by typing.

LaTeX Templates

The schema includes a latexTemplates section providing ready-to-use LaTeX strings for common patterns that agents can emit directly into expression fields.

Name Tokens

Term names follow two patterns: