Draft Standard

Ribose Standard

•
1004(d) (draft 2026-10-31)
Plurimath specifications — Evaluation
Plurimath
Ribose Standard

Draft Standard

Warning for Drafts

This document is not a Ribose Standard. It is distributed for review and comment, and is subject to change without notice and may not be referred to as a Standard. Recipients of this draft are invited to submit, with their comments, notification of any relevant patent rights of which they are aware and to provide supporting documentation.





Foreword

General

This document is the fourth document of the Plurimath specifications series. It specifies evaluation: the computation of a numeric value for a formula tree against variable bindings, under a strict error contract.

The evaluator described here is implemented in the plurimath gem of the 0.11 series (Plurimath::Math::Evaluation). It evaluates arithmetic over the tree exactly as written: it never rewrites the tree, never rounds behind the caller’s back, and never returns a value that is not a real, finite number — the alternative is one of the typed errors. Uncertainty propagation is not part of this edition: the model of PM 1002 carries uncertainty nodes, this document’s evaluator does not compute with them, and the propagation rules will arrive in this document when they arrive in the implementation.

Documents in the series

Table 1 — Documents in the series
NumberTitleSubject
1001Math modelThe formula tree, the node classes, the registry, the rendering surfaces
1002Uncertainty modelThe uncertainty node, its categories, its encodings
1003Format interfacesThe readers and writers per format
1004EvaluationThis document: numeric evaluation of trees

Maintainers

This document is maintained by the Plurimath project at https://github.com/plurimath/plurimath.


Introduction

A formula tree is content until something computes with it. Evaluation is that step: given a tree and a set of bindings — names and their numeric values — the evaluator walks the tree, applies the operations its nodes denote, and yields one number, or refuses with a typed error naming exactly what stood in the way.

The design centre is the strict error contract. Arithmetic in general notation runs into division by zero, negative square roots, logarithms of non-positive numbers, overflowing magnitudes and unbound names. Many evaluators answer such cases with NaN, Infinity or a silent fallback; this one answers with a refusal. A result is always a real, finite number, and everything else is one of eight typed errors. The effect on callers is that a successful evaluation needs no hedging: the number returned is usable, and the errors can be handled each by name.

The evaluator is deliberately small. It evaluates arithmetic: addition, subtraction, multiplication, division, modulo, powers, negation, the function classes the model defines, and bounded iteration for the nary sum and product. It does not simplify, does not convert units, does not propagate uncertainty, and does not solve. Every one of those is a different contract with its own semantics; this document specifies the one the implementation carries.

EXAMPLE

The tree of x^2 + 1 with the binding x → 3. Expected outcome. the evaluation yields 10: the power evaluates to 9, the addition to 10, and the result is a real, finite number.

0.1  The design forces

  • One answer. Real finite number, or typed error — the evaluator never leaves the caller between the two.

  • As written. The tree is evaluated as the author wrote it: precedence, grouping and order respected, nothing rewritten.

  • Small surface. Arithmetic, functions, iteration, bindings — and nothing else. Every non-goal is stated, not implied.

  • Replayable. Determinism is the testability: the corpus freezes trees, bindings and outcomes, and drift is visible.

1  Scope

1.1  General

This document specifies evaluation of Plurimath formula trees:

  • the evaluator: its inputs, its contract, and the shape of its results;

  • the expression parser: the precedence that turns a tree’s linear reading into operations;

  • the arithmetic: every operation, its domain, and its exactness;

  • functions and their arguments;

  • bindings: keys, values, and the errors they raise;

  • bounded iteration for the nary sum and product;

  • the error contract: the eight typed errors and what each one means;

  • conformance of an implementation.

This document does not specify:

  • uncertainty propagation, combination or coverage computation — not implemented in this edition (see clause 12);

  • unit conversion or quantity arithmetic — the UnitsML series governs units, and evaluation works on numbers;

  • simplification, factorisation or any rewriting — the tree is evaluated as written;

  • the numeric contract of exact decimals in the data — CalConnect 36813 governs that, and this evaluator binds ordinary real numbers.

1.2  Relationship to the series

Table 2 — Relationship to the series
DocumentRelationship to this one
1001 Math modelsupplies the tree and the node classes this evaluator walks
1002 Uncertainty modelcarries uncertainty nodes; this evaluator does not compute with them in this edition
1003 Format interfacesdelivers the trees; evaluation is a consumer, not a boundary of that document

1.3  Audience

Implementers of Plurimath, applications embedding evaluation, and authors of the propagation rules to come.

2  Normative references

The following documents are referred to in the text in such a way that some or all of their content constitutes requirements of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.

PM 1001 (math model), of this series — the tree, the node classes and their operand orders.

PM 1002 (uncertainty model), of this series — the nodes this edition does not compute with.

CalConnect 36813 (numeric contract), of the UnitsML series — the exact-decimal discipline of the data, distinct from this evaluator’s binding values.

3  Terms and definitions

For the purposes of this document, the following terms and definitions apply.

For the purposes of this document, the following terms and definitions apply.

