Skip to content

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 15 May 14:20
· 72 commits to main since this release

Quivers 0.7.0 is the analysis pipelines release: a brms-style formula-to-fit-to-diagnostics surface (fit("y ~ x + (1|g)", data=df, ...)) on top of a pre-1.0 clean break renaming quantale to algebra across the DSL, Python API, and docs.

Headline additions

Formula → fit → diagnostics, the one-liner

The new quivers.formulas package compiles a brms / lme4 formula directly to a QVR program through a typed AST dx.Lens — no source-string round-trip, no hand-rolled formula parser (formulae carries the syntax, this package contributes the AST lifting and QVR emission).

from quivers.formulas import fit

result = fit(
    "acceptability ~ verb + frame + log(rt) + (1 + verb | subject)",
    data=df,                       # pandas or polars
    family="bernoulli",            # auto-derives the logit link
    sampler="nuts",
    num_warmup=500,
    num_samples=1000,
    num_chains=4,
    seed=0,
)

fit returns a BayesianFit — a frozen dx.Model carrying the parsed Formula, the compiled MonadicProgram, the posterior (an MCMCResult or a Guide), the observations dict, and result.qvr_source / result.dump_qvr("path.qvr") for inspecting or persisting the emitted program.

R / brms behaviour is faithful by construction:

  • Orthogonal polynomials by default. poly(x, k) matches stats::poly (k orthonormal centred columns). Raw monomials stay available via I(x**k).
  • One coefficient per design-matrix column. poly(x, 2) produces beta_poly_x_2_1 and beta_poly_x_2_2; x*z produces beta_x, beta_z, beta_x_z. Matches brms display.
  • R-style numeric transforms wired in. log, exp, sqrt, abs, sin, cos, tan, log10, log2, log1p, expm1, asin, acos, atan, sinh, cosh, tanh resolve to their numpy counterparts in formula evaluation.
  • Family registry. gaussian, bernoulli, binomial, categorical, poisson, negative_binomial, gamma, beta, student_t, cumulative — each with its canonical link function and auxiliary-parameter priors.
  • Random effects. (slope | g) emits a HalfNormal scale plus a per-level plate draw; multiple random slopes per group are uncorrelated ((... || g) semantics).
  • Prior overrides. priors={"sigma": "HalfCauchy(2.5)", "beta_x": "Normal(0, 1)"} overrides any latent.

Gated behind the formulas extra.

quivers.data: DataFrame schema bridge

DatasetSchema turns a pandas / polars / Narwhals-compatible dataframe into the object cardinalities, observations dict, and plate-index codes a QVR program needs. compose(qvr_body, schema) prepends inferred object X : N declarations to a user-written program body, so the user only writes the program body and the cardinalities come from the data. Four missing-data policies (raise, drop, impute, mask). Gated behind the data extra.

quivers.diagnostics: ArviZ adapter

Glue layer between quivers' inference records and the ArviZ 1.x xarray.DataTree surface — the canonical posterior-analysis container consumed by plot_trace, plot_forest, plot_ppc, loo, compare, hdi, etc.

  • to_datatree wraps quivers' per-site sample tensors, log-densities, acceptance rates, and divergences into the canonical ArviZ groups.
  • compare delegates to ArviZ's PSIS-LOO ranking (Yao et al. 2018) for ranked model comparison plus stacking weights.
  • posterior_predictive_check computes the canonical posterior-predictive p-value for a user-chosen test statistic; built-in statistics (mean / median / sd / var / min / max / q05 / q95) plus pluggable callables.
  • loo_pit re-exposes ArviZ's LOO-PIT calibration diagnostic.

No information-criterion math, no plotting code, no PSIS-LOO implementation lives in quivers — every analytics primitive comes from ArviZ. Gated behind the diagnostics extra.

quivers.dsl.emit: AST → .qvr source

module_to_source walks a Module AST and produces canonical .qvr source. The round-trip loads(module_to_source(m)) == m is exercised on every formula in the test suite, and BayesianFit.dump_qvr(path) writes the emitted program for inspection or version control.

TransformedMorphism: autograd-safe morphism transforms

Morphism.change_base, .dagger, .trace, and .refactor now return a TransformedMorphism whose .tensor is recomputed from the source morphism's tensor on every access — keeping autograd graphs alive across categorical transforms.

BREAKING: quantale → algebra across DSL, Python API, and docs

