Repository navigation
v0.7.0
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)matchesstats::poly(korthonormal centred columns). Raw monomials stay available viaI(x**k). - One coefficient per design-matrix column.
poly(x, 2)producesbeta_poly_x_2_1andbeta_poly_x_2_2;x*zproducesbeta_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,tanhresolve 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 aHalfNormalscale 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_datatreewraps quivers' per-site sample tensors, log-densities, acceptance rates, and divergences into the canonical ArviZ groups.comparedelegates to ArviZ's PSIS-LOO ranking (Yao et al. 2018) for ranked model comparison plus stacking weights.posterior_predictive_checkcomputes 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_pitre-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
| 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 toenvbut never added tototal—log_jointwas 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 tototal. 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 frombayesian_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 inletexpressions, 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.Modelrejects positional). The quickstartMonadicProgramexample 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