3.1 evaluator

the component that computes a numeric value for a tree against bindings

3.2 binding

a name and the real numeric value bound to it for one evaluation

3.3 bindings

the set of bindings an evaluation uses; keys are names, values are real numbers

3.4 name

the identifier a tree’s symbols denote for evaluation purposes

3.5 evaluation

one walk of the tree under one binding set, yielding a number or raising a typed error

3.6 typed error

one of the eight error classes of clause 11; the only failures evaluation produces

3.7 real, finite

the only successful results: a real number with finite value — never NaN, never an infinity

3.8 strict error contract

the rule that evaluation either returns such a result or raises; there is no third answer

3.9 iteration

the bounded evaluation of a nary sum or product over an integer index range

3.10 index

the iteration variable, temporarily bound while the body folds

3.11 shadowing

an index temporarily replacing an outer binding of the same name for the body’s evaluation

3.12 fold

the left-to-right accumulation of the body’s values under the iteration’s operation

3.13 backend

the arithmetic engine the evaluator’s folds delegate to; its operations are clause 7’s

3.14 step limit

the maximum range width an iteration accepts; behaviour pinned by the corpus

3.15 normalisation

the deterministic token preparation that makes implicit products explicit before parsing

3.16 fold order

the left-to-right (or right, for powers) application order within one precedence level

4  Conventions

4.1  General

Evaluations are written as: tree, bindings, result. Errors are written as their class names of clause 11 with the identifying data the message carries.

4.2  Examples

Examples carry an Expected outcome paragraph stating the number yielded or the error raised. Numbers in examples are exact where they are exact: a rational binding such as one third behaves as its exact value in every example that uses it.

4.3  Names

Names in examples (x, n, i) are the plain identifiers the trees carry. The mapping from a tree’s symbols to names is pinned by the corpus; this document treats names as the keys of the binding set.

5  The evaluator

5.1  The model

lml "1.0"

models Evaluation {

  class Evaluator {
    attribute tree, Formula[1]
    attribute bindings, Binding { cardinality 0..n }
  }

  class Binding {
    attribute name, Name[1]
    attribute value, RealNumber[1]
  }

  class Result {
    attribute value, RealNumber[1]
  }

  enum EvaluationError {
    value "division-by-zero"
    value "invalid-binding"
    value "invalid-binding-key"
    value "math-domain"
    value "missing-variable"
    value "non-finite-result"
    value "unsupported-expression"
  }
}
Figure 1

An evaluation is one Evaluator over one tree with zero or more bindings. Its success is one Result; its failure is one EvaluationError, raised as the corresponding class of clause 11.

5.2  The contract

The strict error contract, stated once and honoured everywhere below: an evaluation returns a real, finite number, or raises one of the typed errors. There is no NaN result, no infinite result, no silently skipped subtree, no partial evaluation.

EXAMPLE

An evaluation whose arithmetic would produce a division by zero inside a larger expression. Expected outcome. the whole evaluation raises DivisionByZeroError. No subtree value, no partial result and no default leaks; the caller sees the refusal and nothing else.

5.3  Determinism

The same tree and the same bindings produce the same result or the same error, in the same order of internal operations. Evaluation has no randomness, no parallelism and no environment sensitivity; the corpus replays it identically.

5.4  The tree is not modified

Evaluation reads the tree. Nothing in the tree changes — no annotation of computed values, no caching inside nodes, no rewrite. A tree evaluates twice identically, and an evaluated tree writes exactly as an unevaluated one.

5.5  Foreign exceptions become typed errors

The underlying arithmetic platform’s own signals — domain errors from the math library, float-domain failures, platform division failures — are caught at the evaluation boundary and re-raised as the corresponding typed errors: MathDomainError, NonFiniteResultError, DivisionByZeroError. A caller never sees a foreign exception from evaluation; the message text of the platform error, where one exists, travels inside the typed error.

5.6  The walk, in order

An evaluation proceeds:

  1. bindings validate at entry (clause 9) — nothing has run yet;

  2. the tree walks in writing order through the expression parser’s chain (clause 6);

  3. each node maps to an operation, a function call, an iteration, a name, or a leaf number;

  4. names resolve against the bindings at first use;

  5. folds apply clause 7’s arithmetic and clause 8’s functions, each result checked real-and-finite;

  6. the final value returns; any refusal along the way aborts with its typed error.

The order is observable through the errors: an expression with both a missing name and a division by zero reports whichever the walk reaches first. The corpus includes order-sensitive vectors so the ordering is tested, not implied.

5.7  Zero bindings

An evaluation with no bindings evaluates the closed part of the tree: a tree without names evaluates completely (2 + 3 * 4 yields 14 with no bindings); a tree with any name refuses at that name. Both are ordinary evaluations under the one contract.

5.8  The evaluator is reentrant

An Evaluator instance holds its tree and bindings and nothing mutable; evaluating twice, or evaluating from two callers, shares no state. Iteration’s temporary bindings are scoped to their body and restored on every exit path, including the error paths — an aborted iteration leaves the binding set as it found it.

