Skip to main content

Computational category theory as differentiable tensor programs

Project description

Quivers

CI Docs PyPI Python 3.14+ License: MIT

A probabilistic programming language for PyTorch.

Quivers lets you write Bayesian models in a small, readable DSL and fit them with stochastic variational inference (SVI), NUTS, HMC, or any of nine automatic guides. The program surface should look familiar if you have used Pyro, NumPyro, Stan, or PyMC: declare variables with <-, score observations with observe, integrate out discrete latents with marginalize, get a trainable PyTorch module back.

object Item : 100

program regression : Item -> Item ! Sample, Score
    sigma  <- HalfNormal(1.0)
    beta_0 <- Normal(0.0, 5.0)
    beta_1 <- Normal(0.0, 2.0)
    x      <- Normal(0.0, 1.0)
    let mu = beta_0 + beta_1 * x
    observe y <- Normal(mu, sigma)
    return y

export regression
from quivers.dsl import loads
from quivers.inference import AutoNormalGuide, ELBO, SVI
import torch

program = loads(open("regression.qvr").read())
model   = program.morphism
guide   = AutoNormalGuide(model, observed_names={"y"})
optim   = torch.optim.Adam(guide.parameters(), lr=1e-2)
svi     = SVI(model, guide, optim, ELBO())
for _ in range(2000):
    svi.step({"x": x_data}, {"y": y_data})

The full walkthrough is in the tutorial.

What you get

The everyday PPL features you would expect, on a PyTorch backend:

  • Forty distribution families (Normal, Beta, Gamma, Dirichlet, MVN, LKJ, MatrixNormal, GP, Horseshoe, mixtures, normalising flows, and more).
  • Nine variational guides from mean-field through full-rank multivariate normal, low-rank, mixture, IAF, neural-spline flow, and AutoDAIS.
  • Four inference objectives (ELBO, IWAE, Renyi, VR-IWAE) with reparameterised / score-function / sticking-the-landing / DReG gradient estimators.
  • NUTS and HMC with dual-averaging step-size adaptation and Welford mass-matrix adaptation, plus a WarmupThenHMC hybrid sampler.
  • Marginalised discrete latents as a first-class block (marginalize z : K <- Categorical(p) in { ... }), with logsumexp aggregation handled for you.
  • Plates and grouped marginalisation for hierarchical models with vectorised observations and per-row fibration into shared random effects.
  • A 36-example gallery covering regression (Bayesian, Beta, Dirichlet, NegBin, horseshoe, ZIP), latent variable (factor analysis, PPCA, LDA, IRT, PMF, BNN, GMM, VAE), state space (HMM discrete and continuous, linear-Gaussian SSM, deep Markov, AR1, stochastic volatility, changepoint, Weibull survival), language models (RNN, LSTM, GRU, bidirectional, transformer), seq2seq with encoder/decoder, and formal grammars (PCFG, CCG, Lambek, multimodal TLG).

What's distinctive

