Skip to content

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 14 May 13:16
· 89 commits to main since this release

Quivers 0.5.0 is the typed-prior release: structured matrix-valued priors on weight matrices via an axis-role syntax, a major inference-layer expansion, and an example gallery rebuilt from scratch to exercise the new surface.

Headline additions

Axis-role surface on every distribution clause

Kernel declarations, latent priors, sample steps, and observe steps accept an optional over <axes> [iid over <axes>] post-clause. over names the event axes of the family; remaining axes are iid (categorically a product of independent distributions). Axis names resolve against the named factors of the surrounding morphism's dom/cod; dom/cod are shortcuts when that side is a single unfactored object.

The axis count must match the family's declared event_rank (0 / 1 / 2 for scalar / vector / matrix families); mismatch is a compile-time error rather than a silent reinterpretation. This preserves the categorical distinction between, for example, a flat MVN over dim(A)·dim(B) with dense covariance and a MatrixNormal over (A, B) with Kronecker structure V ⊗ U.

latent W : Euclidean(D) -> Euclidean(K)
    ~ MatrixNormal(loc, row_cov, col_cov) over (dom, cod)

Unified kernel keyword

The continuous and stochastic declaration keywords are removed in favor of a single kernel keyword. A kernel f : A -> B declaration without a ~ clause declares a finite-set lookup-table kernel; with ~ Family [options] [axes] it declares a parametric kernel whose family parameters are produced from the input by a neural parameter network at sample time. This collapses two keywords whose distinction was already in the type signature into one whose name reads as "Markov kernel" everywhere.

Latent morphism priors

A latent f : A -> B ~ Family(args) [options] [over <axes>] clause puts a prior on the morphism's representing tensor. The morphism becomes a sample site whose value is drawn afresh at each forward pass; the inference layer integrates it as if there were an explicit top-of-program bind step. This is the right surface for factor analysis, PPCA, BNNs, and other "matrix of weights with prior" models.

Four new conditional families

  • ConditionalMatrixNormal — Matrix-Normal with Kronecker covariance V ⊗ U, event_rank 2. The natural prior for a weight matrix whose row and column correlations factor separately.
  • ConditionalInverseWishart — Conjugate prior for the covariance of a multivariate normal (Gelman et al. 2013 §3.6), event_rank 2.
  • ConditionalGaussianProcess — RBF / Matern 5/2 / linear kernels with learnable length scale and amplitude; Cholesky factorization on the jittered kernel matrix; event_rank 1.
  • ConditionalHorseshoe — Carvalho-Polson-Scott global-local shrinkage with a 16-point Gauss-Legendre quadrature giving the exact marginal log-prob; event_rank 1.

Surface DSL homogenization

The program-block surface is reorganized around a single Kleisli-bind sigil <-, type-annotated indexing on the binder, scoped marginalization, and !-prefixed effect signatures:

Pre-0.5 surface 0.5 surface
draw v ~ F v <- F
draw v : A -> K ~ F v : A <- F
observe r[n] ~ F for n in N observe r : N <- F
marginalize c (unscoped) marginalize c : A <- F in { … }
posterior P (M) [v] program P(v) : … ! Pure over M
output export

Programs carry an effect signature ! Sample, Score, Marginal, Pure. The compiler verifies that the body's actual effects are a subset of the declared set; ! Pure rejects any sample / score / marginal binds.

Grouped marginalize with multi-observe fibration

marginalize cls : K <- Dirichlet(probs)
    over Item
    in {
        observe r1 : Resp1 via idx1 <- Normal(...)
        observe r2 : Resp2 via idx2 <- Bernoulli(...)
    }

The over G clause on the header declares the grouping plate; each observe carries its own via idx clause naming the per-observe fibration into the shared plate. The runtime scatter-sums per-axis log-likelihoods into a single per-group accumulator before the reduction. Realizes the right Kan extension along the coproduct fibration in Kern.

Agenda-based weighted-deduction framework