6  The expression parser

6.1  General

A tree denotes operations in writing order, not in a flat list: 2 + 3 * 4 multiplies before it adds. The expression parser turns the evaluator’s node walk into that precedence-correct sequence of folds. It is a precedence-climbing parser over the tree’s linear reading, with one level per binding strength.

6.2  The precedence chain

The parser descends one chain, strictest last:

Table 3 — The precedence chain
LevelConstructsFolds to
relation=, ≠, comparisonsthe relation evaluation of clause 7
additive+, −addition and subtraction
multiplicativeimplicit products, /, modmultiplication, division, modulo
unarynegation, positive signnegation
powerx^y, right-associativepowers
operandnumbers, names, groups, functionsleaf evaluation or recursion
groupparenthesised contentrecursion with saved state

Each level parses the next as its operand and folds left-associatively within itself — powers excepted, which fold right-associatively: 232 is 2(32), the mathematical convention.

6.3  What the parser accepts

The parser accepts the arithmetic core the evaluator evaluates: numbers, bound names, the operations above, groups, and the function and iteration calls of clauses 8 and 10. A node outside this core — a Text node, a matrix, an uncertainty node — makes the whole evaluation raise UnsupportedExpressionError: the evaluator does not evaluate what it does not define, and never guesses.

EXAMPLE 1

The tree of 2 + 3 * 4. Expected outcome. the parser folds the multiplicative level first (yielding 12) and the additive level second (yielding 14), regardless of the walk order the tree’s linear reading might suggest.

EXAMPLE 2

The tree of 232. Expected outcome. 512 — the right-associative reading — not 64.

6.4  Groups

A group saves the parser’s pending state, evaluates its content to one value, and presents that value as an operand. Groups are the author’s precedence: 2 * (3 + 4) yields 14, not 10.

6.5  Relations

The relation level evaluates comparisons to truth values in the platform’s terms. A tree whose top level is a relation yields that relation’s result; relations compose left-associatively where the tree carries chains. The corpus pins the truth-value results alongside the numeric ones — both are results of the one contract.

6.6  Token normalisation

Before parsing, the tree’s linear tokens normalise: implicit products are marked (2x becomes 2 * x, a(x + 1) becomes multiplication, x sin y stays two operands), explicit multiplication symbols map to the same fold, and spacing is irrelevant. Normalisation is deterministic and pinned by the corpus; it changes no node, only the fold sequence.

6.7  Function calls in the chain

A function call parses as a prefix at the operand level: the function name, then its argument or arguments as the grammar of the construct gives them — parenthesised, braced, or by adjacency for the notation’s single-argument forms. The argument expressions parse at the full chain, so log_2 x^3 binds the power inside the argument where the notation’s grouping says so; the corpus carries the ambiguous-looking cases explicitly.

7  Arithmetic

7.1  The operations

The evaluator’s operations, their names, and their domains:

Table 4 — The arithmetic
OperationNotation in the treeDomain
additiona + breals
subtractiona − breals
multiplicationa * b, a b (implicit)reals
divisiona / breals, b ≠ 0
moduloa mod breals per the platform’s modulo
powera^bper clause 7’s power rules
negation−areals
positive sign+areals

Every operation consumes real, finite values and produces one; the contract of clause 5 applies at each fold.

7.2  Division

Division by zero raises DivisionByZeroError — including division by an expression that evaluated to zero, however far away the zero came from. There is no limiting behaviour, no infinity: the contract has no place to put one.

7.3  Modulo

Modulo follows the platform’s modulo semantics for real operands; a zero divisor raises DivisionByZeroError. The sign behaviour is the platform’s and the corpus pins it.

7.4  Powers

The power operation evaluates a^b for the domains the real numbers define: a positive base with any real exponent, a zero base with a positive exponent, a negative base only where the exponent is an integer or a rational with an odd denominator in lowest terms. Outside those domains the platform’s domain error becomes MathDomainError. An exponent that would produce a non-finite magnitude raises NonFiniteResultError at the boundary.

EXAMPLE 1

2^10, 9^(1/2), (−8)^(1/3). Expected outcome. 1024; 3; −2 — the real cube root, in the odd-denominator domain.

EXAMPLE 2

(−2)^(1/2) and 0^(−1). Expected outcome. MathDomainError for the first; DivisionByZeroError for the second — the platform’s reading of a zero base with a negative exponent.

7.5  Negation and sign

Negation flips the sign of its operand; a unary plus is the identity. Neither has side effects, and chains (−−x) negate once per sign as written.

7.6  Results

Every fold’s result passes the real-and-finite check before it feeds the next. A non-finite intermediate — an overflow inside the platform’s numbers — aborts the whole evaluation with NonFiniteResultError rather than propagating a poisoned value.

7.7  Implicit products

Adjacency means multiplication where the notation puts values side by side: a number before a name, a name before a group, a group before a group. It does not mean multiplication between two numbers (2 3 is not a valid product — the corpus refuses it as a token fault) nor between a name and the keyword introducing an iteration. The normalisation of clause 6 makes every implicit product explicit before folding.

