Export Format#
prophys defines a single, neutral, versioned interchange format for a
compiled model — the ModelPackage. It carries no
dependency on any downstream consumer; a consumer (Qalibri or any other
system) implements its own import against this documented shape.
compiled = model.compile()
pkg = compiled.export() # ModelPackage
pkg.save("model.json")
loaded = prp.export.ModelPackage.load("model.json")
Structure#
ModelPackage is a plain dataclass, serializable to JSON:
ModelPackage
format_version: str # "1.2"
model_name: str
params: dict[str, Any] # calibrated parameters, constrained space
correlation: dict | None # reserved for joint/copula metadata
attributes: list[AttributeExport]
manifest: RunManifest | None # 1.1: provenance, see below
surrogates: list | None # 1.2: learned surrogates, see below
diagnostics: dict | None # 1.1: attached diagnostic reports
AttributeExport
name: str
unit: str
domain: str # free-text description
representation: "quantized" | "histogram" | "sampler"
support: (float, float) # observed [min, max] over the sample
mean: float
unit_description: str | None # 1.1: unit expanded to dimension + SI scale
std_error: float | None # 1.1: Monte-Carlo error of `mean`
n_samples: int | None # 1.1: draws the representation was built from
# representation == "quantized":
grid: list[float] # bin-center support points
probs: list[float] # normalized probabilities, same length as grid
# representation == "histogram":
edges: list[float] # bin edges, length len(probs) + 1
probs: list[float]
# representation == "sampler":
samples: list[float] # raw Monte-Carlo draws, JAX-free
Choosing a representation#
"quantized"— a probability mass function on \(2^n\) support points. The natural format for consumers that need a discretized distribution over a fixed grid (e.g. state-preparation for quantum amplitude estimation)."histogram"— equal-width bins with edges and probabilities; a gridding-free summary when the consumer just needs a coarse density."sampler"— raw NumPy floats, no JAX dependency at all; the simplest possible handoff for a consumer that wants to resample or refit.
pkg = compiled.export(representation="sampler", n_samples=8192)
Provenance: the run manifest#
Format 1.1 attaches a RunManifest. A
ModelPackage says what the answer was; the manifest says where it came
from:
pkg = prp.export.export_model(
compiled,
params=result.raw_params,
observations={"y": data},
diagnostics=prp.report_card(compiled, "y", data, result=result),
notes="design case B, revision 3",
)
print(pkg.manifest)
RunManifest:
prophys 0.4.0 on Python 3.12.14 (Darwin-arm64)
model ProbabilityModel(y)
structure 50bab27094b6a6ea...
seed 7, mode eval, tau 1, n_samples 2000
licensed: False
created 2026-08-26T06:23:15Z
observations: {'y': {'n': 200, 'informative': 200, 'kinds': {'exact': 200}}}
notes: design case B, revision 3
The model is identified by a structure hash: a digest over its attributes, distribution families, parameter declarations and uncertain inputs. The hash covers structure, not fitted values — two runs of a fit on the same model produce the same hash, or the hash would identify the run rather than the model. Parameters are recorded separately, in both constrained form (what a reader interprets) and unconstrained form (what the engine evaluates from, and so what reproduces the run exactly).
Verifying and reproducing#
loaded = prp.export.ModelPackage.load("model.json")
loaded.verify(model.compile()) # structure and parameters
compiled = prp.export.reproduce(loaded.manifest, model)
verify() raises
ReproducibilityError naming what differs — an edited
model, a drifted parameter, a differing parameter set.
reproduce() recompiles the model with the manifest’s
mode, smoothing temperature, sample count and seed, after checking the
structure hash.
This reproduces the run configuration; it does not rebuild the model graph
from the manifest. The graph is defined by the Python that built it, and the
structure hash is what certifies that this Python still describes the same
model. When two hashes disagree,
structure_description() shows which part changed.
Round-tripping#
ModelPackage.save/.load round-trip through JSON losslessly for all
three representations; the symbolic graph itself is not serialized (the
package intentionally only carries the calibrated numeric artifacts a
downstream consumer needs, not the engine internals used to produce them).
A format 1.0 file loads unchanged — the 1.1 fields are optional and default
to absent, and manifest is None. A file whose format_version is
outside SUPPORTED_VERSIONS is refused with its
version named rather than read with fields silently missing; unknown
fields within a supported version are dropped, so a file from a later
prophys still loads with what this one understands.
- class prophys.export.ModelPackage(format_version, model_name, params, attributes, correlation=None, manifest=None, diagnostics=None, surrogates=None)[source]#
Versioned export of a compiled model’s distributions as JSON, with provenance.
Built by
export_model()(orCompiledModel.export()), written withsave()and read back withload(). It carries each attribute’s marginal distribution, the parameter values, aRunManifestrecording what produced it, optional diagnostic reports, and learned surrogates in a form the standalone runtime library evaluates without Python.Example
>>> package = export_model(compiled, params=fit.raw_params, representation="histogram") >>> package.save("model.json") >>> ModelPackage.load("model.json").attribute("energy").mean
- Parameters:
- attributes: list[AttributeExport]#
One exported distribution per attribute.
- correlation: dict[str, Any] | None = None#
Reserved for a dependence summary between attributes, not filled by
export_model().
- manifest: RunManifest | None = None#
versions, structure hash, seed, licensing. None only for a package loaded from a 1.0 file.
- Type:
Provenance for this export
- diagnostics: dict[str, Any] | None = None#
Diagnostic reports attached to the export, keyed by name, typically the output of
prophys.engine.scoring.report_card().
- surrogates: list | None = None#
Learned surrogates of the model as prophys.export.surrogate exports.
- verify(compiled, *, check_params=True)[source]#
Check that compiled is the model this package came from.
Raises
ReproducibilityErrorwhen the structure hash or the parameters differ (seeprophys.export.manifest.verify()), or when the package has no manifest because it was written in format 1.0.- Parameters:
check_params (bool)
- Return type:
None
- attribute(name)[source]#
Return the exported distribution of the attribute called name.
- save(path)[source]#
Write the package to a JSON file at path.
- Parameters:
path (str)
- Return type:
None
- classmethod load(path)[source]#
Read a package from a JSON file written by
save().Files of format 1.0, 1.1 and 1.2 load, and fields this version does not know are ignored.
- Raises:
ValueError – If the file’s format version is not supported.
- Parameters:
path (str)
- Return type:
- class prophys.export.AttributeExport(name, unit, domain, representation, support, grid=None, probs=None, edges=None, samples=None, mean=None, unit_description=None, std_error=None, n_samples=None)[source]#
The exported marginal distribution of one model attribute.
Which of grid, edges and samples is set depends on representation. probs is set for
"quantized"and"histogram".- Parameters:
- probs: list[float] | None = None#
probability of each point or bin, summing to one.
- Type:
"quantized"and"histogram"
- unit_description: str | None = None#
The attribute’s unit expanded into its dimension and SI scale (see prophys.units.describe), so a consumer can check compatibility without reimplementing this package’s unit parser.
- prophys.export.export_model(compiled, attribute_names=None, representation='quantized', n_qubits=8, n_samples=4096, seed=0, params=None, observations=None, diagnostics=None, notes='')[source]#
Export a compiled model’s attribute distributions as a
ModelPackage.Each attribute is sampled n_samples times and its marginal distribution serialized according to representation:
"quantized": PMF on the2**n_qubitscentres of equally spaced bins over the sample range (for example for consumers in the style of quantum amplitude estimation)."histogram": histogram with2**n_qubitsequally wide bins."sampler": the raw Monte Carlo samples as plain floats, for consumers that just want data to resample from.
Every attribute also records its mean with the Monte Carlo standard error of the same draw. Learned surrogates of the model are exported alongside, except those with Physics layers, which are skipped.
- Parameters:
compiled – The compiled model.
attribute_names (list[str] | None) – Attributes to export. Defaults to all.
representation (str) –
"quantized","histogram"or"sampler".n_qubits (int) – Resolution:
2**n_qubitspoints or bins.n_samples (int) – Monte Carlo draws per attribute.
seed (int) – PRNG seed of the draws.
params (Any) – Unconstrained parameter values to export at. Pass a fit’s raw_params so the distributions and the manifest record the fitted model rather than its declared initial values.
observations (Any) – Observations of a fit, recorded in the manifest as counts.
diagnostics (Any) – Name to diagnostic report (e.g. the output of
report_card()), serialized in the manifest and the package.notes (str) – Free text recorded in the manifest.
- Returns:
The
ModelPackage.- Raises:
ValueError – If representation is unknown.
- Return type:
- class prophys.export.RunManifest(manifest_version, prophys_version, structure_hash, model_name, params, raw_params, seed, mode, tau, n_samples, created_utc, python_version, platform, licensed, licensee='', observations=<factory>, diagnostics=<factory>, notes='')[source]#
Provenance record of an exported result: versions, model structure, parameters and settings.
Built by
build_manifest()and embedded in everyModelPackage. Check a model against it withverify(), and recompile a model with its settings withreproduce().- Parameters:
- manifest_version: str#
Version of the manifest’s own field set (
MANIFEST_VERSION).
- structure_hash: str#
Digest of the model’s structure (see
structure_hash()).
- raw_params: dict[str, Any]#
The same parameters in unconstrained space, the values needed to reproduce the run, since that is what the engine evaluates from.
- licensed: bool#
Whether a valid PROPHYS_LICENSE was in effect. A run on the free tier is limited in model size, so this records which regime produced the result.
- to_dict()[source]#
Return the manifest as a dict ready for JSON, which
manifest_from_dict()reverses.
- matches(other)[source]#
Whether two manifests describe the same model structure.
Compares the structure hash only: two manifests can legitimately differ in seed, sample count, timestamp and fitted parameters while describing the same model.
- Parameters:
other (RunManifest)
- Return type:
- prophys.export.build_manifest(compiled, *, params=None, observations=None, diagnostics=None, notes='')[source]#
Build the provenance record (
RunManifest) of a run of a compiled model.export_model()calls this for every package. Call it directly to record a run that is not exported.params is the unconstrained parameter dict the run used, such as a fit’s raw_params. Without it the model’s declared initial values are recorded, which is correct for an unfitted model and would be misleading for a fitted one, so pass it whenever a fit happened.
diagnostics accepts any mapping of name to
Report(or plain dict), which is serialized alongside. This is the natural place for the output ofprophys.engine.scoring.report_card().- Parameters:
compiled – The compiled model.
params (Mapping[str, Any] | None) – Unconstrained parameter values of the run.
observations (Mapping[str, Any] | None) – Attribute name to observations of a fit, recorded as counts by kind.
diagnostics (Mapping[str, Any] | None) – Name to report (or plain dict).
notes (str) – Free text.
- Returns:
The
RunManifest.- Return type:
- prophys.export.structure_hash(model)[source]#
Compute a stable SHA-256 digest of a probability model’s structure.
Covers, per attribute, its name, unit, domain, the class name of its distribution and of every nested distribution, and the names and families of its upstream RandomVariable leaves. Also covers every Param of the model (name, shape, bounds and transform) and the class of the interaction coupling, if the model has one. The digest is taken over
structure_description().Deliberately excludes: parameter values (they are recorded separately and are expected to change between a prior and a fitted run), sample counts, seeds, and anything else about how the model was evaluated. Two runs of a fit on the same model must produce the same structure hash, or the hash would identify the run rather than the model.
- Parameters:
model – A ProbabilityModel.
- Returns:
The digest as 64 hexadecimal characters.
- Return type:
- prophys.export.structure_description(model)[source]#
Describe the model structure that
structure_hash()digests, as a readable dict.Exposed rather than kept private: when two hashes disagree, this is what tells the reader which part of the model changed.
- prophys.export.verify(manifest, compiled, *, check_params=True)[source]#
Check that a compiled model is the one a manifest was produced from.
Compares the structure hash and, unless check_params is false, every recorded unconstrained parameter value against the compiled model’s default parameter values (its Param initial values). A manifest of a fit therefore passes the parameter check only when the model declares the fitted values. Pass
check_params=Falseto check the structure alone.Parameters are compared to single precision tolerance (
rtol=1e-5,atol=1e-6): the values were serialized from float32 arrays, and requiring exact equality after a decimal round trip would fail on every manifest for no useful reason.- Parameters:
manifest (RunManifest) – The recorded manifest.
compiled – The compiled model to check.
check_params (bool) – Also compare parameter values.
- Raises:
ReproducibilityError – Naming what differs (structure, parameter set, or a parameter value).
- Return type:
None
- prophys.export.reproduce(manifest, model)[source]#
Recompile a model with the settings a manifest records, after checking its structure.
Returns a CompiledModel with the manifest’s mode, tau, sample count and seed, verified against its structure hash. The recorded parameters are not baked in, because a CompiledModel takes its parameters per call rather than holding them: pass
manifest.raw_paramsas params to any evaluation to reproduce the recorded run.This reproduces the run configuration. It does not rebuild the model graph from the manifest. The graph is defined by the Python that built it, and the structure hash is what certifies that this Python still describes the same model.
- Parameters:
manifest (RunManifest) – The recorded manifest.
model – The ProbabilityModel built by the same code.
- Returns:
The compiled model.
- Raises:
ReproducibilityError – If the model’s structure hash differs.
- Return type:
Example
>>> package = ModelPackage.load("model.json") >>> compiled = reproduce(package.manifest, build_model()) >>> compiled.expectation("energy", params=package.manifest.raw_params)
- exception prophys.export.ReproducibilityError[source]#
Raised when a model does not match the run manifest it is checked against.
A subclass of ValueError. Raised by
verify(),reproduce()andModelPackage.verify.
- prophys.export.manifest_from_dict(data)[source]#
Rebuild a
RunManifestfrom its dict form (the inverse ofRunManifest.to_dict).Tolerates fields added by a newer prophys than the one reading it.
Unknown fields are dropped rather than raising: a manifest is a provenance record, and a reader that refuses to open one written by a later version is worse than one that reports the fields it understands.
- Parameters:
- Return type:
- prophys.export.FORMAT_VERSION = '1.2'#
str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.
- prophys.export.MANIFEST_VERSION = '1.0'#
str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.
- prophys.export.SUPPORTED_VERSIONS = frozenset({'1.0', '1.1', '1.2'})#
Build an immutable unordered collection of unique elements.
Learned surrogates (format 1.2)#
Format 1.2 adds surrogates, one
SurrogateExport per learned surrogate of
the model. Each carries
the native network program or tree spec and the weights of every member, exported at the parameters the package was exported at (the fitted ones when a fit’s
raw_paramsis passed),input and output names with units, the head kind and quantile levels,
the support region and the head posterior,
the training card (
PretrainResult) with its diagnostics,probe inputs, their outputs and an FNV 1a checksum of those outputs,
a base64 blob for the runtime library (Runtime Library).
SurrogateExport.verify() recomputes the checksum. Packages of format 1.0
and 1.1 still load. Surrogates with Physics layers keep their physics in
the model graph and are not exported to the runtime.