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:

Module

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:
  • path (str | PathLike[str]) – The file, directory, ZIP archive or HTTP URL to load.

  • context (Context | None) – The owning context. The default creates a new one. Pass an existing context to share its source snapshots and registry.

Returns:

The loaded module. Call Module.compile() to compile a query.

Raises:

CompilationError – The source does not load, parse or infer.

Return type:

Module

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 pyhf package is not needed. The result’s flatppl.Module.source holds the generated FlatPPL, and flatppl.Module.pyhf reads its fit settings and layout. Register it and write a query to compile it, or use flatppl.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. Use pathlib.Path for 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 an external input, so one module serves data, toys and Asimov data through flatppl.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’s auxdata_order. The nominal centres are the view’s auxdata.

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 – observations or auxiliary is not "bound" or "external".

  • OSError – The file cannot be read.

  • UnicodeDecodeError – The bytes are not UTF-8.

Return type:

Module

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.formula retains 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.

  • link (str | None) – Override the family’s default link.

  • 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 center and contrasts.

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:

Module

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 CompilationError if 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:

Module

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; name labels it and does not register it.

Parameters:
  • name (str) – A diagnostic label, such as "model.flatppl.zip".

  • data (bytes) – The complete ZIP archive bytes.

Returns:

The module loaded from the archive’s main.flatppl.

Raises:

CompilationError – The archive or its model is invalid.

Return type:

Module

register(name, module)

Register a module under a name that other modules import.

Registration does not change the module’s own origin.

Parameters:
  • name (str) – A relative registry path, such as "model.flatppl".

  • module (Module) – A module from this context.

Raises:

Module

class flatppl.Module

An immutable FlatPPL definition with a fixed dependency closure.

Get modules from flatppl(), load(), from_pyhf(), from_formula() or Context.load(). A module that declares inputs and outputs is a query, and compile() turns it into a JAX function.

Attribute access such as module.theta returns the binding theta unless a Python attribute has that name. Use bindings for 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.

property context: Context

The context that owns this module.

property source: str

The FlatPPL source text. Imported pyhf models show generated source.

property source_name: str

The label that diagnostics use for this module’s source.

pack(*, include_context=False)

Export this module and its dependencies as a portable ZIP archive.

The archive contains main.flatppl and every referenced module and data file. Source text is retained except for paths that must change. Bound or sliced modules export their effective definitions. Use save() 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:

bytes

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:
  • path (str | PathLike[str]) – The destination ZIP path, usually ending in .flatppl.zip. An existing file is replaced.

  • include_context (bool) – Include all modules registered in this module’s context, as in pack().

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.FormulaView for 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, inf and pi as floats, arrays as NumPy arrays, records and tables as dicts, and tuples as tuples. fixed(x) reads back as Fixed and a reference to another binding as Reference.

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:

object

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 with compile().

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 record point. "flat" passes them as one real vector theta in declaration order, which suits samplers. It holds scalar and vector parameters with real elements, and refuses matrix, record, integer and boolean parameters. A positional cartprod takes all scalars or all vectors, so each scalar becomes a length-one vector, such as cartpow(posreals, 1). Each parameter’s set is kept in the domain of theta but not enforced at run time. Use compile_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:

Module

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)
graph()

Return the dependency graph of the public bindings.

Return type:

Graph

upstream(name)

Return every public binding that name depends on, in source order.

Raises:

KeyError – No public binding has that name.

Return type:

tuple[str, …]

downstream(name)

Return every public binding that depends on name, in source order.

Raises:

KeyError – No public binding has that name.

Return type:

tuple[str, …]

slice(outputs)

Return a module with only the bindings that outputs reach.

The slice is printed and parsed again in the same context, so its source and positions refer to the printed text. Imports and values bound by set() 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:

Module

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:

Mapping[str, str]

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:

Module

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 inputs and outputs into 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 needs jax.config.update("jax_enable_x64", True) before this call.

  • autodiff (bool) – Emit a program that Enzyme can differentiate. False selects generic emission for value-only queries such as sampling, and JAX differentiation then raises TypeError.

  • 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 follows jax.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_module alias 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 <= 0 for Normal, reports. "nan" makes that call’s floating-point results NaN, needs no checkify, and lets a sampler reject the point. "raise" reports it through checkify like the other runtime checks. Index, solve and seed checks raise in both modes. See JAX and differentiation.