7.8  Accuracy classes

Every value an evaluation carries belongs to an accuracy class. Integers and rationals are exact: their add, subtract, multiply and rational division are exact operations, and an exact operand list yields an exact result. Floats are limited with undeclared accuracy (the platform’s bits); guard-digit decimals are limited to their declared precision. Limited operands contaminate exact ones: the accuracy of an operation’s result is the accuracy of its least precise operand. A five-digit value times a six-digit value is defined to five digits — the class algebra states this, the corpus vectors pin it.

7.9  Boundaries

A boundary is an operation that would replace exact values with platform approximations: a transcendental function, an irrational root, a non-exact power on exact operands. The evaluator processes until a boundary and never violates one silently — every crossing is reported.

7.10  Modes

The caller chooses the mode at the entry point; the default is approximate.

  • Approximate mode crosses every boundary: the computation runs on platform floats, and the result reports each boundary it crossed — the operation, the operands and their accuracy classes, and the produced value. This is the mode of the original contract: whatever the platform computes is delivered as computed, refused when not real-and-finite, never silently rounded. The corpus records its expected values, platform and version pinned.

  • Strict mode never crosses an exactness boundary: the first boundary defers the evaluation. The result then carries no value, the boundary record, and the unevaluated expression in source form — a partially evaluated result whose accuracy is undiminished, which the caller can re-run in approximate mode or with declared guard digits. Limited operands degrade as defined: a transcendental over a limited value computes without deferring, since there is no exactness left to lose.

  • Guard digits extend strict mode: with a declared digit count, a boundary is crossed by computing a decimal result to that declared precision (an exact rational square root stays exact without any declaration). Functions without a guard-digit implementation are refused with a typed error naming the function.

Exact vectors — whole expressions evaluated without a crossed boundary — are byte-identical across runtimes: their results are integers and rationals, not platform values. The exact-decimal discipline of the data layer (CalConnect 36813) is the same discipline strict mode evaluates under.

7.11  Results

Evaluation returns a result object, not a bare number: the value, the ordered boundary records (operation, operands, operand accuracy, action — approximated, guarded or deferred — and the produced value), and the unevaluated expressions when strict mode deferred. A result whose boundaries contain no approximation is exact; a deferred result carries the residual expression.

7.12  Order of folds

Left-associative levels fold left: a − b − c is (a − b) − c, and a / b / c is (a / b) / c. Right-associativity belongs to powers alone. The distinction is observable in floating point even when exact arithmetic would agree; the corpus pins the fold order with vectors whose inputs differ by association.

7.13  A precedence walk, concretely

The tree of −3 + 4 * 2^2 / (1 + 1):

  1. the group folds first: 1 + 1 yields 2;

  2. the power: 2^2 yields 4;

  3. the multiplicative level folds left: 4 * 4 yields 16, then 16 / 2 yields 8;

  4. the unary level negates 3 to −3 for its operand;

  5. the additive level folds: −3 + 8 yields 5.

Expected outcome. 5 — each level once, in the chain’s order, with the group overriding the written order.

8  Functions

8.1  The function classes

The evaluator evaluates the function classes the model defines where a numeric semantics exists: the trigonometric and hyperbolic functions and their inverses, the logarithms (ln, lg, log with a base), the exponential, the absolute value, floor and ceiling, min and max, and the named constants of the registry where the platform defines their values.

Table 5 — Function evaluation
FamilyEvaluationDomain refusals
trigonometricper the platformnone; results checked real and finite
inverse trigonometricper the platformargument outside [−1, 1] → MathDomainError
hyperbolicper the platformoverflow → NonFiniteResultError
logarithmsln, lg, log_bnon-positive argument → MathDomainError; base ≤ 0 or base 1 → MathDomainError
exponentialper the platformoverflow → NonFiniteResultError
absabsolute valuenone
floor, ceilper the platformnone
min, maxover the argumentsnone

8.2  Arguments

A function’s arguments are its operands, evaluated left to right as ordinary sub-evaluations. The argument count is the class-defined arity of PM 1001; a tree that carries a different count is an UnsupportedExpressionError — the evaluator does not improvise signatures.

8.3  The logarithm base

log with a base evaluates to the logarithm in that base: log_2 8 yields 3 under exact arithmetic in the corpus. The one-argument form is the natural logarithm’s decadic sibling per the registry’s reading; the corpus pins which.

8.4  Constants

Registry constants with platform values (π, the exponential constant) evaluate to the platform’s value of that constant. Constants without one are names: they bind from the bindings or refuse with MissingVariableError, like any name.

EXAMPLE 1

The tree of log(x) with the binding x → 100 under the decadic reading. Expected outcome. 2 where the corpus fixes the decadic reading; the reading itself is pinned there, not negotiated per call.

EXAMPLE 2

The tree of sqrt(x) with x → −1. Expected outcome. MathDomainError — the square root of a negative number has no real value, and the contract has no complex numbers.

8.5  Nary calls and argument evaluation