Most PPLs let you write observe y ~ Normal(mu, sigma). Quivers lets you write the same thing AND a few things ordinary PPLs do not.

  • Typed scoped marginalisation. marginalize z : K <- Categorical(p) in { ... } is a syntactic block whose body runs once per discrete value of z, with the per-value scores aggregated by logsumexp. This is the standard Rao-Blackwellisation trick, but spelt as a control-flow construct instead of a runtime flag.
  • Axis-role priors on weights. A weight matrix latent W : Euclidean(D) -> Euclidean(K) can carry a structured prior whose covariance is genuinely matrix-valued: ~ MatrixNormal(loc, row_cov, col_cov) over (dom, cod). The over <axes> clause says which axes the family's joint covariance lives on; the rest are iid. This is the right surface for factor analysis, PPCA, Bayesian neural nets, and other "matrix of weights with prior" models.
  • Exact-likelihood structured families. HMMs and Kalman smoothers compose like ordinary distributions; the forward / forward-backward / smoother passes are wrapped.
  • Compile-time effects. Programs carry an effect signature ! Sample, Score, Marginal, Pure that the compiler checks against the body. A ! Pure block that contains an observe is rejected with a typed error before training begins.
  • Weighted deduction. Chart algorithms (CKY, Earley, Viterbi, A*, Knuth's algorithm, semi-naive Datalog) are exposed as a deduction { atoms ... rule ... semiring ... start ... } block whose chart is a differentiable tensor. Drops in alongside the rest of the language.
  • Structural compression. A four-block pattern (signature { ... } encoder { ... } decoder { ... } loss { ... }) factors out transformers, tree LSTMs, graph NNs, autoregressive LMs, and the vector inside-outside parser as instances of one interface.

What's under the hood (optional reading)

The DSL is a thin layer over a typed categorical surface in src/quivers/. If you want to extend the library, write a new family, prove anything about a model, or read the type errors fluently, the categorical layer is what you read. If you just want to fit models, you can ignore it. The denotational semantics (docs) gives every well-typed program a formal meaning in a $\mathcal{V}$-enriched symmetric monoidal closed category. The implementation rests on enriched category theory (Kelly, 1982), the categorical foundations of probability (Giry, 1982; Fritz, 2020), and the SVI / HMC inference substrate (Hoffman, Blei, Wang & Paisley, 2013; Neal, 2011; Hoffman & Gelman, 2014).

Installation

pip install quivers

Or install from source:

git clone https://github.com/FACTSlab/quivers
cd quivers
pip install -e ".[dev]"

Requirements: Python 3.14+, PyTorch 2.0+, didactic 0.6.0+, panproto 0.45.0+, panproto-grammars-all 0.45.0+.

Learning path

Two parallel tracks, depending on what you want:

  • QVR DSL tutorial for probabilistic-programming users. Seven chapters, model development through inference, side-by-side with PyMC / NumPyro / Stan.
  • Python API tutorial for library developers and category-theory-fluent users. Seven chapters covering the typed categorical surface end to end.

Then:

Project structure

src/quivers/
├── core/           objects, quantales, morphisms, tensor ops, wiring
├── categorical/    functors, natural transformations, adjunctions, monoidal, traced
├── monadic/        monads, comonads, algebras, distributive laws
├── enriched/       ends/coends, Kan extensions, profunctors, Yoneda, Day, optics
├── stochastic/     Markov kernels, Giry monad, grammar parsers, chart algorithms
├── continuous/     distribution families, spaces, flows, monadic programs
├── dsl/            parser (panproto / tree-sitter), AST (didactic Models),
│                   compiler, resolution lenses, Program Theory
├── inference/      registry, guides, objectives, estimators, MCMC, hybrids
├── program.py      Program: wraps morphisms as nn.Module
└── giry.py         GiryMonad, FinStoch

The tree-sitter grammar lives at grammars/qvr/ and is vendored by panproto's panproto-grammars-all distribution.

Contributing

See CONTRIBUTING.md for development setup, code style, and the git workflow. Issues and pull requests welcome at github.com/FACTSlab/quivers.

License

MIT. See LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quivers-0.5.0.tar.gz (1.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quivers-0.5.0-py3-none-any.whl (499.1 kB view details)

Uploaded Python 3

File details

Details for the file quivers-0.5.0.tar.gz.

File metadata

  • Download URL: quivers-0.5.0.tar.gz
  • Upload date:
  • Size: 1.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for quivers-0.5.0.tar.gz
Algorithm Hash digest
SHA256 4562cdc1cc8e424dcd2a8397b1296a08bfc4444bbf51eacca9c1ee523a4b32a0
MD5 49cf2487054477e23988e4bb0a45d0da
BLAKE2b-256 185b97dfb7ab40293cc5cf19271de0a106eb38790ebee880fce0b588f9a8b5db

See more details on using hashes here.

Provenance

The following attestation bundles were made for quivers-0.5.0.tar.gz:

Publisher: release.yml on FACTSlab/quivers

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file quivers-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: quivers-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 499.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for quivers-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 11d0500d1474b99feaba49f22efee222c7fc2bf922cb9ff335e22689d441dab7
MD5 e8ae7353bbfea4f9384a9de683c9b227
BLAKE2b-256 5db7183b9df15e67e32df945b2a04ad989ae6c5a84b33e8869c06004ff50ecd2

See more details on using hashes here.

Provenance

The following attestation bundles were made for quivers-0.5.0-py3-none-any.whl:

Publisher: release.yml on FACTSlab/quivers

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page