Returns:

The compiled function.

Raises:
Return type:

flatppl.CompiledFunction

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 elementof input, 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 True for NUTS. Ordinary functions keep the default False and only transform their inputs.

  • dtype (jax.typing.DTypeLike) – Floating-point precision, as in compile().

  • autodiff (bool) – Enable differentiation, 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 unconstrain for initial values and constrain for 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:

flatppl.TransformedFunction

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.

measure names 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) gives a. 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 measure this module is a query with one continuous elementof input and a scalar log-density output, as for compile_transformed(), and the position is that input.

Parameters:
  • measure (str | None) – A measure or likelihood binding of this module, or None when this module is the query.

  • unconstrained (bool) – Take positions in unconstrained coordinates, where every real vector is valid. False takes model parameters.

  • jacobian (bool) – Add the log-Jacobian of the coordinate map, so the density is that of the unconstrained coordinates. Use True for sampling and False for maximum likelihood or maximum a posteriori fits in unconstrained coordinates. It has no effect when unconstrained is False.

  • 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 – measure is 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:

flatppl.inference.LogDensity

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.bindings or 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:

flatppl._api.Module

name

The FlatPPL binding name.

Type:

str

kind

"parameter" for elementof, "observation" for external or load_data, "draw" for x ~ measure, and "derived" for everything else, including values bound by Module.set().

Type:

Literal[‘parameter’, ‘observation’, ‘draw’, ‘derived’]

value_type

The inferred type as text, such as "real[3]", or None.

Type:

str | None

phase

The inferred phase as text, such as "fixed" or "parametric", or None.

Type:

str | None

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 that Module.set() binds later is None.

Type:

collections.abc.Mapping[str, Any] | None

shape

The array extents, () for a scalar, None for an extent not known yet, and None overall for records, tuples, tables and non-values.

Type:

tuple[int | None, …] | None

size

The number of scalar elements, or None when an extent is not known yet or the binding is not a value.

Type:

int | None

span

Byte offsets (start, end) of the right-hand side in Module.source, or None.

Type:

tuple[int, int] | None

source

The right-hand side as written, or None for a value bound by Module.set(). A draw shows its whole statement.

Type:

str | None

location

Where the right-hand side starts, or None.

Type:

flatppl._api.Location | None

dependencies

The public bindings that this one references directly, in source order. References through private bindings count.

Type:

tuple[str, …]

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. None for 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:

str

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)'
class flatppl.Location(source, line, column)

A position in FlatPPL source text.

source

The label or path of the source, as in Module.source_name.

Type:

str

line

The line, counting from 1.

Type:

int

column

The column in characters, counting from 1.

Type:

int

Graph

class flatppl.Graph(nodes, edges, bindings)

The public bindings of a module as a directed acyclic graph.

An edge (a, b) means that b references a directly, or through private bindings. Get a graph from Module.graph().

nodes

The binding names in source order.

Type:

tuple[str, …]

edges

Pairs (dependency, dependent) in source order of the dependent.

Type:

tuple[tuple[str, str], …]

bindings

The bindings by name.

Type:

collections.abc.Mapping[str, flatppl._api.Binding]

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_dot()

Write the graph in Graphviz DOT syntax.

Return type:

str

to_networkx()

Return a networkx.DiGraph with each binding’s metadata on its node.

Raises:

ImportError – networkx is not installed.

Return type:

Any

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 None for 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.

name

The binding name.

Type:

str

domain

The inferred value set, as in Binding.domain.

Type:

collections.abc.Mapping[str, Any] | None

shape

The array extents, as in Binding.shape.

Type:

tuple[int | None, …] | None

size

The number of scalar elements, as in Binding.size.

Type:

int | None

binding

The binding itself.

Type:

flatppl._api.Binding

init

The suggested initial value.

Type:

float | numpy._typing._array_like.NDArray[numpy.float64] | None

lo

The suggested lower bound. It is a fit range, not the domain.

Type:

float | numpy._typing._array_like.NDArray[numpy.float64] | None

hi

The suggested upper bound.

Type:

float | numpy._typing._array_like.NDArray[numpy.float64] | None

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", or None for an unconstrained parameter.

Type:

Literal[‘normal’, ‘poisson’] | None

width

The auxiliary constraint’s width.

Type:

float | numpy._typing._array_like.NDArray[numpy.float64] | None

centre

The auxiliary constraint’s nominal centre, the value its auxiliary measurement observes.

Type:

float | numpy._typing._array_like.NDArray[numpy.float64] | None

original_name

The parameter’s name in the imported format, which differs from name when it is not a FlatPPL identifier.

Type:

str | None

role

"poi" for the parameter of interest, otherwise None.

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, where fixed pins a parameter.

value

The marked value.

Type:

object

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.

name

The name of the referenced binding.

Type:

str

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 pyhf package is not needed. The result’s flatppl.Module.source holds the generated FlatPPL, and flatppl.Module.pyhf reads its fit settings and layout. Register it and write a query to compile it, or use flatppl.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. Use pathlib.Path for 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 an external input, so one module serves data, toys and Asimov data through flatppl.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’s auxdata_order. The nominal centres are the view’s auxdata.

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 – observations or auxiliary is not "bound" or "external".

  • OSError – The file cannot be read.

  • UnicodeDecodeError – The bytes are not UTF-8.

Return type:

Module

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 the pyhf package. Names in par_order, auxdata_order and poi are pyhf names. par_map gives each one’s binding and its place in the flat parameter vector.

module

The converted module.

Type:

flatppl._api.Module

measurement

The selected measurement’s name, or None for a model-only document.

Type:

str | None

poi

The parameter of interest’s pyhf name, or None.

Type:

str | None

par_order

The pyhf parameter names in pyhf’s order, as model.config.par_order.

Type:

tuple[str, …]

par_map

Each pyhf parameter’s binding and slice of the flat vector.

Type:

collections.abc.Mapping[str, flatppl.pyhf.ParameterSlice]

auxdata_order

The constrained parameters in pyhf’s order, as model.config.auxdata_order.

Type:

tuple[str, …]

auxdata

The nominal auxiliary data, flat, in auxdata_order, as model.config.auxdata.

Type:

numpy._typing._array_like.NDArray[numpy.float64]

channels

The channels in pyhf’s order, which sorts them by name.

Type:

tuple[flatppl.pyhf.Channel, …]

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 npars: int

The length of the flat parameter vector, as model.config.npars.

property poi_index: int | None

The parameter of interest’s flat index, or None.

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.

Return type:

list[float]

suggested_bounds()

Return the suggested bounds, flat, as pyhf’s suggested_bounds.

Return type:

list[tuple[float, float]]

suggested_fixed()

Return the fixed flags, flat, as pyhf’s suggested_fixed.

Return type:

list[bool]

logpdf(dtype='float32')

Compile the full log-likelihood over pyhf’s flat vectors.

The function takes pars, pyhf’s flat parameter vector, and data when the import left inputs external. data is laid out as in pyhf: the main counts of every channel in channels order when observations are external, then the auxiliary data in auxdata_order when the centres are external. With bound observations and centres it takes pars alone. It returns a scalar where pyhf returns a one-element array, and it supports jax.jit, jax.grad and jax.vmap.

Parameters:

dtype (jax.typing.DTypeLike) – "float32" or "float64", as in flatppl.Module.compile().

Returns:

logpdf(pars) or logpdf(pars, data). It raises ValueError when data is missing, not expected, or of the wrong length.

Raises:

CompilationError – The query does not compile.

Return type:

Callable[[…], Any]

expected_data(dtype='float32', *, include_auxdata=False)

Compile the expected data over pyhf’s flat parameter vector.

The function takes pars and returns every channel’s expected counts in channels order, as pyhf’s model.expected_data. With include_auxdata the expected auxiliary data follow in auxdata_order: the parameter itself for a Gaussian constraint, and the parameter times its rate factor for a Poisson one.

Parameters:
Returns:

expected_data(pars).

Raises:

CompilationError – The query does not compile.

Return type:

Callable[[…], Any]

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:

str

slice

The parameter’s components in the flat vector.

Type:

slice

type

The pyhf modifier type, such as "normsys". A name that normsys and histosys share is one "histosys" parameter.