The nary functions the evaluator defines (sum, prod with bounds) route to iteration (clause 10); the nary classes without bounds refuse as unsupported in this edition — a bare ∑ over a list has no evaluation semantics here. Argument sub-evaluations run through the same chain and contract; an error inside an argument aborts the whole call, and there is no argument-level recovery.

8.6  The log argument rule

The logarithm’s argument is the full expression the notation groups: log x + 1 is log(x) + 1 under the adjacency binding, and log(x + 1) is the logarithm of the sum. Where the writer’s shape and the reader’s grouping disagree, the tree is authority: the evaluator evaluates the tree it is given, and the corpus carries the disambiguated pairs.

8.7  Constants and names, precisely

A registry constant with a platform value evaluates without bindings; a name without one binds or refuses. The registry decides which is which, per PM 1001 — evaluation adds no constants of its own and treats an unknown constant exactly like any other name.

9  Bindings

9.1  The binding set

Bindings are the evaluation’s variables: a set of names, each with a real numeric value. Keys arrive as strings or symbols and normalise to strings; values must be real numbers.

9.2  Validation at entry

The binding set is validated before the tree is touched:

  1. a key that is neither a string nor a symbol raises InvalidBindingKeyError, carrying the key;

  2. a value that is not a real number raises InvalidBindingError, carrying the key and the value;

  3. duplicate keys after normalisation — :x and "x" together — collapse to one binding, the last one given.

An evaluation with an invalid binding refuses before any evaluation happens: the tree is not walked with a bad environment.

EXAMPLE 1

Bindings { x: 3, "y" => 4.5 }. Expected outcome. accepted; the names x and y bind 3 and 4.5.

EXAMPLE 2

The binding key 2 — a number offered as a name. Expected outcome. InvalidBindingKeyError carrying 2, raised before evaluation.

EXAMPLE 3

The binding x → "three". Expected outcome. InvalidBindingError carrying the key and the string: values must be real numbers, not their spellings.

9.3  Missing names

A name the tree mentions and the bindings lack raises MissingVariableError, carrying the name. The refusal happens at first use — evaluation does not pre-scan the tree for names, so an evaluation that dies early reports the first missing name it needed, not all of them.

9.4  Shadowing

The iteration index temporarily shadows an outer binding of the same name for the body’s evaluation and restores the outer binding afterwards (clause 10). Shadowing is scoped to the body: outside the iteration, the outer binding is untouched.

EXAMPLE

The tree of i + sum_(i=1)^3 i with the binding i → 10. Expected outcome. the outer i contributes 10; the iteration binds its own i over 1..3 and contributes 6; the result is 16. The outer binding survives the iteration unchanged.

9.5  The numeric types accepted

A binding value may be any real numeric type the platform offers — integers, rationals, floating-point numbers. The evaluator normalises nothing: an integer binding stays an integer in the arithmetic where the platform keeps it one, a rational stays exact while its operations do, and the corpus pins the type-observable outcomes (sum_(i=1)^3 i with an integer index folds in integers). Values that are complex, non-real or not numbers at all refuse per clause 9.

9.6  Name shape

A name is the identifier text a tree’s symbols carry for evaluation. Names are case-sensitive and exact: X and x are different bindings, and a binding for one does not serve the other. There are no reserved names — the iteration indexes are ordinary names that shadow per clause 10.

9.7  Binding once, evaluating many

An evaluation binds its names once, at entry. There is no rebinding during evaluation, no environment mutation from inside the tree, and no callback through which the tree could observe or alter its own bindings.

10  Iteration

10.1  The construct

The nary sum and product with explicit bounds — sum_(i=1)^n body, prod_(i=1)^n body — evaluate as bounded iteration: the index runs the integer range and the body’s values fold under the operation, starting from the operation’s identity.

10.2  The bounds

The lower bound parses as index = start and the upper as the end expression. Both evaluate to integers: a bound that evaluates to a non-integer or an infinite value raises the typed error of its cause (MathDomainError for a non-integer bound where the platform names it so, NonFiniteResultError for an infinite one). An empty range — a start above the end — yields the identity: the empty sum is 0, the empty product is 1.

10.3  The step limit

A range wider than the implementation’s step limit refuses with UnsupportedExpressionError: iteration is bounded by construction, and an unbounded or enormous range is a caller error, not a long computation.

10.4  The fold

The body evaluates once per index value, left to right, with the index bound; the values fold under the operation — addition for the sum, multiplication for the product — from the identity. The index binding shadows per clause 9 and restores after.

EXAMPLE 1

sum_(i=1)^4 i^2. Expected outcome. 30 — 1 + 4 + 9 + 16, each square evaluated with the index bound, folded in order.

EXAMPLE 2

prod_(i=1)^4 i — the factorial of 4 written as a product. Expected outcome. 24.

EXAMPLE 3

sum_(i=5)^4 i — an empty range. Expected outcome. 0, the addition identity; no error, no evaluation of the body.

10.5  The index definition, precisely

The lower bound parses as the two-part form name = start. The name becomes the index; anything else in the lower-bound position is an UnsupportedExpressionError. The start evaluates once, to an integer; a non-integer start refuses with the typed error the platform names for it.