A declarative deduction { … } block backed by a general agenda-engine runtime (quivers.stochastic.agenda):

  • One engine, seven parameters (item algebra, rule set, semiring, axiom source, goal predicate, start symbol, depth bound) subsumes CKY, Earley, Viterbi, semi-naive Datalog, A* parsing, Knuth's algorithm, and depth-first MLTT proof search.
  • Charts as first-class differentiable values: view.weight(item), view.enumerate(pattern), view.goal_weight() return torch tensors with autograd.
  • Pre-registered stdlib deductions: CCG, Lambek, STLC, MLTT, Datalog, Dijkstra, HMM, ViterbiHMM, EditDistance.

Structural compression surface

A four-block pattern (signature { ... } encoder { ... } decoder { ... } loss { ... }) factors out transformers, tree LSTMs, graph NNs, autoregressive LMs, variational autoencoders (Kingma & Welling, 2014), and the vector inside-outside parser (Le & Zuidema, 2014) as instances of one F-algebra / F-coalgebra interface.

Inference layer overhaul

Six layers on a shared LatentRegistry:

Categorical refinements

  • Quantale duality: Quantale.dual() returns a DualQuantale whose tensor_op and join swap roles under the de-Morgan involution; user-defined quantales (CustomQuantale) and semigroupoids (CustomSemigroupoid) take inline DSL operations with associativity / identity smoke checks at build time.
  • CompositionRule → BilinearForm | Semigroupoid → Quantale hierarchy: non-associative bilinear forms and identity-less semigroupoids ship alongside quantales; operadic n-ary contractions via einsum-style EinsumWiring specs land any n-ary morphism under a named composition rule.
  • First-class transformations: change-of-base transformations (softmax, L1/L2 normalization, Bayes inversion, quantale homomorphisms) are values: let-bindable, composable with >>>, passable into change_base.
  • Shape-aware change-of-base: Morphism.change_base accepts both QuantaleHomomorphism (pointwise) and MorphismTransformation (shape-aware) values; the seam type-checks at composition time.

Example gallery (36 examples)

Regression (Bayesian, beta, Dirichlet, NegBin, horseshoe, ZIP); latent-variable (factor analysis, PPCA, LDA, IRT-2PL, PMF, BNN, GMM, VAE); time-series and state-space (HMM discrete, continuous HMM, linear-Gaussian SSM, deep Markov, AR(1), stochastic volatility, changepoint, Weibull survival); sequence architectures (vanilla RNN LM, LSTM LM, GRU LM, bidirectional RNN LM, transformer LM, seq2seq with encoder + decoder); formal grammars (PCFG, CCG, Lambek calculus, multimodal TLG, custom rules, Montague NLI, quantifier scope). Each example exercises at least one distinguishing quivers feature (axis-role priors, marginalize, change_base, encoder blocks, scan, deduction declarations, structural compression) and runs end-to-end on synthetic data with a recovery test.

Major refactors

  • src/quivers/continuous/bayesian.py renamed to plate.py and further split: _DeterministicMorphism, cumsum, softmax, cholesky_quad_form moved to quivers.continuous.deterministic; CholeskyFactor continuous space moved to quivers.continuous.spaces; LKJCorrelationFactor and Truncated moved to quivers.continuous.families; plate.py now strictly the plate / vectorised-observe / grouped-marginalize machinery.
  • src/quivers/dsl/compiler.py (~6300 LOC) split into a package src/quivers/dsl/compiler/ with one module per concern (_prelude, core, declarations, programs, structural, deductions, resolution, expressions); public import paths unchanged.

Documentation

  • A new Denotational Semantics chapter giving a formal compositional semantics for the DSL across discrete, stochastic, and continuous strata, plus an adequacy theorem connecting the compiler implementation to the denotation.
  • Two-track tutorial (QVR DSL track and Python API track), with side-by-side Pyro / NumPyro / Stan / PyMC comparisons in the QVR track.

Breaking changes (pre-1.0 clean cut)

No backward-compatibility shims. User code that relied on the pre-0.5 surface should follow the migration table above. The loss= keyword on SVI is aliased as objective=; the posterior= positional argument on Predictive replaces the keyword form; imports from quivers.core.extra_quantales move to quivers.core.quantales.

Full changelog

See CHANGELOG.md for the line-item diff (axis-role surface, every new family, refactor list, deprecation table, and per-section additions).

Full Changelog: v0.4.1...v0.5.0