This library is in flux. APIs may change without notice. Generated from source with koruc 0.1.7 on 11/4/2026.
Sym
import std/symstd/sym — symbolic scalar expressions with a canonical normal form.
sym.kz · 44 tors
std/sym — symbolic scalar expressions with a canonical normal form. · 38 more lines
Phantom lifecycles
Derived from the phantom labels in the declarations below — state! issues an
obligation the compiler will chase, !state discharges it, a bare state holds it without moving it. Nothing here is hand-drawn.
string 6 states sexpr!sexpr-external!allocated!// Tors. Canon strings ride <sexpr!>; ops consume linearly.
//
// Literal / trusted parse: π, e, 2*π, √(2), (π+e), 1/3...
// `expr` spells expression syntax at the callsite — authored math, not
// quoted text. Runtime text goes through ingest/parse instead.
~pub tor lit { expr: Expression }
| exact string<sexpr!>
| bad// External boundary: outside text -> <sexpr-external!>, only parse discharges.
~pub tor ingest { s: string } -> string<sexpr-external!>~pub tor parse { s: string<!sexpr-external> }
| exact string<sexpr!>
| bad string<std.io:allocated!>~pub tor add { a: string<!sexpr>, b: string<!sexpr> } -> string<sexpr!>~pub tor sub { a: string<!sexpr>, b: string<!sexpr> } -> string<sexpr!>~pub tor mul { a: string<!sexpr>, b: string<!sexpr> } -> string<sexpr!>~pub tor div { a: string<!sexpr>, b: string<!sexpr> }
| exact string<sexpr!>
| div-zero~pub tor neg { a: string<!sexpr> } -> string<sexpr!>~pub tor sqrt { a: string<!sexpr> }
| exact string<sexpr!>
| neg-root// Equivalence is canonical string equality — borrows both.
~pub tor equiv { a: string<sexpr>, b: string<sexpr> }
| same
| diff~pub tor free { n: string<!sexpr> }~pub tor render { n: string<!sexpr> } -> string<std.io:allocated!>~pub tor dup { n: string<!sexpr> } -> { a: string<sexpr!>, b: string<sexpr!> }// Cross-tower lanes
//
// Re-issue a canonical decimal as a symbolic leaf. The bytes are already
// canonical sexpr — numeric leaves share the decimal alphabet — so this is
// a mark move, not a conversion.
~pub tor of-dec { n: string<std.num:!exact> } -> string<sexpr!>// Integer power by repeated symbolic multiply: pow(x,3) -> (x*x*x),
// pow(x,-2) -> inv((x*x)), pow(x,0) -> 1e0. pow(0,-1) -> | div-zero,
// riding inv's own zero guard.
~pub tor pow { a: string<!sexpr>, n: i64 }
| exact string<sexpr!>
| div-zero// d/dx of a canonical sexpr — structural rules over the NF, result
// normalized through the same norm, so deriv lands canon.
~pub tor deriv { a: string<!sexpr> } -> string<sexpr!>~part supgen koru_std/sym.supgen.kz
Koru Standard Library: the `supgen` part of sym.kz — SupGen: certificate-producing structural synthesis over the Dec/sym tower. Joined via `~part supgen` in sym.kz; merged into the module at load. Power-series arithmetic over exact rationals (Rat = n/d over big ints) and bounded ODE discovery: enumerate (order, degree) candidates, build the series residual, solve for the relation kernel exactly, verify the residual on terms NOT used in the solve, emit a certificate string — or refuse `| not-found` (never claims nonexistence; bounds are named). Series of any expression in the sym grammar (dec/x/+/*/inv/sqrt) has RATIONAL coefficients — every construct here is D-finite. Constant atoms pi/e/phi are not rational, so series over them refuse | non-rational; poles and zero-constant sqrt/inverses refuse | non-analytic. Certificate algebra (second half of the SupGen artifact, mirroring isar-proofs HolonomicCertificate): cert-seed registers a declared law body p0=[..]|p1=[..] for an abstract/opaque generator; cert-shift is integralShift — if g satisfies cert c and deriv h = g, h satisfies shift(c): order+1, p0 := [0], pk := c.p(k-1).
// Series of a canonical sexpr at x=0 — `terms` coefficients as
// `terms=L:c0,c1,...` over exact rationals.
~pub tor series { a: string<!sexpr>, terms: i64 }
| exact string<std.io:allocated!>
| non-analytic
| non-rational
| bad// SupGen derive: bounded holonomic ODE discovery. Enumerates
// (order, degree) up to the declared bounds, solves the series-residual
// linear system exactly, verifies the residual on terms the solve never
// used, and emits a certificate — or | not-found (within bounds).
~pub tor derive-ode { a: string<!sexpr>, max-order: i64, max-deg: i64 }
| exact string<std.io:allocated!>
| not-found
| non-analytic
| non-rational
| bad// Integral closure — HolonomicCertificate.integralShift, proven in Lean
// (HolonomicClosure.integral_closure_shift): prepend p0=0, order+1. A
// theorem application, not a search — consumes the cert string.
~pub tor cert-shift { c: string<std.io:!allocated> }
| exact string<std.io:allocated!>
| bad-cert string<std.io:allocated!>// Abstract-term seed — declares a cert body `p0=[..]|p1=[..]|...` as
// data; truth is GIVEN, not discovered. This is the entry point for
// holonomy over terms the grammar does not close over: register the
// law, everything above it is algebra (cert-shift, later compose).
~pub tor cert-seed { body: string }
| exact string<std.io:allocated!>
| bad-cert string<std.io:allocated!>~part certcomp koru_std/sym.certcomp.kz
Koru Standard Library: the `certcomp` part of sym.kz — certificate closure under sum and product via companion-basis elimination over the rational-function field Q(x). Mirrors isar_holonomic_closure_algebra.py (_tensor_basis_certificate) and is proven in isar-proofs HolonomicClosure.lean. General composition is refused BY NAME (exp_exp_not_holonomic is a theorem, not a gap). Joined via `~part certcomp` in sym.kz; merged into the module at load. A cert ode(k=m,d=D)|p0..pm with nonzero leading p_m yields the companion rewrite g^(m) = sum_{k<m} (-p_k/p_m) g^k over Q(x). The derivative stays inside a finite span: sum: f^(i), g^(j) dim = m + n product: f^(i) * g^(j) dim = m * n so h, h', ..., h^dim are linearly dependent over Q(x); the first dependency found by augmented Gauss-Jordan gives h's ODE. Output is a theorem application (via=sum / via=prod), not a finite witness. Polynomials over Rat — coefficient lists, low to high; trailing zeros are permitted internally, polyIsZero/polyDegIdx scan.
// Tors.
//
// Sum closure: h = f + g. Companion-basis elimination over Q(x);
// HolonomicClosure's sum theorem — structural, not a finite witness.
~pub tor cert-sum { a: string<std.io:!allocated>, b: string<std.io:!allocated> }
| exact string<std.io:allocated!>
| bad-cert string<std.io:allocated!>// Product closure: h = f * g, dim <= m*n companion basis.
~pub tor cert-prod { a: string<std.io:!allocated>, b: string<std.io:!allocated> }
| exact string<std.io:allocated!>
| bad-cert string<std.io:allocated!>// Function composition f(g(x)) — proven not holonomic in general
// (exp_exp_not_holonomic / Stanley 1980 growth bound). This is a named
// theorem refusal, never a search: inputs are validated, then refused.
~pub tor cert-compose {
outer: string<std.io:!allocated>,
inner: string<std.io:!allocated>
}
| not-holonomic string<std.io:allocated!>
| bad-cert string<std.io:allocated!>// D-finite -> P-recursive projection (HolonomicBridge.lean): emits a
// rec(...) object — coefficients are polynomials in the index n, not x.
// det=1 marks q_{K,0} != 0: the recurrence's leading coefficient then
// never vanishes for n >= 0, so the coefficient sequence is determined
// by its first k terms — Lean's toPRecursiveCertificate packaging
// condition. A projection of a cert, not a search.
~pub tor cert-bridge { c: string<std.io:!allocated> }
| exact string<std.io:allocated!>
| bad-cert string<std.io:allocated!>~part certreg koru_std/sym.certreg.kz
Koru Standard Library: the `certreg` part of sym.kz — the certificate registry, mirroring isar_holonomic_closure_algebra.py's HolonomicRegistry. Koru has no mutable globals: the registry is an allocated TEXT BLOB threaded through flows — every op consumes the old blob and hands back a new one (persistent-value semantics). Joined via `~part certreg` in sym.kz; merged into the module at load. Format: reg:v1;G1=<cert>;G2=<cert>;... Keys are deterministic (G1, G2, ...). Provenance is embedded in each cert's `via` field: seed / verified=N / shift(Gk) / sum(Ga,Gb) / prod(Ga,Gb) — the Python registry's provenance strings, compressed into the cert text itself. Split `reg:v1;G1=cert;...` into cert-text slices borrowing `text`. Validates the header and each `G<n>=` record prefix.
// Tors.
//
// An empty registry blob.
~pub tor cert-reg-new {} -> string<std.io:allocated!>// Append a raw cert text as the next G entry. Validates the registry
// blob AND the cert — nothing unvalidated enters the store.
~pub tor cert-reg-put {
reg: string<std.io:!allocated>,
cert: string<std.io:!allocated>
}
| exact string<std.io:allocated!>
| bad-cert string<std.io:allocated!>// Register a declared law body — the abstract-term path, appended as
// the next G entry with via=seed.
~pub tor cert-reg-seed { reg: string<std.io:!allocated>, body: string }
| exact string<std.io:allocated!>
| bad-cert string<std.io:allocated!>// integralShift at registry level: G_new = shift(G_key), via=shift(Gk).
~pub tor cert-reg-shift { reg: string<std.io:!allocated>, key: string }
| exact string<std.io:allocated!>
| not-found
| bad-cert string<std.io:allocated!>// Sum closure at registry level: G_new = sum(G_a, G_b), via=sum(Ga,Gb).
~pub tor cert-reg-sum { reg: string<std.io:!allocated>, a: string, b: string }
| exact string<std.io:allocated!>
| not-found
| bad-cert string<std.io:allocated!>// Product closure at registry level, via=prod(Ga,Gb).
~pub tor cert-reg-prod { reg: string<std.io:!allocated>, a: string, b: string }
| exact string<std.io:allocated!>
| not-found
| bad-cert string<std.io:allocated!>// Discovery at registry level (Python register_from_expr): run the
// bounded SupGen search, append via=verified=N on success.
~pub tor cert-reg-derive {
reg: string<std.io:!allocated>,
a: string<!sexpr>,
max-order: i64,
max-deg: i64
}
| exact string<std.io:allocated!>
| not-found
| non-analytic
| non-rational
| bad
| bad-cert string<std.io:allocated!>// Composition at registry level: validate both keys resolve to certs,
// then refuse by name — the impossibility is a theorem.
~pub tor cert-reg-compose {
reg: string<std.io:!allocated>,
outer: string,
inner: string
}
| not-holonomic string<std.io:allocated!>
| not-found
| bad-cert string<std.io:allocated!>// Fetch a cert's text by key. Borrows the registry — the blob's
// allocated! obligation stays with the caller.
~pub tor cert-reg-get { reg: string<*>, key: string }
| exact string<std.io:allocated!>
| not-found
| bad-cert string<std.io:allocated!>// The key of the most recent entry ("G{n}"), for threading chains.
// Borrows the registry.
~pub tor cert-reg-last { reg: string<*> }
| exact string<std.io:allocated!>
| empty
| bad-cert string<std.io:allocated!>~part certgen koru_std/sym.certgen.kz
Koru Standard Library: the `certgen` part of sym.kz — certified series. Joined via `~part certgen` in sym.kz; merged into the module at load. Depends on: sym.kz (parseTree/norm/SNode), supgen (Rat/serFromNode/ certWrite/OdeCert), certcomp (Poly/Frac closure algebra, certBridge, recWrite, certClosure). cert-of derives the ODE STRUCTURALLY — theorem-level, no series witness (HolonomicClosure.lean semantics): dec -> f' = 0 x -> x f' - f = 0 a + b -> certClosure sum a * b -> certClosure prod inv(a), a order-1 -> q1 g' - q0 g = 0 (g = 1/f) sq(p), p a poly -> 2p g' - p' g = 0 (g = sqrt(p)) anything else is a named refusal, never a silent default. cert-series emits `cser(terms=N,det=1)|a=[...]|ode=...|rec=...`: cert-of -> certBridge -> det (Lean h0: q_{K,0} != 0) -> seeds are the expression's ACTUAL first R coefficients (exact), tail is generated by the recurrence. Every generated coefficient is forced by the ODE residual — theorem-correct, not a finite witness. det=0 refuses as under-determined carrying the (unpackageable) rec for diagnostics.
// Tors.
//
// Structural ODE derivation — theorem-level, no series witness.
~pub tor cert-of { a: string<!sexpr> }
| exact string<std.io:allocated!>
| not-holonomic string<std.io:allocated!>
| bad string<std.io:allocated!>// Certified series: the theorem upgrade. cert-of -> bridge -> det ->
// exact seeds -> recurrence-generated tail. The emitted coefficients
// are FORCED by the annihilating ODE (residual zero for all n >= 0 by
// the closure theorems), so the tail is theorem-correct — the finite
// window only seeds it.
~pub tor cert-series { a: string<!sexpr>, terms: i64 }
| exact string<std.io:allocated!>
| under-determined string<std.io:allocated!>
| not-holonomic string<std.io:allocated!>
| non-rational
| non-analytic
| bad// decide-integral: elementary construction for polynomial integrands;
// otherwise the holonomic-special lane — structural cert-of preferred
// (theorem-grade), bounded derive-ode as the discovery fallback
// (witness-grade seed, flagged). Matches the artifact's layer order:
// elementary-construct first, certified antiderivative via
// integral-shift second, unresolved with named evidence last.
~pub tor decide-integral { a: string<!sexpr>, max-order: i64, max-deg: i64 }
| elementary string<std.io:allocated!>
| holonomic-special string<std.io:allocated!>
| unresolved string<std.io:allocated!>
| not-holonomic string<std.io:allocated!>
| non-rational
| non-analytic
| bad// decide-ode: Kovacic pole-structure classification for y'' = r(x) y.
// Ported faithfully: poles = roots of den(r) — over C any non-constant
// denominator has roots — so bounded iff den is constant and
// deg(num) <= deg(den), i.e. r is a constant. No dsolve engine: the
// bounded arm emits the constant-coefficient solution FORM as text.
~pub tor decide-ode { r: string<!sexpr> }
| liouvillian string<std.io:allocated!>
| holonomic-special string<std.io:allocated!>
| unclassifiable string<std.io:allocated!>
| bad string<std.io:allocated!>// Generic `|name=` segment extractor over decision/cert blobs — the
// composition seam that lets decide-* outputs feed cert-reg-put without
// record-payload arms.
~pub tor decide-field { blob: string<*>, name: string }
| exact string<std.io:allocated!>
| not-found~part rel koru_std/sym.rel.kz
std/sym part: rel — declared-generator relationships. A generator is a named function of x declared in a `rel:v1` registry: rel:v1;exp=;sin=g(cos);cos=(-1e0*g(sin)) Entry i internes atom 4+i; `g(name)` in an expression resolves against the registry's names. A law is a canonical sexpr (over x, decimals, √/inv and other generators) giving D(g_i) — attached after declaration so cyclic law pairs (sin <-> cos) and self-laws (exp' = exp) both work. Grammar extension lives in sym.kz: `g(name)` parses only under a registry (ParseCtx.greg); the closed `lit` grammar refuses g-atoms. Expressions containing g-atoms form a distinct universe from <sexpr!> — they cannot flow through sym:add/mul/... (those parse with no registry) — so rel surfaces take and return plain strings. Tors: rel-new -> rel:v1 (allocated!) rel-seed reg, name -> exact reg' | dup | full | bad declare a name rel-law reg, name, law -> exact reg' | unknown-generator | bad rel-derive reg, expr -> exact text | unknown-generator | lawless | bad rel-norm reg, expr -> exact text | unknown-generator | bad rel-derive applies the declared laws mechanically (chain rule) and returns the normalized canonical text — theorem-grade, since each step is the derivative rule or a declared law substitution. rel-norm gives the canonical form: two expressions provably-equal under the laws iff their canonical texts match (the equality-check primitive is caller-side text compare).
~pub tor rel-new {} -> string<std.io:allocated!>// Declare a generator name (lawless until rel-law attaches a law).
~pub tor rel-seed { name: Expression, reg: string<std.io:!allocated> }
| exact string<std.io:allocated!>
| dup
| full
| bad// Attach (or replace) the derivative law for a declared generator. The law
// is a sexpr over x and generator names — self- and mutual references
// resolve since the name set is complete at attach time.
~pub tor rel-law {
name: Expression,
reg: string<std.io:!allocated>,
source: Source
}
| exact string<std.io:allocated!>
| unknown-generator
| bad// d/dx of expr under the declared laws — theorem-grade: every rewrite step
// is a derivative rule or a declared-law substitution.
~pub tor rel-derive { reg: string<*>, source: Source }
| exact string<std.io:allocated!>
| unknown-generator
| lawless
| bad// Canonical normal form of expr under the registry's name set — the
// caller-side equality primitive: canon-equal texts are provably equal.
~pub tor rel-norm { reg: string<*>, source: Source }
| exact string<std.io:allocated!>
| unknown-generator
| bad