10.6  Bounds validation

After the start, the upper bound evaluates once, to an integer. Validation is order-fixed: start first, end second, both integers, then the step limit. The error each check raises names its stage, so a caller with a malformed bound learns which one it was.

10.7  The step limit’s value

The implementation carries a fixed maximum range width; the corpus pins it as behaviour (a range one past it refuses, one within it runs). The limit exists so that sum_(i=1)109 — an infinite work order in the caller’s clothing — is a refusal the caller handles, not a hang they kill.

10.8  Nested iteration

A body may itself carry an iteration: the inner index shadows the outer for the inner body, and the ranges compose. The corpus carries nested vectors to fixed depth; the step limits apply per range.

11  The error contract

11.1  The eight errors

Table 6 — The typed errors of evaluation
ErrorRaised whenCarries
DivisionByZeroErrora division or modulo by an evaluated zeronothing beyond the platform’s message where one exists
InvalidBindingErrora binding value is not a real numberthe key and the value
InvalidBindingKeyErrora binding key is neither string nor symbolthe key
MathDomainErroran operation or function outside its real domainthe platform’s message
MissingVariableErrora name the tree needs is unboundthe name
NonFiniteResultErrora result or intermediate is not real-and-finitenothing
UnsupportedExpressionErrorthe tree contains a node evaluation does not definethe node
Errorthe base class—

Catching the base class catches them all; catching a subclass catches the specific refusal. The errors are the contract’s vocabulary: everything a caller can do about a refusal starts from one of these names.

11.2  Refusal points

Where each error can arise:

  1. bindings — InvalidBindingKeyError, InvalidBindingError, at entry;

  2. names — MissingVariableError, at first use;

  3. unsupported content — UnsupportedExpressionError, at the node;

  4. arithmetic and functions — DivisionByZeroError, MathDomainError, at the fold;

  5. the boundary — NonFiniteResultError, at every fold and at the end.

11.3  What the contract forbids

No default values for missing names, no complex-number escape hatch, no unsigned infinity, no NaN, no evaluation of part of a tree, no second chance. Each of those would turn a refusal the caller can handle into a value the caller must guess about — the contract prefers the refusal.

11.4  Messages

Message shapes are stable within an edition. The identifying data travels in the message: the missing name, the offending binding, the node class refused. The corpus pins the shapes with one vector per error.

11.5  Causes, not substitutes

Where a typed error wraps a platform exception, the platform’s error is the cause — preserved for diagnostics, never raised in its place. Callers match on the typed name; the cause answers “what exactly did the platform say”.

11.6  Catching guidance

Handle the specific errors you can act on: retry with corrected bindings for MissingVariableError, report the input for UnsupportedExpressionError, treat DivisionByZeroError and MathDomainError as mathematical facts about the input. Catching the base class is for the boundary of a long pipeline; everywhere else, the specific name is the better match, and the corpus holds a vector for each name.

11.7  Errors are results too

A refusal is a well-defined outcome, deterministic as any number: the same tree and bindings produce the same error with the same message. The evaluation corpus treats errors exactly like results — frozen, replayed, drift-checked — because a caller’s error handling is only as reliable as the errors are repeatable.

12  What this edition does not do

12.1  Uncertainty propagation

The model carries uncertainty nodes (PM 1002); this edition’s evaluator does not compute with them. An evaluation whose tree contains an uncertainty node refuses with UnsupportedExpressionError — the honest answer, rather than an arithmetic that quietly drops the uncertainty. The propagation rules — sensitivities, the propagation law, second-order terms, coverage — enter this document in the edition whose implementation carries them.

12.2  Simplification

The evaluator never rewrites the tree: no folding of constants into nodes, no canonicalisation of equivalent forms, no algebra. Evaluation is a reading of the tree, and two equal trees evaluate identically while two different trees evaluate as written even when their values coincide.

12.3  Units and quantities

Evaluation works on numbers. Unit conversions, quantity arithmetic and the absolute/difference typing of the UnitsML series are that series’ contracts; an evaluator applied to unit-bearing trees evaluates the numeric content as the bindings supply it and the units ride with the tree, unconverted.

12.4  Solving

No root-finding, no inversion, no symbolic manipulation. The evaluator answers one tree with one number, given complete bindings; everything else is a different tool.

12.5  Why the limits are stated

Each non-goal is a contract someone will eventually ask for. Stating them keeps the boundary honest: an evaluator that quietly simplified would surprise every caller who diffed two trees; one that silently propagated uncertainty would make reported results and computed results behave differently in the same expression; one that converted units would need the whole UnitsML typing inside arithmetic. The limits are the design; the clauses above are the contract they protect.

12.6  The road in

When propagation arrives, it arrives in this document: its operations, its error extensions if any, its corpus, its conformance class — the same structure this edition uses for arithmetic. The uncertainty nodes of PM 1002 were built to carry everything propagation will need: category, fields, exact decimals. Nothing in the model blocks the road; the evaluator simply has not walked it yet.