Type:

str

class flatppl.pyhf.Channel

One channel of a pyhf model.

name

The pyhf channel name.

Type:

str

bins

The number of bins.

Type:

int

observed

The binding that holds the observed counts.

Type:

str

expected

The binding that computes the expected counts.

Type:

str

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.formula retains 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.

  • link (str | None) – Override the family’s default link.

  • 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 center and contrasts.

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:

Module

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:

flatppl._api.Module

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.

Type:

tuple[int, …]

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. Call from_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:

Module

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 under jax.jit, jax.grad, jax.vmap and sharding; see JAX and differentiation. Queries with runtime checks other than parameter value sets require checkify.checkify around the staged computation before jax.jit, as does checks="raise".

stablehlo

The emitted StableHLO text of the unbatched query.

Type:

str

schema

A read-only description of the interface with the keys entry_point, inputs (entries with name and value), output, multiple_outputs and output_names. Each value schema has a kind of tensor (with index, dtype, shape and value_type), record or table (with fields, and rows for a table), or tuple (with items).

Type:

collections.abc.Mapping[str, Any]

__call__(*args, **kwargs)

Evaluate the query.

Parameters:
  • *args (Any) – Inputs in declared order.

  • **kwargs (Any) – Inputs by name, after the positional ones.

Returns:

An array, or a dict or tuple of arrays, as the query’s outputs declare. A query built with gradient=True returns (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:

Any

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:

Mapping[str, int]

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, a jax.vmap template 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:

dict[str, Any]

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.

Type:

flatppl._jax.CompiledFunction

unconstrained

The query with transformed inputs. In log-density mode this includes the forward log-Jacobian exactly once.

Type:

flatppl._jax.CompiledFunction

constrain

Map free coordinates to model parameters.

Type:

flatppl._jax.CompiledFunction

unconstrain

Map interior model parameters to free coordinates. Boundary values can give infinite coordinates. Inputs are not clipped or repaired.

Type:

flatppl._jax.CompiledFunction

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, and fn includes the log-Jacobian of constrain unless jacobian=False.

fn

The log density of a position. It supports jax.jit, jax.grad and jax.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 for posreals and 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]

names

The parameter names, the fields of a record position, in order.

Type:

tuple[str, …]

shapes

Each parameter’s shape in model coordinates.

Type:

collections.abc.Mapping[str, tuple[int, …]]

dtype

"float32" or "float64".

Type:

str

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]]

unconstrained

Whether fn takes unconstrained coordinates.

Type:

bool

jacobian

Whether fn includes the log-Jacobian.

Type:

bool

flat

The same density over one flat vector.

Type:

flatppl.inference.FlatLogDensity

transformed

The compiled functions behind these fields.

Type:

flatppl._transforms.TransformedFunction

__call__(position)

Evaluate fn at a position.

Return type:

Array

class flatppl.inference.FlatLogDensity

A LogDensity over one flat vector.

The vector holds the leaves of LogDensity.init in 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:

collections.abc.Callable[[jax.Array], jax.Array]

grad

The gradient of fn.

Type:

collections.abc.Callable[[jax.Array], jax.Array]

potential

The negated log density, for minimisers.

Type:

collections.abc.Callable[[jax.Array], jax.Array]

init

The starting vector.

Type:

jax.Array

unravel

Map a vector back to the position pytree.

Type:

collections.abc.Callable[[jax.Array], Any]

names

One name per vector element, such as "beta[2]". Indices count from one, as in FlatPPL.

Type:

tuple[str, …]

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 a load_module alias 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 Authorization header, 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')
describe()

Return the box’s describe reply, fetched once and cached.

Returns:

One entry per member with its kind, queries, derivative support, normalized flag and value sets.

Raises:

BoxError – The server refused the request.

Return type:

Mapping[str, Any]

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, and max_intervals in 2..2**31-1.

rtol

The relative tolerance.

Type:

float

atol

The absolute tolerance.

Type:

float

max_intervals

The size of the interval buffer.

Type:

int

Diagnostics

exception flatppl.CompilationError(diagnostic)

A compiler diagnostic raised while loading, parsing, inferring or compiling.

str(error) starts with source:line:column: stage: message and 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, or None.

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.