Math input
How an expression written on a math keyboard becomes a Julia value, and how a Julia value becomes typeset mathematics again.
GiacSlate offers two distinct entry points, which are easy to confuse:
Mathfield | @giac_str (giac"…") | |
|---|---|---|
| what it is | a @bind control | a literal inside a code cell |
| bound value | MathJSON (a String) | a GiacExpr, directly |
| conversion | mathfield_to_giac, explicit | none — the literal is the expression |
| typical use | an exercise answer to grade | an expression the reader edits in place |
giac"…" — the live literal
A giac"…" literal is ordinary Xcas source, evaluated by giac_eval:
factor(giac"x^6 - 1")
desolve(giac"y'' + 4*y = 0 and y(0) = 1 and y'(0) = 0", giac"y(t)")What makes it special is the editor extension using GiacSlate installs: inside a code cell, such a literal renders as a typeset MathLive field. Click into it, edit the mathematics, press <kbd>Enter</kbd> — the literal's source is rewritten and the cell recomputes. The file stays perfectly ordinary Julia: outside Slate, giac"x^2+1" evaluates exactly the same.
<kbd>⌘</kbd>/<kbd>Ctrl</kbd>+<kbd>M</kbd> inserts a fresh field; the ∫ button in the cell toolbar does the same with the mouse.
An empty literal is missing, not an error:
giac"" # missingThat is deliberate: a blank math field should read as "not filled in yet" and flow through the grader as such, rather than breaking the cell.
Mathfield — the @bind control
When what you want is the reader's answer rather than an expression edited in place, bind a control:
@bind answer Mathfield(label = "your answer")answer receives MathJSON — a String. To turn it into an expression:
expr = mathfield_to_giac(answer) # a GiacExpr, or `missing` if the field is emptyBecause the bound value is a plain String, SlateExtensionsBase's type-driven coerce/reconcile defaults apply as-is: the answer survives a re-run of the bind cell.
The front-end component (assets/mathfield.js) is fetched only on the first binding of a Mathfield, through required_assets.
Typesetting in prose
gmath and gdisplay render a Giac expression as LaTeX ready to be interpolated into a Markdown cell with {{ … }}:
# in a code cell
Hs = giac"1/(s^2 + 2*s + 5)"The system has transfer function {{ gmath(Hs) }}, a second-order response. Its
unit-step response is
{{ gdisplay(yt) }}gmath produces inline math ($…$), gdisplay a display block ($$…$$). Because the Markdown cell reads the variable, it re-typesets whenever that variable changes.
The bridge, in both directions
The two conversion functions are exported, and exposed to the front-end as the giac_tex and giac_src handlers:
GIAC source ──[ giac_src_to_tex ]──▶ LaTeX (display)
MathJSON ──[ mathjson_to_giac_src ]──▶ GIAC source (write-back)giac_src_to_texevaluates, then renders to LaTeX. GIAC is lenient — it returnsundefon malformed input instead of throwing — soundefis treated as an error here: an unreadable field must show as broken, not as the literal wordundef.mathjson_to_giac_srcreturns source text and evaluates nothing. Empty input, anull, and the["Error", …]payload MathLive emits for an invalid field all give""— a half-typed formula must not break the cell being edited.mathfield_to_giacis the variant that does evaluate, returning aGiacExpr.
What the MathJSON walk translates
MathJSON heads are converted into Xcas source: arithmetic (Add, Subtract, Multiply, Divide, Power, Root, Sqrt), grouping (Delimiter, Sequence), List, Equal, Subscript, the usual constants (Pi, ExponentialE, ImaginaryUnit, GoldenRatio, the infinities), and a table of functions (trigonometric and hyperbolic, Exp, Ln, Log, Abs, Floor, Gamma, Factorial, …).
Two explicit refusals, rather than bogus symbols:
- string literals are not valid math input;
- decorated symbols (
x̂,x̄,x⃗,ẋ, …) have no clean GIAC counterpart, so the conversion raises instead of inventing ahat(x)that would neither compute nor compare against anything. Use a plain name (xhat,xbar).
Likewise, a symbol still non-ASCII after canonicalisation is refused.
An unrecognised MathJSON head is translated into a GIAC function call of the same name, lowercased. That is a best-effort fallback, useful for reaching the engine's ~1800 commands — not a security boundary. There would be no point in one here anyway: a giac"…" literal is arbitrary Xcas source by construction. These notebooks are meant to be read and run by their owner, not to execute input from an untrusted third party.
Greek letters and subscripts
A math keyboard emits Greek letters as Unicode glyphs, which GIAC treats as distinct from its ASCII identifiers. A single normaliser is shared by every ingress — the MathJSON bridge, the giac"…" macro, the display path, and the grader — folding:
| written | canonicalised |
|---|---|
ω, θ, Δ | omega, theta, Delta |
x₀, ω₁ | x_0, omega_1 |
This unifies encodings of one symbol; it never merges two distinct symbols.
Reference
GiacSlate.@giac_str — Macro
giac"…"Parse and evaluate GIAC source into a GiacExpr, e.g. giac"1/(s+a)", giac"diff(sin(x),x)". The inline-math editor renders such a literal as a live, editable math field.
An empty literal (giac"", the state of a blank math field) evaluates to missing rather than throwing — so a blank field reads cleanly as "not filled in yet" (e.g. an unanswered exercise flows through an autograder as missing) instead of breaking the cell.
Extended characters typed straight into the literal (a Greek glyph ω, a subscript x₀) are canonicalised to GIAC's ASCII source (_canon_src) at macro-expansion, so a directly-typed giac"ω" is the same symbol as a keyboard-entered ω — see the canonicalisation note in mathfield.jl.
GiacSlate.gmath — Function
gmath(e)Render a GiacExpr (or anything with a text/latex show) as an inline LaTeX string wrapped for markdown ($…$). Use inside a markdown cell's {{ … }} interpolation to typeset a code-cell math variable — e.g. The transfer function is {{ gmath(H) }}. The cell re-renders when the variable changes.
See gdisplay for the display-block form.
GiacSlate.gdisplay — Function
gdisplay(e)As gmath, but wrapping the LaTeX as a display block ($$…$$) rather than inline — for an expression that deserves its own centred line in the prose.
GiacSlate.Mathfield — Type
Mathfield(; label = nothing, default = "")A MathLive <math-field> @bind control binding the reader's expression as MathJSON: @bind ans Mathfield(label = "your answer"), then mathfield_to_giac(ans). The front-end loads on first use (using GiacSlate is all the setup needed — no boot cell).
GiacSlate.mathfield_to_giac — Function
mathfield_to_giac(mathjson) -> GiacExpr | missingConvert a MathLive <math-field> MathJSON payload (a raw JSON string, or the already-parsed value) into a GiacExpr. An empty field yields missing, so it flows through the autograder as "not answered yet".
GiacSlate.giac_src_to_tex — Function
giac_src_to_tex(src) -> StringConvert GIAC source into the LaTeX the math field displays — the display side of the editor bridge, exposed to the front-end as the giac_tex handler.
An empty source yields "". GIAC is lenient and returns undef for malformed input instead of throwing, so undef is treated as an error here and raised: a field that cannot be parsed must show as broken, not as the literal word undef.
The source is canonicalised first (_canon_src), so a directly-typed ω displays as \omega rather than as an unknown glyph.
GiacSlate.mathjson_to_giac_src — Function
mathjson_to_giac_src(json) -> StringConvert a MathLive MathJSON payload (a raw JSON string) into GIAC source — the write-back side of the editor bridge, exposed to the front-end as the giac_src handler. This is what turns what the reader typed in a math field back into the text of the giac"…" literal in the cell.
Empty input, a null/"Nothing" payload, and MathLive's ["Error", …] payload (an empty or invalid field, or an engine that isn't ready) all yield "" rather than throwing — a half-typed formula must not break the cell being edited.
Unlike mathfield_to_giac, which evaluates and returns a GiacExpr, this returns source text and evaluates nothing.