13  Conformance

13.1  General

Conformance to this document is the implementation of the evaluator per clauses 5 to 11. One class covers it, with the corpus as its evidence; a partial implementation claims nothing.

13.2  Conformance classes

Table 7 — Conformance classes
ClassLicenses the implementation to claimReplay requirements
evaluationevaluates trees against bindings per this documentthe evaluation corpus: results, errors, and message shapes, replayed identically

The claim carries the model claim of PM 1001: an evaluator over trees is an implementation of trees first.

13.3  The evaluation corpus

The corpus freezes, per entry: the tree (in a canonical reading), the bindings, and the outcome — the exact result or the typed error with its message shape. Entries come from this document’s examples first and from defect fixes and community reports as they arrive; a generation is immutable once published.

13.4  Drift

An implementation whose result or error differs from the corpus for the same tree and bindings does not conform. Floating-point-order differences that change results are drift: the corpus, not the platform, defines the expected values, and an implementation adjusts or the document moves an edition.

14  Annex A: precedence and operations

14.1  The precedence chain in full

Table 8 — Precedence, strictest binding last
LevelConstructsAssociativityFolds to
relation=, ≠, <, >, comparisonsleftrelation evaluation
additive+, −leftadd, subtract
multiplicativeimplicit product, *, /, modleftmultiply, divide, modulo
unary−, +prefixnegate, identity
power^rightpower
operandnumbers, names, groups, calls—leaf or recursion
groupparentheses—recursion

14.2  The operations in full

Table 9 — The arithmetic, normative summary
OperationResultRefusals
adda + bnon-finite intermediate
subtracta − bnon-finite intermediate
multiplya · bnon-finite intermediate
dividea / bzero divisor; non-finite
moduloplatform modulozero divisor
powera^b in the real domains of clause 7domain; non-finite
negate−anone
identityanone

14.3  Function domains, normative summary

Table 10 — Function refusals
FunctionRefusal domain
inverse trigonometricargument outside the closed interval of arcsine and arccosine
logarithmsargument ≤ 0; base ≤ 0 or base = 1
exponential, hyperbolicoverflow only
trigonometric, abs, floor, ceil, min, maxno domain refusals

Every refusal raises MathDomainError with the platform’s message; every overflow raises NonFiniteResultError.

15  Annex B: the error messages

Table 11 — Message shapes
ErrorMessage carries
DivisionByZeroErrorthe platform’s division message, where one exists
InvalidBindingErrorthe key, and the inspection of the rejected value
InvalidBindingKeyErrorthe inspection of the rejected key
MathDomainErrorthe platform’s domain message
MissingVariableErrorthe missing name, alone
NonFiniteResultErrornothing — the class is the message
UnsupportedExpressionErrorthe class of the refused node

One vector per row exists in the corpus, so an implementation’s messages are checked against the shapes, not against prose in this document.

15.1  Refusal vectors in the corpus

The message shapes of this annex carry one corpus vector each, plus: a missing name deep inside an iteration body (the name reported is the body’s first use), an unsupported node inside a group (the group does not shield it), and a non-finite intermediate inside an argument (refused at the argument, before the call). The corpus, not this annex, is the checkable form; this annex is its key.

16  Annex C: test-suite examples

Vectors illustrative of the evaluation corpus. Each states the tree, the bindings, and the outcome.

16.1  Results

EXAMPLE 1

x^2 + 1 with x → 3. Expected outcome. 10.

EXAMPLE 2

232. Expected outcome. 512 — right-associative powers.

EXAMPLE 3

(a + b) * (a − b) with a → 5, b → 2. Expected outcome. 21 — groups first, then the product.

EXAMPLE 4

sum_(i=1)^4 i^2. Expected outcome. 30.

EXAMPLE 5

prod_(i=1)^4 i. Expected outcome. 24.

EXAMPLE 6

sum_(i=5)^4 i. Expected outcome. 0 — the empty range, no error.

EXAMPLE 7

i + sum_(i=1)^3 i with i → 10. Expected outcome. 16 — shadowing scoped to the body; the outer binding survives.

16.2  Refusals

EXAMPLE 1

1/0 and x/(y − y) with any x, y bound. Expected outcome. DivisionByZeroError — the second through an evaluated zero.

EXAMPLE 2

sqrt(−1) written as a power (−2)^(1/2). Expected outcome. MathDomainError.

EXAMPLE 3

log(0). Expected outcome. MathDomainError.

EXAMPLE 4

x + 1 with no bindings. Expected outcome. MissingVariableError carrying x.

EXAMPLE 5

The tree of a text node: text("hello"). Expected outcome. UnsupportedExpressionError naming the node class.

EXAMPLE 6

A tree containing an uncertainty node (PM 1002). Expected outcome. UnsupportedExpressionError — clause 12’s rule, tested.

EXAMPLE 7

The binding x → "three". Expected outcome. InvalidBindingError with the key and value.

EXAMPLE 8

The binding key 2. Expected outcome. InvalidBindingKeyError with the key.

