Export Format

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() (or CompiledModel.export()), written with save() and read back with load(). It carries each attribute’s marginal distribution, the parameter values, a RunManifest recording 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:
format_version: str#

Format version of the package, e.g. "1.2".

model_name: str#

Readable name of the source model.

params: dict[str, Any]#

Parameter values the package was exported at, in constrained space.

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.

surrogate(name)[source]#

Return the exported surrogate called name.

Raises:

KeyError – If the package has no such surrogate.

Parameters:

name (str)

to_dict()[source]#

Return the package as a dict ready for JSON (the content of the saved file).

Return type:

dict[str, Any]

verify(compiled, *, check_params=True)[source]#

Check that compiled is the model this package came from.

Raises ReproducibilityError when the structure hash or the parameters differ (see prophys.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.

Raises:

KeyError – If the package has no such attribute.

Parameters:

name (str)

Return type:

AttributeExport

to_json(indent=2)[source]#

Serialize the package to a JSON string.

Parameters:

indent (int)

Return type:

str

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:

ModelPackage

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:
name: str#

Attribute name.

unit: str#

Unit string of the attribute (e.g. "kW").

domain: str#

Free text domain description of the attribute, as declared in the model.

representation: str#

"quantized", "histogram" or "sampler".

support: tuple[float, float]#

(min, max) of the Monte Carlo draws the export was built from.

grid: list[float] | None = None#

the support points (bin centres).

Type:

"quantized"

probs: list[float] | None = None#

probability of each point or bin, summing to one.

Type:

"quantized" and "histogram"

edges: list[float] | None = None#

the n + 1 bin edges, equally spaced.

Type:

"histogram"

samples: list[float] | None = None#

the raw Monte Carlo draws as plain floats.

Type:

"sampler"

mean: float | None = None#

Monte Carlo mean of the draws.

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.

std_error: float | None = None#

Monte Carlo standard error of mean, from the same draw the distribution was built from. None when the export did not compute it.

n_samples: int | None = None#

Draws the exported representation was built from.

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 the 2**n_qubits centres of equally spaced bins over the sample range (for example for consumers in the style of quantum amplitude estimation).

  • "histogram": histogram with 2**n_qubits equally 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_qubits points 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:

ModelPackage

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 every ModelPackage. Check a model against it with verify(), and recompile a model with its settings with reproduce().

Parameters:
manifest_version: str#

Version of the manifest’s own field set (MANIFEST_VERSION).

prophys_version: str#

prophys version that produced the run.

structure_hash: str#

Digest of the model’s structure (see structure_hash()).

model_name: str#

Readable name of the model.

params: dict[str, Any]#

Parameters in constrained space, the values a reader interprets.

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.

seed: int#

PRNG seed the model was compiled with.

mode: str#

"eval" (exact geometry) or "opt" (smoothed).

tau: float#

Smoothing temperature, meaningful only in "opt" mode.

n_samples: int#

Monte Carlo marginalization sample count the model was compiled with.

created_utc: str#

ISO 8601 timestamp of the export, in UTC.

python_version: str#

Python version of the run.

platform: str#

Operating system and machine, e.g. "Linux-x86_64".

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.

licensee: str = ''#

Licensee name of the license in effect, empty on the free tier.

observations: dict[str, Any]#

Observation counts by kind per attribute, when the run was a fit.

diagnostics: dict[str, Any]#

Any diagnostic reports attached to the run, keyed by name.

notes: str = ''#

Free text supplied at export.

to_dict()[source]#

Return the manifest as a dict ready for JSON, which manifest_from_dict() reverses.

Return type:

dict[str, Any]

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:

bool

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 of prophys.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:

RunManifest

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:

str

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.

Return type:

dict[str, Any]

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=False to 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_params as 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:

Any

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() and ModelPackage.verify.

prophys.export.manifest_from_dict(data)[source]#

Rebuild a RunManifest from its dict form (the inverse of RunManifest.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:

data (Mapping[str, Any])

Return type:

RunManifest

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_params is 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.