API reference¶
Compile FlatPPL modules into differentiable JAX functions.
The Rust compiler parses and types FlatPPL source and emits StableHLO. JAX runs
the program and Enzyme-JAX differentiates it. __all__ lists the public API.
The package exports the names below. Every other name, including the modules whose names start with an underscore, is private.
Modules from source¶
- flatppl.flatppl(source, *, context=None, name=None, source_path=None)¶
Parse inline FlatPPL source into a module.
The source sees no Python variables. Pass values with
Module.set()or as inputs of the compiled function.- Parameters:
source (str) – FlatPPL source text.
context (Context | None) – The owning context. The default creates a new one.
name (str | None) – The registry path that relative registry imports start from. Register the module under a name with
Context.register().source_path (str | PathLike[str] | None) – The host file that relative file imports start from, usually
__file__.
- Returns:
The parsed module.
- Raises:
CompilationError – The source does not parse or infer.
- Return type:
Example
>>> from flatppl import flatppl >>> float(flatppl("outputs = 2.0 + 3.0").compile()()) 5.0
- flatppl.load(path, *, context=None)¶
Load a FlatPPL file, directory, ZIP bundle or cached HTTP source.
This is
Context.load()with an optional context. Imports and data resolve relative to the loaded source. ZIP bundles extract no files.- Parameters:
- Returns:
The loaded module. Call
Module.compile()to compile a query.- Raises:
CompilationError – The source does not load, parse or infer.
- Return type:
- flatppl.from_pyhf(source, *, context=None, name=None, measurement=None, observations='bound', auxiliary='bound')¶
Convert a pyhf model or workspace into a FlatPPL module.
The bundled Rust converter does the conversion, so the
pyhfpackage is not needed. The result’sflatppl.Module.sourceholds the generated FlatPPL, andflatppl.Module.pyhfreads its fit settings and layout. Register it and write a query to compile it, or useflatppl.pyhf.PyhfView.logpdf(). See Import a pyhf model.- Parameters:
source (str | PathLike[str] | IO[str] | IO[bytes]) – JSON text, a path, or a readable text or binary stream. A string that starts with
{or[after whitespace is JSON text, and any other string is a path. Usepathlib.Pathfor an ambiguous filename. Files and byte streams are UTF-8, with an optional byte-order mark. A stream is read from its current position and stays open.context (Context | None) – The owning context. The default creates a new one.
name (str | None) – The registry path that relative registry imports start from.
measurement (str | None) – The workspace measurement whose configuration the likelihood uses. The default is the first, as in pyhf.
observations (Literal['bound', 'external']) –
"external"leaves every channel’s observed counts of a workspace as anexternalinput, so one module serves data, toys and Asimov data throughflatppl.Module.set()or query inputs. A model-only document has external observations either way.auxiliary (Literal['bound', 'external']) –
"external"reads every auxiliary constraint’s centre from one record input,pyhf_auxdata, with a field per constrained parameter in pyhf’sauxdata_order. The nominal centres are the view’sauxdata.
- Returns:
The converted module.
- Raises:
CompilationError – The conversion fails, with stage
"pyhf". This includes an unknown measurement name, and a measurement named for a model-only document.ValueError –
observationsorauxiliaryis not"bound"or"external".OSError – The file cannot be read.
UnicodeDecodeError – The bytes are not UTF-8.
- Return type:
- flatppl.from_formula(formula, data, family='gaussian', priors=None, *, link=None, dpars=None, context=None, name=None, **options)¶
Convert a formula and training table to an immutable FlatPPL module.
The Rust frontend handles the supported brms formula subset and diagnoses unsupported families, terms, priors and options. The returned module has its training data bound;
flatppl.Module.formularetains the template and recipe for preparing new data.- Parameters:
formula (str) – An R-style formula, such as
"y ~ x + group".data (object) – A CSV, JSON or Arrow IPC path, or a pandas or Polars dataframe, Arrow table or record batch, another dataframe interchange producer, or a mapping of column names to arrays. Categories, numeric precision and nulls reach Rust intact.
family (str) – The observation family. Rust selects its default link.
priors (Sequence[Mapping[str, object]] | None) – Prior entries, for example
[{"class": "b", "prior": "Normal(0, 2)"}]. Omitted entries use the frontend’s brms defaults, including improper Lebesgue priors for ordinary regression coefficients.dpars (Mapping[str, Mapping[str, object]] | None) – Formulas for family parameters, for example
{"sigma": {"formula": "sigma ~ x", "link": "log"}}. Rust validates each predictor and chooses any omitted link.context (Context | None) – The owning context. The default creates a new one.
name (str | None) – The registry path that relative registry imports start from.
**options (object) – Rust converter options, such as
centerandcontrasts.
- Returns:
The training module, with generated source and formula metadata.
- Raises:
CompilationError – Rust cannot convert the specification or table.
TypeError – The data cannot be transported as a table.
ValueError – The table has duplicate column names.
- Return type:
Context¶
- class flatppl.Context¶
An append-only registry of source snapshots and module names.
Modules that import each other by name share one context. A new context starts empty. Names cannot be replaced once registered.
Equality compares registered names and their source, imports and data using cached content hashes. File caches and compiled functions are excluded. The first comparison reads any data not yet loaded and may raise
CompilationErrorif a dependency is missing. Contexts are mutable and cannot be dictionary keys.- load(path)¶
Load a file, directory, ZIP bundle or cached HTTP source.
A directory or ZIP loads its
main.flatppl. Loading a ZIP extracts no files. The first load takes a snapshot; later loads in this context reuse it.- Parameters:
path (str | PathLike[str]) – The file, directory or ZIP archive to load.
- Returns:
The loaded module.
- Raises:
CompilationError – The source does not load, parse or infer.
- Return type:
- load_bundle(name, data)¶
Load a ZIP snapshot from bytes without extracting files.
Imports and data resolve inside the archive. Each call creates an independent snapshot;
namelabels it and does not register it.- Parameters:
- Returns:
The module loaded from the archive’s
main.flatppl.- Raises:
CompilationError – The archive or its model is invalid.
- Return type:
- register(name, module)¶
Register a module under a name that other modules import.
Registration does not change the module’s own origin.
- Parameters:
- Raises:
CompilationError – The name is taken or invalid.
Module¶
- class flatppl.Module¶
An immutable FlatPPL definition with a fixed dependency closure.
Get modules from
flatppl(),load(),from_pyhf(),from_formula()orContext.load(). A module that declaresinputsandoutputsis a query, andcompile()turns it into a JAX function.Attribute access such as
module.thetareturns the bindingthetaunless a Python attribute has that name. Usebindingsfor those.Equality and hashing compare source, imports and data content. File paths, ZIP encoding and Python compile options are excluded. This is content identity, not mathematical equivalence. The first comparison or hash reads any data not yet loaded and may raise
CompilationError.- pack(*, include_context=False)¶
Export this module and its dependencies as a portable ZIP archive.
The archive contains
main.flatppland every referenced module and data file. Source text is retained except for paths that must change. Bound or sliced modules export their effective definitions. Usesave()to write the archive directly to a path.- Parameters:
include_context (bool) – Also include every registered module in this module’s context. Loading the archive restores those names. The default includes only this module and its dependencies.
- Returns:
ZIP bytes, using standard Deflate compression.
- Raises:
CompilationError – A dependency is missing or its path is not fixed.
- Return type:
- save(path, *, include_context=False)¶
Save this module, its imports and data as a portable ZIP bundle.
Use
load()to reopen it. The archive is built before the file is opened, so a missing dependency leaves an existing file unchanged.- Parameters:
- Raises:
CompilationError – A dependency is missing or its path is not fixed.
OSError – The destination cannot be written.
- property bindings: Mapping[str, Binding]¶
All public bindings by name, including names that Python attributes hide.
- property parameters: Parameters¶
The free parameters, the bindings written as
elementof(set).A module with a converter’s settings record adds each parameter’s fit settings, such as a pyhf import’s selected measurement. See
Parameter.
- property pyhf: PyhfView¶
The pyhf view of a module that
from_pyhf()converted.It reads the selected measurement’s settings record. See
flatppl.pyhf.PyhfView.- Raises:
AttributeError – The module has no pyhf settings record.
- property formula: flatppl.formula.FormulaView¶
The training recipe and metadata of a formula import.
See
flatppl.formula.FormulaViewfor preparing new data without changing the training module.- Raises:
AttributeError – The module was not created from a formula.
- constant(name)¶
Read a binding’s right-hand side back as a Python value.
The read is structural and evaluates nothing. Numbers, booleans and strings read back as Python scalars,
infandpias floats, arrays as NumPy arrays, records and tables as dicts, and tuples as tuples.fixed(x)reads back asFixedand a reference to another binding asReference.- Parameters:
name (str) – A public binding whose right-hand side is a literal.
- Returns:
The value.
- Raises:
CompilationError – No public binding has that name, or its right-hand side is not a literal, with stage
"constant".- Return type:
Example
>>> from flatppl import flatppl >>> module = flatppl(''' ... mu = elementof(reals) ... point = record(mu = 0.5, sigma = fixed(1.0), poi = mu) ... ''') >>> module.constant("point") {'mu': 0.5, 'sigma': Fixed(value=1.0), 'poi': Reference(name='mu')}
- query(outputs, *, inputs='parameters', layout='record', gradient=False)¶
Build a query over this module’s bindings.
The query is ordinary FlatPPL, visible through
source. It loads this module under a fresh name in the same context, so each call adds one registry entry. Compile the result withcompile().- Parameters:
outputs (str | Sequence[str] | Mapping[str, str]) – A binding name, a sequence of names, or a mapping from result name to a FlatPPL expression over this module’s public bindings. A draw, or anything that depends on one, cannot be an output, because a loaded module hides stochastic bindings.
inputs (Literal['parameters'] | ~collections.abc.Sequence[str]) –
"parameters"for every free parameter the outputs depend on, or the names of parameters and externals.layout (Literal['record', 'flat']) –
"record"passes the parameters as one recordpoint."flat"passes them as one real vectorthetain declaration order, which suits samplers. It holds scalar and vector parameters with real elements, and refuses matrix, record, integer and boolean parameters. A positionalcartprodtakes all scalars or all vectors, so each scalar becomes a length-one vector, such ascartpow(posreals, 1). Each parameter’s set is kept in the domain ofthetabut not enforced at run time. Usecompile_transformed()for unconstrained coordinates.gradient (bool) – Compile to a function that returns
(outputs, jacobian), with the Jacobian of the outputs with respect to the parameter input. For a scalar output it is the gradient.
- Returns:
The query module.
- Raises:
ValueError – An output or input is not allowed, a parameter domain is unknown or has a size not bound yet, or the flat layout cannot hold a parameter. The message names the binding.
CompilationError – The generated query does not infer.
- Return type:
Example
>>> import jax >>> from flatppl import flatppl >>> model = flatppl(''' ... mu = elementof(reals) ... sigma = elementof(posreals) ... prior = lawof(record(mu = mu, sigma = sigma)) ... shifted = mu + 2.0 * sigma ... ''') >>> query = model.query("shifted", gradient=True) >>> value, jacobian = query.compile()({"mu": 1.0, "sigma": 0.5}) >>> float(value), float(jacobian["sigma"]) (2.0, 2.0)
- upstream(name)¶
Return every public binding that
namedepends on, in source order.
- downstream(name)¶
Return every public binding that depends on
name, in source order.
- slice(outputs)¶
Return a module with only the bindings that
outputsreach.The slice is printed and parsed again in the same context, so its
sourceand positions refer to the printed text. Imports and values bound byset()carry over.- Parameters:
outputs (str | Sequence[str]) – The binding names to keep, with everything they reach.
- Returns:
The sliced module.
- Raises:
CompilationError – A name is not a public binding.
- Return type:
- math(format='tex')¶
Render every binding as mathematics.
- Parameters:
format (Literal['tex', 'mathml', 'typst']) –
"tex","mathml"or"typst".- Returns:
Each binding’s statement by name, in source order, including private bindings.
- Raises:
ValueError – The format is unknown.
- Return type:
- set(**constants)¶
Return a new module with declared externals bound to fixed values.
Dependent sizes resolve after all values are bound, values are checked against their declared domains, and bound names leave
inputs. Values are copied, so later changes to a host array do not reach the module. The original module stays usable, for example with other sizes. Register the result in the context to import the bound definition.- Parameters:
**constants (object) – Values by external name. A value is a scalar, a numeric array, a mapping for a record, a tuple, or a table from a dataframe or any Arrow producer.
- Returns:
The bound module.
- Raises:
TypeError – A value has an unsupported kind or element type.
ValueError – A table holds nulls or repeated column names.
CompilationError – A name is not an external, or a value lies outside its domain.
- Return type:
Example
>>> from flatppl import flatppl >>> module = flatppl(''' ... n = external(posintegers) ... x = elementof(cartpow(reals, n)) ... inputs = x ... outputs = sum(x) ... ''') >>> float(module.set(n=3).compile()([1.0, 2.0, 3.0])) 6.0
- compile(*, dtype='float32', autodiff=True, integration=None, optimize_forward=False, target=None, boxes=None, checks='nan')¶
Compile the module’s
inputsandoutputsinto a JAX function.The module caches exports per dtype, autodiff mode, integration settings and target, so a repeated call skips the Rust compiler.
- Parameters:
dtype (jax.typing.DTypeLike) –
"float32"or"float64", or an equal JAX dtype. Float64 needsjax.config.update("jax_enable_x64", True)before this call.autodiff (bool) – Emit a program that Enzyme can differentiate.
Falseselects generic emission for value-only queries such as sampling, and JAX differentiation then raisesTypeError.integration (Integration | None) – Allow numerical scalar marginals and normalizers with these settings. The default requires an exact lowering.
optimize_forward (bool) – Apply extra Enzyme passes to forward calls of programs without loops. Differentiation keeps its own passes.
target (Literal['cpu', 'gpu'] | None) – The
"cpu"or"gpu"lowering profile. The default followsjax.default_backend(). Both run on any backend and give the same values.boxes (Mapping[str, Box] | None) – Black boxes for the module’s interface modules, keyed by the
load_modulealias that loads each interface. Box queries run on the box server. See Black boxes.checks (Literal['nan', 'raise']) – How a distribution parameter outside its declared value set, such as
sigma <= 0forNormal, reports."nan"makes that call’s floating-point results NaN, needs nocheckify, and lets a sampler reject the point."raise"reports it throughcheckifylike the other runtime checks. Index, solve and seed checks raise in both modes. See JAX and differentiation.
- Returns:
The compiled function.
- Raises:
CompilationError – The module does not lower to a query.
TypeError –
integrationis not anIntegration.ValueError – The dtype is unsupported or needs JAX x64, or
checksis neither"nan"nor"raise".
- Return type:
Example
>>> import jax >>> from flatppl import flatppl >>> query = flatppl(''' ... x = elementof(reals) ... inputs = x ... outputs = logdensityof(Normal(mu = 0.0, sigma = 1.0), x) ... ''') >>> logdensity = query.compile() >>> round(float(logdensity(0.0)), 6), float(jax.grad(logdensity)(1.0)) (-0.918939, -1.0)
- compile_transformed(*, logdensity=False, dtype='float32', autodiff=True, integration=None, optimize_forward=False, target=None, checks='nan')¶
Compile a query and canonical coordinate wrappers for its input.
The query must have one continuous
elementofinput, which may be a record or array of parameters. Bind fixed data before compiling. Rust chooses the transforms from the declared domains and emits them with the query into StableHLO. No Python callback runs during execution.- Parameters:
logdensity (bool) – Add the change-of-variables correction to a scalar log density with respect to the input domain’s coordinate Lebesgue measure. Use
Truefor NUTS. Ordinary functions keep the defaultFalseand only transform their inputs.dtype (jax.typing.DTypeLike) – Floating-point precision, as in
compile().integration (Integration | None) – Numerical integration settings, as in
compile().optimize_forward (bool) – Enable extra Enzyme passes, as in
compile().target (Literal['cpu', 'gpu'] | None) – Lowering profile, as in
compile().checks (Literal['nan', 'raise']) – Parameter value-set reporting, as in
compile().
- Returns:
The original query, the unconstrained query, and both coordinate transforms. Use
unconstrainfor initial values andconstrainfor retained draws. See Fit a mixed model with automatic coordinate transforms for a BlackJAX example.- Raises:
CompilationError – The input has no supported continuous chart, sizes or bounds are unresolved, the query has several inputs, or log-density mode receives a non-scalar output.
ValueError – The query requests a gradient instead of a scalar value.
- Return type:
- logdensity(measure=None, *, unconstrained=True, jacobian=True, bounds=True, dtype='float32', target=None, integration=None, optimize_forward=False)¶
Prepare a log density for a sampler or an optimiser.
measurenames a binding of this module:A measure, such as a prior or a posterior: the position is its variate on its support, a dict for a measure on a record such as
lawof(record(theta = theta, s = s))or a posterior of it.A likelihood: the position is a record of its interface inputs, under their interface names, so
kernelof(y, a = theta)givesa. Each input takes the support of the value its boundary binds. A converter’s settings record, such as a pyhf measurement, supplies initial values, fit bounds and fixed components for the inputs it names. Fixed components leave the position and keep their initial values.
Without
measurethis module is a query with one continuouselementofinput and a scalar log-density output, as forcompile_transformed(), and the position is that input.- Parameters:
measure (str | None) – A measure or likelihood binding of this module, or
Nonewhen this module is the query.unconstrained (bool) – Take positions in unconstrained coordinates, where every real vector is valid.
Falsetakes model parameters.jacobian (bool) – Add the log-Jacobian of the coordinate map, so the density is that of the unconstrained coordinates. Use
Truefor sampling andFalsefor maximum likelihood or maximum a posteriori fits in unconstrained coordinates. It has no effect whenunconstrainedisFalse.bounds (bool) – For a likelihood, narrow each real parameter’s set to its converter fit bounds, intersected with its declared set. The density then has the bounds as its support.
dtype (jax.typing.DTypeLike) – Floating-point precision, as in
compile().target (Literal['cpu', 'gpu'] | None) – Lowering profile, as in
compile().integration (Integration | None) – Numerical integration settings, as in
compile().optimize_forward (bool) – Enable extra Enzyme passes, as in
compile().
- Returns:
The log density, its gradient, starting point, coordinate maps and parameter metadata. See
flatppl.inference.LogDensity.- Raises:
CompilationError – The support has no supported continuous chart, or the query has several inputs or a non-scalar output.
ValueError –
measureis not a measure or a likelihood, its support is unknown or has an extent not bound yet, a likelihood depends on an unbound external, on no parameter or only on fixed ones, the initial point lies on a domain boundary, or the query requests a gradient instead of a scalar value.
- Return type:
Example
>>> from flatppl import flatppl >>> model = flatppl(''' ... rate ~ Gamma(shape = 2.0, rate = 1.0) ... prior = lawof(record(rate = rate)) ... ''') >>> density = model.logdensity("prior") >>> point = density.constrain(density.init) >>> float(point["rate"]), float(density.grad(density.init)["rate"]) (1.0, 1.0)
Binding¶
- class flatppl.Binding¶
A public binding of a module and its inferred metadata.
Get bindings from
Module.bindingsor by attribute access on a module. A binding is a handle, not a value: it supports no arithmetic and no evaluation.- module¶
The module that owns the binding.
- Type:
- kind¶
"parameter"forelementof,"observation"forexternalorload_data,"draw"forx ~ measure, and"derived"for everything else, including values bound byModule.set().- Type:
Literal[‘parameter’, ‘observation’, ‘draw’, ‘derived’]
- domain¶
The inferred value set as a read-only tree, or
None. Each node has a"set"key: a named set such as"reals"or"posintegers","interval"with"lo"and"hi"(numbers, or"-inf"and"inf"),"stdsimplex","ordered"or"zerosum"with"n","cartpow"with"of"and"shape","cartprod"with a tuple"of","record"with"fields"of"name"and"set", or"unknown". An extent thatModule.set()binds later isNone.- Type:
collections.abc.Mapping[str, Any] | None
- shape¶
The array extents,
()for a scalar,Nonefor an extent not known yet, andNoneoverall for records, tuples, tables and non-values.
- size¶
The number of scalar elements, or
Nonewhen an extent is not known yet or the binding is not a value.
- span¶
Byte offsets
(start, end)of the right-hand side inModule.source, orNone.
- source¶
The right-hand side as written, or
Nonefor a value bound byModule.set(). A draw shows its whole statement.
- location¶
Where the right-hand side starts, or
None.- Type:
- dependencies¶
The public bindings that this one references directly, in source order. References through private bindings count.
- inputs¶
For a kernel or a likelihood, each interface input’s domain tree by input name, in interface order: the support of the value its boundary binds.
Nonefor other bindings.- Type:
collections.abc.Mapping[str, collections.abc.Mapping[str, Any]] | None
Example
>>> from flatppl import flatppl >>> module = flatppl(''' ... x = elementof(interval(0.0, inf)) ... y = 2.0 * x ... ''') >>> module.x.kind, dict(module.x.domain) ('parameter', {'set': 'interval', 'lo': 0.0, 'hi': 'inf'}) >>> module.y.source, module.y.location.line, module.y.dependencies ('2.0 * x', 3, ('x',))
- math(format='tex')¶
Render this binding as mathematics.
- Parameters:
format (Literal['tex', 'mathml', 'typst']) –
"tex","mathml"or"typst".- Returns:
The binding’s statement in that notation.
- Return type:
Example
>>> from flatppl import flatppl >>> module = flatppl("theta ~ Normal(mu = 0.0, sigma = 1.0)") >>> module.theta.math() 'θ \\sim \\mathcal{N}\\left(0, 1\\right)'
Graph¶
- class flatppl.Graph(nodes, edges, bindings)¶
The public bindings of a module as a directed acyclic graph.
An edge
(a, b)means thatbreferencesadirectly, or through private bindings. Get a graph fromModule.graph().- edges¶
Pairs
(dependency, dependent)in source order of the dependent.
- bindings¶
The bindings by name.
Example
>>> from flatppl import flatppl >>> graph = flatppl(''' ... mu = elementof(reals) ... y = 2.0 * mu ... ''').graph() >>> graph.edges (('mu', 'y'),) >>> print(graph.to_dot()) digraph { "mu"; "y"; "mu" -> "y"; }
- to_networkx()¶
Return a
networkx.DiGraphwith each binding’s metadata on its node.- Raises:
ImportError – networkx is not installed.
- Return type:
Parameters¶
- class flatppl.Parameters(parameters)¶
The free parameters of a module by name, in source order.
Get it from
Module.parameters. It reads the module’s inferred domains, and the fit settings of the converter’s settings record when the module has one, such as a pyhf import’s selected measurement.Example
>>> from flatppl import flatppl >>> module = flatppl(''' ... mu = elementof(reals) ... sigma = elementof(posreals) ... n = external(posintegers) ... ''') >>> list(module.parameters), module.parameters["sigma"].domain["set"] (['mu', 'sigma'], 'posreals')
- class flatppl.Parameter¶
A free parameter of a module: a binding written as
elementof(set).The fit settings come from the converter’s settings record, and are
Nonefor a module without one. A pyhf import is one source: its selected measurement supplies them. A scalar parameter has scalar settings. A vector parameter has one value per component.- domain¶
The inferred value set, as in
Binding.domain.- Type:
collections.abc.Mapping[str, Any] | None
- size¶
The number of scalar elements, as in
Binding.size.
- binding¶
The binding itself.
- Type:
- init¶
The suggested initial value.
- lo¶
The suggested lower bound. It is a fit range, not the domain.
- hi¶
The suggested upper bound.
- fixed¶
Whether a fit holds the value, per component.
- Type:
bool | numpy._typing._array_like.NDArray[numpy.bool] | None
- constraint¶
The auxiliary constraint’s family,
"normal"or"poisson", orNonefor an unconstrained parameter.- Type:
Literal[‘normal’, ‘poisson’] | None
- width¶
The auxiliary constraint’s width.
- centre¶
The auxiliary constraint’s nominal centre, the value its auxiliary measurement observes.
- original_name¶
The parameter’s name in the imported format, which differs from
namewhen it is not a FlatPPL identifier.
- role¶
"poi"for the parameter of interest, otherwiseNone.- Type:
Literal[‘poi’] | None
Values read back¶
- class flatppl.Fixed(value)¶
A value that a module’s source marks as
fixed(value).Module.constant()returns it for converter records, such as HS3 parameter points, wherefixedpins a parameter.
- class flatppl.Reference(name)¶
A reference to another binding, read from a module’s source.
Module.constant()returns it where a record names a binding instead of holding a value, such as the parameter of interest in a pyhf measurement.
pyhf¶
Import pyhf models and read them the way pyhf lays them out.
flatppl.pyhf.from_pyhf() converts a pyhf model or workspace with the bundled Rust
converter. The converter writes each measurement’s fit settings and channel
layout into a literal record, and flatppl.Module.pyhf reads the
selected one as a PyhfView: pyhf’s parameter order and flat vector
layout, the suggested fit settings, the auxiliary data and the channels, plus
logpdf and expected_data functions over pyhf’s flat vectors. See
Import a pyhf model.
- flatppl.pyhf.from_pyhf(source, *, context=None, name=None, measurement=None, observations='bound', auxiliary='bound')¶
Convert a pyhf model or workspace into a FlatPPL module.
The bundled Rust converter does the conversion, so the
pyhfpackage is not needed. The result’sflatppl.Module.sourceholds the generated FlatPPL, andflatppl.Module.pyhfreads its fit settings and layout. Register it and write a query to compile it, or useflatppl.pyhf.PyhfView.logpdf(). See Import a pyhf model.- Parameters:
source (str | PathLike[str] | IO[str] | IO[bytes]) – JSON text, a path, or a readable text or binary stream. A string that starts with
{or[after whitespace is JSON text, and any other string is a path. Usepathlib.Pathfor an ambiguous filename. Files and byte streams are UTF-8, with an optional byte-order mark. A stream is read from its current position and stays open.context (Context | None) – The owning context. The default creates a new one.
name (str | None) – The registry path that relative registry imports start from.
measurement (str | None) – The workspace measurement whose configuration the likelihood uses. The default is the first, as in pyhf.
observations (Literal['bound', 'external']) –
"external"leaves every channel’s observed counts of a workspace as anexternalinput, so one module serves data, toys and Asimov data throughflatppl.Module.set()or query inputs. A model-only document has external observations either way.auxiliary (Literal['bound', 'external']) –
"external"reads every auxiliary constraint’s centre from one record input,pyhf_auxdata, with a field per constrained parameter in pyhf’sauxdata_order. The nominal centres are the view’sauxdata.
- Returns:
The converted module.
- Raises:
CompilationError – The conversion fails, with stage
"pyhf". This includes an unknown measurement name, and a measurement named for a model-only document.ValueError –
observationsorauxiliaryis not"bound"or"external".OSError – The file cannot be read.
UnicodeDecodeError – The bytes are not UTF-8.
- Return type:
- class flatppl.pyhf.PyhfView¶
A converted pyhf module laid out the way pyhf lays out its model.
Get it from
flatppl.Module.pyhf. It reads the selected measurement’s settings record, which the converter writes, and nothing from thepyhfpackage. Names inpar_order,auxdata_orderandpoiare pyhf names.par_mapgives each one’s binding and its place in the flat parameter vector.- module¶
The converted module.
- Type:
- par_map¶
Each pyhf parameter’s binding and slice of the flat vector.
- auxdata_order¶
The constrained parameters in pyhf’s order, as
model.config.auxdata_order.
- auxdata¶
The nominal auxiliary data, flat, in
auxdata_order, asmodel.config.auxdata.- Type:
numpy._typing._array_like.NDArray[numpy.float64]
- channels¶
The channels in pyhf’s order, which sorts them by name.
- Type:
Example
>>> from flatppl import from_pyhf >>> model = from_pyhf('''{"channels": [{"name": "c", "samples": [ ... {"name": "s", "data": [5.0, 10.0], "modifiers": [ ... {"name": "mu", "type": "normfactor", "data": null}]}, ... {"name": "b", "data": [50.0, 60.0], "modifiers": [ ... {"name": "gamma", "type": "shapesys", "data": [5.0, 12.0]}]}]}], ... "observations": [{"name": "c", "data": [50.0, 60.0]}], ... "measurements": [{"name": "m", "config": {"poi": "mu"}}], ... "version": "1.0.0"}''') >>> view = model.pyhf >>> view.par_order, view.poi_index, view.auxdata.tolist() (('mu', 'gamma'), 0, [100.0, 25.0])
- property channel_slices: Mapping[str, slice]¶
Each channel’s bins in pyhf’s flat main data, by channel name.
- suggested_init()¶
Return the suggested initial values, flat, as pyhf’s
suggested_init.
- suggested_bounds()¶
Return the suggested bounds, flat, as pyhf’s
suggested_bounds.
- logpdf(dtype='float32')¶
Compile the full log-likelihood over pyhf’s flat vectors.
The function takes
pars, pyhf’s flat parameter vector, anddatawhen the import left inputs external.datais laid out as in pyhf: the main counts of every channel inchannelsorder when observations are external, then the auxiliary data inauxdata_orderwhen the centres are external. With bound observations and centres it takesparsalone. It returns a scalar where pyhf returns a one-element array, and it supportsjax.jit,jax.gradandjax.vmap.- Parameters:
dtype (jax.typing.DTypeLike) –
"float32"or"float64", as inflatppl.Module.compile().- Returns:
logpdf(pars)orlogpdf(pars, data). It raisesValueErrorwhendatais missing, not expected, or of the wrong length.- Raises:
CompilationError – The query does not compile.
- Return type:
- expected_data(dtype='float32', *, include_auxdata=False)¶
Compile the expected data over pyhf’s flat parameter vector.
The function takes
parsand returns every channel’s expected counts inchannelsorder, as pyhf’smodel.expected_data. Withinclude_auxdatathe expected auxiliary data follow inauxdata_order: the parameter itself for a Gaussian constraint, and the parameter times its rate factor for a Poisson one.- Parameters:
dtype (jax.typing.DTypeLike) –
"float32"or"float64", as inflatppl.Module.compile().include_auxdata (bool) – Append the expected auxiliary data.
- Returns:
expected_data(pars).- Raises:
CompilationError – The query does not compile.
- Return type:
- class flatppl.pyhf.ParameterSlice¶
Where one pyhf parameter sits in pyhf’s flat parameter vector.
- name¶
The module’s binding for the parameter. It differs from the pyhf name when that is not a FlatPPL identifier.
- Type:
- class flatppl.pyhf.Channel¶
One channel of a pyhf model.
flatppl.from_pyhf is the same function, re-exported at the top level.
Formulas¶
Build FlatPPL regression modules with the bundled Rust formula frontend.
Python transports tables and exposes the converter’s metadata. Formula parsing, contrasts, row selection and prior construction all run in Rust. See Regression formulas for training and prediction examples.
- flatppl.formula.from_formula(formula, data, family='gaussian', priors=None, *, link=None, dpars=None, context=None, name=None, **options)¶
Convert a formula and training table to an immutable FlatPPL module.
The Rust frontend handles the supported brms formula subset and diagnoses unsupported families, terms, priors and options. The returned module has its training data bound;
flatppl.Module.formularetains the template and recipe for preparing new data.- Parameters:
formula (str) – An R-style formula, such as
"y ~ x + group".data (object) – A CSV, JSON or Arrow IPC path, or a pandas or Polars dataframe, Arrow table or record batch, another dataframe interchange producer, or a mapping of column names to arrays. Categories, numeric precision and nulls reach Rust intact.
family (str) – The observation family. Rust selects its default link.
priors (Sequence[Mapping[str, object]] | None) – Prior entries, for example
[{"class": "b", "prior": "Normal(0, 2)"}]. Omitted entries use the frontend’s brms defaults, including improper Lebesgue priors for ordinary regression coefficients.dpars (Mapping[str, Mapping[str, object]] | None) – Formulas for family parameters, for example
{"sigma": {"formula": "sigma ~ x", "link": "log"}}. Rust validates each predictor and chooses any omitted link.context (Context | None) – The owning context. The default creates a new one.
name (str | None) – The registry path that relative registry imports start from.
**options (object) – Rust converter options, such as
centerandcontrasts.
- Returns:
The training module, with generated source and formula metadata.
- Raises:
CompilationError – Rust cannot convert the specification or table.
TypeError – The data cannot be transported as a table.
ValueError – The table has duplicate column names.
- Return type:
- class flatppl.formula.FormulaView¶
Read-only training metadata and a reusable data preparation recipe.
Get this view from
flatppl.Module.formula. The native converter owns the retained template; preparing new rows never changes the training data or refits its preprocessing state.- module¶
The module represented by this view.
- Type:
- info¶
The converter’s model metadata, including formula, family, design columns, parameter names and original training row indices.
- Type:
collections.abc.Mapping[str, Any]
- recipe¶
Training levels, contrasts, centring and prior defaults as a read-only tree. It is for inspection; preparation uses Rust’s copy.
- Type:
collections.abc.Mapping[str, Any]
- rows¶
Zero-based row positions retained from this module’s input table. These are positions, not pandas index labels.
- prepare(data, *, mode='prediction')¶
Bind a fresh module using this fit’s training recipe.
Prediction needs no response column. Rows missing required predictors are omitted by Rust and reported in the returned view’s
rows. Unseen factor/group levels are diagnosed instead of recoded.- Parameters:
data (object) – A table or file path accepted by
from_formula().mode (Literal['prediction', 'training']) –
"prediction"leaves observations external."training"also binds the supplied response for scoring, using the same recipe and prior defaults. Callfrom_formula()for a new fit or cross-validation fold that needs new defaults.
- Returns:
A new module in the same context, with its own row selection.
- Raises:
CompilationError – Data are incompatible with the training recipe.
- Return type:
flatppl.from_formula is the same function, re-exported at the top level.
Compiled functions¶
- class flatppl.CompiledFunction¶
A compiled query as a JAX function.
flatppl.Module.compile()returns instances. Calls take the query’s inputs and return its outputs as described in Python values and signatures. The function works underjax.jit,jax.grad,jax.vmapand sharding; see JAX and differentiation. Queries with runtime checks other than parameter value sets requirecheckify.checkifyaround the staged computation beforejax.jit, as doeschecks="raise".- schema¶
A read-only description of the interface with the keys
entry_point,inputs(entries withnameandvalue),output,multiple_outputsandoutput_names. Each value schema has akindoftensor(withindex,dtype,shapeandvalue_type),recordortable(withfields, androwsfor a table), ortuple(withitems).- Type:
collections.abc.Mapping[str, Any]
- __call__(*args, **kwargs)¶
Evaluate the query.
- Parameters:
- Returns:
An array, or a dict or tuple of arrays, as the query’s outputs declare. A query built with
gradient=Truereturns(outputs, jacobian)instead, with the Jacobian of the outputs with respect to the first input.- Raises:
TypeError – An input is missing, repeated or unknown, a record or table has other fields, or a value has the wrong element type.
ValueError – An array has the wrong shape, an integer does not fit its type, or the query needs JAX x64.
- Return type:
- stats()¶
Count the operations of the unbatched StableHLO program.
- Returns:
The number of operations of each kind, such as
"multiply"or"dot_general", sorted by name, and their"total".- Return type:
Example
>>> from flatppl import flatppl >>> function = flatppl(''' ... x = elementof(reals) ... inputs = x ... outputs = 2.0 * x ... ''').compile() >>> function.stats()["multiply"] 1
- example_input(fill=0.0)¶
Build inputs of the right structure, shapes and dtypes.
The result maps each input name to arrays filled with
fill, in the layout a call takes: records and tables as dicts, tuples as tuples. Use it as a starting point for a sampler, ajax.vmaptemplate or a test value.- Parameters:
fill (float) – The value of every element, cast to each element’s dtype.
- Returns:
The inputs by name, so
function(**function.example_input())runs.- Return type:
Example
>>> from flatppl import flatppl >>> query = flatppl(''' ... p = elementof(cartprod(mu = reals, x = cartpow(reals, 3))) ... inputs = p ... outputs = p.mu + sum(p.x) ... ''').compile() >>> point = query.example_input(1.0) >>> point["p"]["x"].shape, float(query(**point)) ((3,), 4.0)
- class flatppl.TransformedFunction¶
A query in constrained and unconstrained coordinates.
Build this with
flatppl.Module.compile_transformed(). All four functions execute StableHLO and support JAX transformations. The density correction, when requested, is part of the unconstrained StableHLO program.- constrained¶
The original compiled query.
- unconstrained¶
The query with transformed inputs. In log-density mode this includes the forward log-Jacobian exactly once.
- constrain¶
Map free coordinates to model parameters.
- unconstrain¶
Map interior model parameters to free coordinates. Boundary values can give infinite coordinates. Inputs are not clipped or repaired.
Inference¶
Prepare a log density for JAX inference and optimisation packages.
flatppl.Module.logdensity() returns a LogDensity: the log
density on a position pytree, a starting point in the same coordinates, the
coordinate maps, and the names, shapes, bounds and fixed components that
samplers, optimisers and diagnostics read. Every map is compiled StableHLO from
flatppl.Module.compile_transformed().
The package ships no adapter for any inference package. The Worked tutorials shows each package on these fields.
- class flatppl.inference.LogDensity¶
A scalar log density prepared for samplers and optimisers.
Get it from
flatppl.Module.logdensity(). A position is the query’s input: a dict for a record input, otherwise an array. In unconstrained coordinates every real vector is a valid position, andfnincludes the log-Jacobian ofconstrainunlessjacobian=False.- fn¶
The log density of a position. It supports
jax.jit,jax.gradandjax.vmap. Calling the object calls it.- Type:
collections.abc.Callable[[Any], jax.Array]
- grad¶
The gradient of
fn, jitted.- Type:
collections.abc.Callable[[Any], Any]
- potential¶
The negated log density, jitted. Optimisers and NumPyro minimise this sign.
- Type:
collections.abc.Callable[[Any], jax.Array]
- init¶
A starting position in the coordinates of
fn: a converter’s initial values for a likelihood that has them, otherwise the point at zero unconstrained coordinates, such as 1 forposrealsand the midpoint of a finite interval.- Type:
Any
- constrain¶
Map unconstrained coordinates to model parameters.
- Type:
collections.abc.Callable[[Any], Any]
- unconstrain¶
Map interior model parameters to unconstrained coordinates.
- Type:
collections.abc.Callable[[Any], Any]
- shapes¶
Each parameter’s shape in model coordinates.
- Type:
collections.abc.Mapping[str, tuple[int, …]]
- bounds¶
(lower, upper), two pytrees shaped like a position in model coordinates, with each element’s bounds and infinities where a set has none.- Type:
tuple[Any, Any]
- fixed¶
For a likelihood, each parameter’s fixed components, as a bool or a bool array. The position omits them and the density holds them at their initial values. Empty for a measure or a query.
- Type:
collections.abc.Mapping[str, bool | numpy._typing._array_like.NDArray[numpy.bool]]
- flat¶
The same density over one flat vector.
- transformed¶
The compiled functions behind these fields.
- class flatppl.inference.FlatLogDensity¶
A
LogDensityover one flat vector.The vector holds the leaves of
LogDensity.initin JAX’s pytree order, which sorts record fields by name. Use it for packages that take a flat array, such as iminuit and nutpie.- fn¶
The log density of a vector.
- Type:
- potential¶
The negated log density, for minimisers.
- Type:
- unravel¶
Map a vector back to the position pytree.
- Type:
collections.abc.Callable[[jax.Array], Any]
Black boxes¶
- class flatppl.Box(url, name, *, token=None, timeout=600.0, upload_threshold=65536)¶
A black box served over the flatppl-bridge protocol.
Pass boxes to
flatppl.Module.compile()to bind a model’s interface modules. The model never names a server: the binding maps aload_modulealias of the model to a box.- Parameters:
url (str) – The server root, such as
"http://127.0.0.1:8737".name (str) – The box name on that server.
token (str | None) – A bearer token for the
Authorizationheader, if the server requires one.timeout (float) – Seconds to wait for one HTTP request.
upload_threshold (int) – Data parts of at least this many bytes travel once to the server’s content store and are then referenced by hash.
Example
>>> from flatppl import Box >>> Box("http://127.0.0.1:8737", "stan") Box('http://127.0.0.1:8737', 'stan')
- exception flatppl.BoxError(status, title, detail, missing=())¶
A box server refused or failed a request.
- status¶
The HTTP status code: 400 for a malformed request, 404 for missing content, 422 for an unsupported query and 500 for a box failure.
- title¶
The short problem title the server sent.
- detail¶
The server’s explanation.
- missing¶
For a 404, the content hashes the server’s store lacks.
Integration¶
- class flatppl.Integration(rtol=1e-05, atol=0.0, max_intervals=128)¶
Settings for adaptive scalar quadrature.
Pass an instance to
Module.compile()to allow numerical scalar marginals and normalizers where no exact rule applies. The tolerances bound the estimated absolute error of the integral before its logarithm:error <= max(atol, rtol * integral). They do not bound the error of derivatives, which follow the selected quadrature mesh. A failed convergence returns NaN. The compiler checks the values: both tolerances finite and nonnegative with at least one positive, andmax_intervalsin2..2**31-1.
Diagnostics¶
- exception flatppl.CompilationError(diagnostic)¶
A compiler diagnostic raised while loading, parsing, inferring or compiling.
str(error)starts withsource:line:column: stage: messageand shows the source line with a caret under the column, when the position is known. JAX and Enzyme raise their own errors while tracing or running a compiled function.- stage¶
The compiler stage, such as
"parse","infer"or"pyhf".
- source¶
The label or path of the source that failed.
- span¶
Byte offsets
(start, end)into that source, orNone.
- location¶
Where the span starts, or
None.
- excerpt¶
The source line the span starts on, or
None.
- import_chain¶
The labels of the importing sources, outermost first.
- message¶
The diagnostic text.