EXAMPLE 9

An exponentiation whose magnitude overflows the platform’s numbers. Expected outcome. NonFiniteResultError at the fold, not at the end — intermediate checks refuse early.

16.3  Determinism

EXAMPLE

The same tree and bindings evaluated twice, in one process and across processes. Expected outcome. the identical result or the identical error, every time; the corpus replays the whole set.

16.4  Precedence vectors

EXAMPLE 1

−3 + 4 * 2^2 / (1 + 1). Expected outcome. 5, per the walk of Annex A.

EXAMPLE 2

8 / 4 / 2. Expected outcome. 1 — left-associative division.

EXAMPLE 3

2 − 3 − 4. Expected outcome. −5 — left-associative subtraction, not 3.

16.5  Binding vectors

EXAMPLE 1

:x and "x" given together with different values. Expected outcome. one binding, the last given; the corpus pins which spelling survives.

EXAMPLE 2

A rational binding 1/3 in x * 3. Expected outcome. 1 — exact under the platform’s rational arithmetic, and the corpus states the type-observable result.

16.6  Iteration vectors

EXAMPLE 1

sum_(i=1)^n i with n → 0. Expected outcome. 0 — the empty range for a bound that evaluated to zero.

EXAMPLE 2

A range past the step limit. Expected outcome. UnsupportedExpressionError naming the iteration; the limit’s edge is a corpus vector on both sides.

17  Annex D: worked evaluations

Two evaluations end to end, from tree to outcome.

17.1  The quadratic discriminant

The tree of b^2 − 4ac, bindings b → −3, a → 1, c → 2.

  1. The power level: b^2 folds to 9.

  2. The multiplicative level: 4, a, c fold to 8 — implicit products fold left: 4·1 = 4, 4·2 = 8.

  3. The additive level: 9 − 8 folds to 1.

Expected outcome. 1. The discriminant is positive; nothing in this document says what that means — the caller reads their own mathematics into the number.

17.2  A series sum with shadowing

The tree of x_0 + sum_(n=1)^5 (n * x_0 / n) — a deliberately redundant form to exercise the machinery — bindings x_0 → 2.

  1. The iteration’s lower bound reads n = 1; the upper bound evaluates to 5; the range is 1..5.

  2. For each n in order, the body folds: the product n · 2 then the division by the bound n, yielding 2 each time — the index shadows nothing here (no outer n), but binds itself for the body.

  3. The five values fold additively from 0: 10.

  4. The additive level: 2 + 10.

Expected outcome. 12. The outer x_0 binding is untouched by the iteration; a second evaluation of the same tree with the same bindings yields 12 again, byte for byte.

17.3  What the walk-through shows

  • the precedence chain in action: powers, products, then the sum, then the addition;

  • the binding discipline: entry validation, use-time missing-name refusals, scoped index binding;

  • determinism as an observable property, not a promise.


Bibliography

[1]  Plurimath repository, — https://github.com/plurimath/plurimath

[2]  Plurimath::Math::Evaluation implementation, — the reference implementation of this document

[3]  PM 1001, of this series

[4]  PM 1002, of this series

[5]  PM 1003, of this series

[6]  JCGM 100:2008, INTERNATIONAL ORGANIZATION FOR STANDARDIZATION, ORGANISATION INTERNATIONALE DE NORMALISATION (ISO), INTERNATIONAL ELECTROTECHNICAL COMMISSION, COMMISSION ÉLECTROTECHNIQUE INTERNATIONALE (IEC), INTERNATIONAL ORGANIZATION OF LEGAL METROLOGY, ORGANISATION INTERNATIONALE DE MÉTROLOGIE LÉGALE (OIML), INTERNATIONAL UNION OF PURE AND APPLIED CHEMISTRY, UNION INTERNATIONALE DE CHIMIE PURE ET APPLIQUÉE (IUPAC), INTERNATIONAL UNION OF PURE AND APPLIED PHYSICS, UNION INTERNATIONALE DE PHYSIQUE PURE ET APPLIQUÉE (IUPAP), INTERNATIONAL FEDERATION OF CLINICAL CHEMISTRY AND LABORATORY MEDICINE, FÉDÉRATION INTERNATIONALE DE CHIMIE CLINIQUE ET DE BIOLOGIE MOLÉCULAIRE (IFCC), INTERNATIONAL LABORATORY ACCREDITATION COOPERATION, COOPÉRATION INTERNATIONALE D’ACCRÉDITATION DES LABORATOIRES (ILAC), and BUREAU INTERNATIONAL DES POIDS ET MESURES (BIPM). Guide to the expression of uncertainty in measurement. Report no. JCGM 100:2008. First edition. Paris: International Bureau of Weights and Measures, Bureau international des poids et mesures; International Organization for Standardization, Organisation internationale de normalisation; International Electrotechnical Commission, Commission électrotechnique internationale, 2008. Available from: https://www.bipm.org/documents/20126/2071204/JCGM_100_2008_E.pdf/cb0ef43f-baa5-11cf-3f85-4dcd86f77bd6.