Skip to content

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 15 May 19:38
· 68 commits to main since this release

Algebra-guided training tooling lands as the headline 0.9.0 feature: a new quivers.analysis package walks any compiled QVR module and recommends saturation-free, algebra-aware initializers. The encoder rule-body sublanguage gains 86 PyTorch primitives and full user-callable dispatch, so encoder bodies can call top-level programs / morphisms / encoders / decoders by name. Contraction declarations infer their einsum from the typed signature.

Added

  • Comprehensive PyTorch primitive surface for let-expression bodies. The let-expression compiler now resolves 86 named primitives drawn from torch.nn.functional and torch: every standard activation (relu, gelu, silu/swish, mish, elu, selu, leaky_relu, prelu, rrelu, hardtanh, hardshrink, softplus, softshrink, softsign, hardsigmoid, hardswish, sigmoid, logsigmoid, tanh, tanhshrink, threshold, glu), simplex maps (softmax, log_softmax, softmin, normalize), pointwise transcendentals (exp, expm1, log, log1p, log2, log10, sqrt, rsqrt, square, abs, neg, sign, reciprocal, clamp), trig / hyperbolic (sin, cos, tan, asin, acos, atan, sinh, cosh, asinh, acosh, atanh), rounding (floor, ceil, round, trunc), special functions (erf, erfc, erfinv, lgamma, digamma), dim=-1 reductions (sum, mean, var, std, min, max, argmin, argmax, prod, amax, amin, logsumexp, norm), cumulative / ordering ops (cumsum, cumprod, cummax, cummin, flip, sort), and training-mode primitives (dropout, alpha_dropout, layer_norm, rms_norm). Reductions take dim=-1 by convention; reductions over a named axis go through the typed contraction surface.
  • User-defined programs callable from encoder bodies. Encoder / decoder / loss rule bodies (and any let-expression context) can now invoke top-level program declarations, let-bound morphisms, encoders, decoders, and deductions by name. The call form f(arg, ...) resolves first against the primitive table, then against the structural-globals dict, then against the user-declared constructor set. A deterministic program is a Dirac Kleisli arrow embedding Smooth into Kleisli(Giry); calling it from an encoder body composes the two Smooth pieces and stays in Smooth.
  • Compile-time arity checking on let-expression calls. For user-defined callables (Morphism, MonadicProgram, plain Python callables) the compiler verifies the positional argument count at compile time and raises CompileError("call to 'f': expected N positional argument(s), got M"). Variadic callables (*args) skip the check. Morphism is unary; MonadicProgram arity equals len(params) when present, else 1.
  • Runtime tensor-shape errors wrapped at call sites. A RuntimeError or TypeError raised inside a user-defined callable surfaces as CompileError("call to 'f' failed: ..."), so shape mismatches name the call site instead of producing a bare PyTorch trace.
  • DSL [init=auto] annotation on latent declarations. latent f : A -> B [init=auto] overrides the default randn * scale init with the algebra's saturation-free recipe. Through LatentMorphism's sigmoid bijector (for ProductFuzzy / Boolean / Gödel / Łukasiewicz / Probability) the raw parameter is set via logit(value); for other algebras the recipe is applied to the raw parameter directly. The annotation rides on the existing option_block grammar; no new keywords.
  • Encoder factory form: encoder NAME over SIG using FACTORY [k=v, ...]. An alternative to the explicit { ... } body that invokes a shipped builder from quivers.structural.shapes (rnn_encoder, transformer_encoder, bow_encoder, tree_lstm_encoder, gnn_encoder) with optional kwarg overrides. The two forms are mutually exclusive on one declaration and can coexist in the same module. The registry mapping factory name → import path lives in quivers.dsl.compiler.structural._ENCODER_FACTORY_REGISTRY.
  • quivers.analysis package with algebra-guided training tooling.
    • ChainShape.from_module(module) walks a compiled QVR Module and produces a per-step record (StepShape) with bound variable name, source line / col, chain depth (1-indexed at the first stochastic bind), governing algebra, and inferred intermediate axis size.
    • Algebra.init_spec(depth, intermediate_size) -> InitSpec returns the closed-form saturation-free init recipe per algebra (product-fuzzy p ≈ ln(2)/k, Łukasiewicz p ≈ 1/k, log-prob -ln k, Markov logits at 0, tropical / max-plus / real 1/√k, Boolean / Gödel idempotent at 1/2, probability / counting 1/k). recommend_init maps every latent in a module to its InitSpec; apply_init_spec materialises the recipe onto a learnable tensor via torch.nn.init.
    • saturation_warnings(module) returns source-keyed SaturationWarning diagnoses for every latent whose recipe differs materially (> 20% in location or scale) from a default Normal(0, 1).
  • Type-driven contraction wiring. contraction NAME(args) : DOM -> COD blocks no longer require a hand-written einsum string. The compiler infers the einsum from the typed signature: axes that appear in the output propagate; axes that appear in ≥ 2 inputs but not the output get contracted via the rule's join; axes that appear in exactly one input but not the output are flagged with a source-keyed error pointing at the disambiguators. Two opt-in clauses for the cases inference can't derive: share T1, T2, ... keeps the listed axes element-wise even when shared across inputs; wiring "<einsum>" remains as the explicit escape hatch (diagonal extraction, reorderings, etc.).

Full Changelog: v0.8.0...v0.9.0