The quantale keyword and every Quantale-named symbol overclaimed: seven of the eleven built-in enrichment structures fail strict quantale-distributivity in Kelly's sense. The t-norm pairs (product-fuzzy, Łukasiewicz) are commutative residuated lattices; the real semiring is unbounded; the probability case uses saturated sum. The new term algebra names the structure $(V, \otimes, \oplus, \mathbf{1})$ honestly. Strict quantale is preserved as the named subclass identified in Algebras §2.

Old New
quantale X (DSL keyword) algebra X
Quantale (abstract base) Algebra
BooleanQuantale, LukasiewiczQuantale, GodelQuantale, TropicalQuantale, MaxPlusQuantale, LogProbQuantale, RealQuantale, ProbabilityQuantale, CountingQuantale, MarkovQuantale BooleanAlgebra, LukasiewiczAlgebra, GodelAlgebra, TropicalAlgebra, MaxPlusAlgebra, LogProbAlgebra, RealAlgebra, ProbabilityAlgebra, CountingAlgebra, MarkovAlgebra
ProductFuzzy ProductFuzzyAlgebra
DualQuantale, CustomQuantale, QuantaleFromCallables DualAlgebra, CustomAlgebra, AlgebraFromCallables
QuantaleHomomorphism AlgebraHomomorphism
Algebra.compatible_quantales() Algebra.compatible_algebras()
_QUANTALE_REGISTRY, _register_extra_quantales _ALGEBRA_REGISTRY, _register_extra_algebras
compiler env binding __quantale__ __algebra__
QuantaleDecl AST node AlgebraDecl
quivers.core.quantales module quivers.core.algebras
quivers.core.quantale_morphisms module quivers.core.algebra_morphisms
quivers.stochastic.quantale re-export deleted; import MarkovAlgebra, MARKOV from quivers.core.algebras
quivers.Algebra (Eilenberg-Moore monad algebra) quivers.MonadAlgebra (the public re-export; inside quivers.monadic.algebras the class is still named Algebra)

Singletons (PRODUCT_FUZZY, BOOLEAN, LUKASIEWICZ, GODEL, TROPICAL, MAX_PLUS, LOG_PROB, REAL, PROBABILITY, COUNTING, MARKOV, REICHENBACH, MATERIAL_IMPLICATION) keep their names. Registry key strings ("product_fuzzy", "boolean", ...) keep their names.

Other notable changes

  • Marginalize blocks now contribute to log_joint. The compile path was emitting the marginalize callable as a deterministic let, so its result was bound to env but never added to total — log_joint was empirically constant in the body's observed data, and inference reduced to fitting the prior. Introduces _ScoreSpec, a step whose callable is both bound and added to total. Inner blocks in nested marginalize still emit a let (their reduction is consumed by the outer block, which is the score). Closes #21.
  • Regression examples corrected. Dropped the spurious x : Resp <- Normal(0, 1) predictor declarations from bayesian_regression, beta_regression, dirichlet_regression, horseshoe_regression, negbin_regression, zip_regression. Predictors are exogenous data and flow through the host-data channel as free variables in let expressions, not as latent draws.

Docs

  • New Analysis Pipelines guide covers the formula → fit → diagnostics surface end-to-end.
  • Major rewrite of the Enriched Category Theory guide against the actual APIs (Lens(whole=, focus_index=), Inclusion(coproduct=, component_index=), representable_weight(index_set=, represented_at=), Profunctor(contra=, co=, tensor=), end / coend, compose_optics).
  • Semantics docs updated: setting.md §1 no longer overclaims Kelly enrichment for every $\mathcal{V}$; algebras.md §2 is the canonical classification of which built-in algebras are strict quantales, which are residuated lattices, and which are commutative / saturated semirings.
  • Switched all positional FinSet("X", 3) / Euclidean("R", 2) calls in user-facing snippets to kwarg form (dx.Model rejects positional). The quickstart MonadicProgram example was rewritten against the real (vars, morphism, args) step-tuple shape.

CHANGELOG repair

A side effect of the factor-expressions PR (#20) was that the 0.5.0 unreleased section got renamed in-place to 0.6.0, leaving a gap at 0.5.0. This release reinstates 0.5.0 (dated 2026-05-13) carrying the V-Cat / MorphismTransformation / composition-rules / family-registry / axis-role-surface body; 0.6.0 (dated 2026-05-14) now carries only the factor expressions feature. No history was lost in the process.

Full Changelog: v0.6.0...v0.7.0