The supported LaTeX subset
Octant translates a bounded subset of mathematical LaTeX into Chelis Deep. The subset is "mathematical notation as it appears in finance and scientific computing textbooks," not arbitrary LaTeX. This chapter enumerates the constructs that translate, with a worked example or two each, the Chelis shape Octant emits, and the type-inference behaviour that goes with it.
If you hit something not listed here, see Scope and limitations. Most "won't translate" errors come from a known unsupported construct, not a bug, and each has a rewrite recipe.
The Deep snippets below show the structural tags (app, var, lit,
def, if, grad) and elide the {span: "..."} metadata that every
emitted node actually carries. The metadata is the audit trail; see
Provenance and span tracking.
Single-letter ASCII identifiers, Greek letters via \alpha, \sigma,
\Phi, \Sigma, \mu, and the constants \pi, e, \infty.
% chelis: x : f32% chelis: sigma : f32\sigma xThis translates to (app (var mul) (var sigma) (var x)). Greek letters
keep their LaTeX-stripped name (\sigma becomes sigma). The inference
pass treats them as ordinary scalars and asks for a % chelis:
annotation unless they are bound by a sum, product, or builtin constant.
The constants \pi, e, and \infty parse as identifiers. The
inference pass treats them like any other free variable and asks for a
% chelis: annotation. The reference pairs that mention e declare it
as % chelis: e : f32.
The default scalar type is f32. Add a % chelis: <name> : f64
annotation to widen.
Numeric literals
Section titled “Numeric literals”Integers, decimals, and scientific notation in either
1.5 \times 10^{-3} or 1.5e-3 form.
% chelis: r : f320.5 rThis translates to (app (var mul) (lit 0.5) (var r)). The
\times 10^{...} shape is supported; it routes through the general
power lowering and does not get a special-cased numeric literal.
Integer literals infer to i32; decimals to f32. Mixed i32/f32
arithmetic widens to f32 under the unification rules.
Subscripts and superscripts
Section titled “Subscripts and superscripts”Subscripts attach to identifiers via _<single-token> or _{...}.
% chelis: x_i : f32% chelis: S_t : f32x_i + S_tSubscripted identifiers flatten by default: x_i becomes a single named
scalar x_i. The % chelis: annotation refers to the flattened name.
This matches how textbook math reads x_i, a named scalar indexed by
convention. When the index is itself an arithmetic expression
(x_{i+1}) or the base is a complex expression ((A B)_{ij}),
normalization lowers to a structured index node instead.
Superscripts are exponentiation when the exponent is numeric or
evaluates to a number: x^2, e^{rT}, \sigma^2, x^{0.5}. The
emitted Deep depends on the exponent shape; see the pow lowering
table.
x^T and x^{\top} are special-cased as transpose, not exponentiation;
see Transpose.
Arithmetic and grouping
Section titled “Arithmetic and grouping”Binary operators: +, -, *, /, \cdot, \times. Equality =
for top-level name = body definitions. Juxtaposition is implicit
multiplication.
% chelis: a : f32% chelis: b : f32% chelis: c : f32a b + cGrouping: (...), [...], \{...\}, and the \left( ... \right) sized
variants. The closing form must match the opener. A
\left( ... \right] is a parse error.
% chelis: x : f32% chelis: y : f32\left( x + y \right)All binary operators require numeric operands. bool cannot mix with
i32, f32, or f64. The = form at top level marks the left side as
the definition name and the right side as the body, which is what
produces (def name body) in the Deep output.
Comparison operators <, >, \leq, \geq are not supported as
free binary operators. They are permitted only inside indicator-condition
position (\mathbb{1}_{x = 0}) and the \sum_{i=1}^{n} lower-bound
syntax, both as part of larger constructs.
Fractions and roots
Section titled “Fractions and roots”\frac{a}{b} lowers to division:
% chelis: a : f32% chelis: b : f32\frac{a}{b}(app (var div) (var a) (var b))\sqrt{x} lowers to the sqrt builtin:
% chelis: x : f32\sqrt{x}(app (var sqrt) (var x))\sqrt[n]{x} is the n-th root. It is supported and lowered through the
general power fallback (exp (mul (log x) (div 1 n))). There is no
dedicated n-th-root primitive.
An empty \frac{}{} or \frac{a}{} is a parse error, as is \sqrt
with no following {...}.
Big operators
Section titled “Big operators”Bounded sums and products. The lower bound must use the i = start
form, and the upper bound is required.
% chelis: n : i32% chelis: x : tensor[n, f32]\sum_{i=1}^{n} x_i(app (var reduce_sum) (var i) (lit 1) (var n) (var x_i))The emitted reduce_sum form takes index lower upper body. Octant
prefers the direct reduction form for simple subscript bodies.
\prod_{i=1}^{n} x_i is the equivalent product, emitting reduce_prod.
Unbounded forms (\sum_i x_i, \sum x) are an explicit error: the lower
bound must be derivable. Set-membership iteration \sum_{i \in S} is
rejected because \in is not a recognized command. A lower bound with
no upper bound is also an error.
Function application
Section titled “Function application”Standard math: \sin(x), \cos(x), \tan(x), \exp(x), \log(x),
\ln(x), \sqrt{x}, |x| (absolute value), \max(a, b),
\min(a, b).
% chelis: x : f32% chelis: y : f32\max(x, y)(app (var max) (var x) (var y))|x| lowers to (app (var abs) (var x)).
The positive-part shape \max(x, 0) is written directly.
The indicator \mathbb{1}_{cond} and \mathbf{1}_{cond} lower to an
if node:
% chelis: x : f32\mathbb{1}_{x = 0}(if (app (var eq) (var x) (lit 0)) (lit 1.0) (lit 0.0))The condition body must be a recognized predicate. = is the comparison
Octant accepts in the indicator position.
\sin and the other named functions require the parenthesized argument
form (\sin(x)). \sin x (juxtaposition) parses as \sin times x,
which is rarely what you want. Use the parenthesized form.
Probability and statistics
Section titled “Probability and statistics”Expectation \mathbb{E}[X], conditional expectation \mathbb{E}[X | F],
probability \mathbb{P}(A), and conditional probability
\mathbb{P}(A | B).
% chelis: x : f32% chelis: f : f32\mathbb{E}[x | f](app (var cond_expectation) (var x) (var f))The unconditional \mathbb{E}[X] form lowers to expectation. Octant
does not compute expectations. The surrounding context must define
expectation, cond_expectation, or cond_probability, typically via
an import:
% chelis: import Shoals.MonteCarlo (expectation, cond_expectation)The | inside \mathbb{E}[...] and \mathbb{P}(...) is a conditional
separator, not absolute value. Octant's parser keeps a context stack so
that \mathbb{E}[|x| | F] parses correctly: the inner |x| is absolute
value, the outer | is the separator.
Joint probability \mathbb{P}(A, B) is not supported. Rewrite as
\mathbb{P}(A \cap B) if your target context defines cap, or split it.
Calculus
Section titled “Calculus”Partial derivatives \frac{\partial f}{\partial x} and ordinary
derivatives \frac{df}{dx} lower to a gradient node:
% chelis: x : f32% chelis: f : f32\frac{\partial f}{\partial x}(grad {wrt: x} (var f))The Chelis compiler is responsible for verifying that f is pure and
differentiable. Octant emits the gradient form and defers the check.
Integrals are not supported. \int_0^1 f(x) dx raises an error: Octant
requires a known closed form. Hand-expand the integral to its
closed-form expression and translate that.
Equation environments
Section titled “Equation environments”\begin{equation} with an optional \label{...} propagates the label
into every emitted span identifier:
% chelis: c : f32% chelis: s : f32% chelis: k : f32\begin{equation}\label{eq:bs}c = s + k\end{equation}(def {span: "eq:bs_001"} c (app {span: "eq:bs_002"} (var add) (var s) (var k)))Every span identifier inside the labelled equation is prefixed with the
label (eq:bs_001, eq:bs_002), so octant explain --target eq:bs_002
resolves to the right LaTeX byte range. The label also flows into the
spans manifest's latex.label field. \begin{equation*} is treated the
same as \begin{equation}.
Other environments (tabular, aligned, matrix) are not math
environments and produce a clean error. \begin{align} parses the shell
but its & row separators are not handled; split it into multiple
\begin{equation} blocks.
Magic comments
Section titled “Magic comments”The % chelis: magic comments declare the types of free identifiers and
bring imported symbols into scope. The supported forms:
| LaTeX | Effect |
|---|---|
% chelis: r : f64 | declares r of type f64 |
% chelis: x, y : f32 | declares both x and y of type f32 |
% chelis: theta : tensor[k, f64] | a tensor with one named dim k, element f64 |
% chelis: import Shoals.MonteCarlo (expectation, dW) | brings expectation and dW into scope |
The recognized primitive types are f32, f64, i32, i64, and
bool. Tensor types take a comma-separated list [<dim>..., <prim>]
where each dim is an integer literal, an identifier, or _ for a
wildcard, and the element type is the last entry of the bracket list.
Imports add the listed names to scope as customer-supplied symbols. The emitter records the import header in the output program.
An unknown primitive errors. Stray colons error. The % chelis: prefix
is required: % r : f64 is treated as a generic LaTeX comment and
ignored.
Pow lowering
Section titled “Pow lowering”Bin{Pow, x, y} is lowered at Deep emission, not at type inference. The
exponent shape selects the emitted form:
| LaTeX exponent | Emitted Deep |
|---|---|
x^2 | (app (var mul) x x) |
x^3 | (app (var mul) x (app (var mul) x x)) |
x^4 | (app (var mul) (app (var mul) x x) (app (var mul) x x)) |
x^{0.5} | (app (var sqrt) x) |
x^{-1} | (app (var div) (lit 1.0) x) |
x^{-2} | (app (var div) (lit 1.0) (app (var mul) x x)) |
| anything else | (app (var exp) (app (var mul) (app (var log) x) y)) |
The negative-integer rows match either a literal negative integer or the
synthesized (sub 0 n) form that unary-negation lowering produces, so
x^{-1} reaches the cheap form regardless of how it renders.
The fallback uses the standard real-valued power identity. There is no
pow primitive in the output vocabulary. Every emission goes through
add, sub, mul, div, sqrt, exp, and log. A customer reading
the emitted Deep sees only that small set.
The synthesized (lit 1.0) literals in the inverse-power cases inherit
the span of the parent power node. They have no source representation but
still point back into the LaTeX, which is what keeps the audit chain
intact.
Transpose
Section titled “Transpose”x^T, x^{\top}, and A^T are special-cased in normalization and lower
to a transpose node rather than a power:
% chelis: a : f32a^T(app (var transpose) (var a))The T and \top forms are equivalent. Anything else in the exponent
position goes through the regular power path. Only the bare T and
\top are transpose. The emitted transpose reference assumes a
customer-supplied definition; Octant emits the structural form so
downstream linear-algebra modules can resolve it.
Special functions and Nautilus mappings
Section titled “Special functions and Nautilus mappings”The following LaTeX names map into Nautilus modules. The
normal-distribution family lives in Nautilus.Distributions; the rest
in Nautilus.Special.
| LaTeX | Chelis target |
|---|---|
\Phi(x) | Nautilus.Distributions.normal_cdf(x) |
\phi(x) | Nautilus.Distributions.normal_pdf(x) |
\Phi^{-1}(x) | Nautilus.Distributions.normal_inv_cdf(x) |
\Gamma(x) | Nautilus.Special.gamma(x) |
\text{erf}(x) | Nautilus.Special.erf(x) |
\text{erfc}(x) | Nautilus.Special.erfc(x) |
\text{Beta}(a, b) | Nautilus.Special.beta(a, b) |
By default Octant emits these in stub mode: it inlines a local identity
stub def for each Nautilus reference and rewrites call sites to a bare
name. The --emit-nautilus access opt-out reverts to the access-chain
form. See Provenance and span
tracking for the contract.
% chelis: x : f32\Phi(x)\log and \ln both map to log (natural log).