Skip to main content
Once you have built and certified an ExactProgram, you can serialize it to JSON for storage, transmission, or caching. b01t includes a round-trip serialization format called exact-oracle-v1 that captures the full program structure — registers, operations, ancilla discipline, and certification level — and re-validates all structural invariants on load.

Serializing an ExactProgram

Import the serialization functions from b01t:
from b01t import (
    exact_program_to_json,
    exact_program_from_json,
    exact_program_to_dict,
    exact_program_from_dict,
)

To JSON

from b01t import coherent, QReg, cx, z, Certification
from b01t import ancilla, compute, phase, uncompute
from b01t import exact_program_to_json

@coherent
def oracle(sys: QReg):
    with ancilla(1) as anc:
        compute(lambda: cx(sys[0], anc[0]))
        phase(lambda: z(anc[0]))
        uncompute()

prog = oracle.build_exact(("sys", 1))
json_str = exact_program_to_json(prog)
print(json_str)
exact_program_to_json() returns a deterministic, sorted-key JSON string. The output is always consistent for the same program.

To dict

If you need to embed the program data in a larger JSON object or manipulate it as a Python dictionary:
from b01t import exact_program_to_dict

data = exact_program_to_dict(prog)
print(data["format"])   # "exact-oracle-v1"
print(data["name"])     # "oracle"
print(data["certification"])  # "safe"

The JSON format

The serialized format uses the tag "exact-oracle-v1" in the "format" field. Here is an example of what the JSON looks like for the single-qubit oracle above:
{
  "certification": "safe",
  "format": "exact-oracle-v1",
  "name": "oracle",
  "ops": [
    {
      "ancilla": {
        "kind": "anc",
        "name": "anc0",
        "size": 1
      },
      "compute": [
        {
          "gate": "CX",
          "op": "gate",
          "wires": [
            {"index": 0, "kind": "sys", "reg": "sys"},
            {"index": 0, "kind": "anc", "reg": "anc0"}
          ]
        }
      ],
      "middle": [
        {
          "gate": "Z",
          "op": "gate",
          "wires": [{"index": 0, "kind": "anc", "reg": "anc0"}]
        }
      ],
      "middle_kind": "phase",
      "op": "ancilla",
      "uncompute": [
        {
          "gate": "CX",
          "op": "gate",
          "wires": [
            {"index": 0, "kind": "sys", "reg": "sys"},
            {"index": 0, "kind": "anc", "reg": "anc0"}
          ]
        }
      ]
    }
  ],
  "regs": [
    {"kind": "sys", "name": "sys", "size": 1},
    {"kind": "anc", "name": "anc0", "size": 1}
  ]
}
Each operation is tagged with "op": "gate" for a single gate, "ancilla" for an ancilla block, and "par" for parallel composition. Ancilla blocks include the "middle_kind" field — either "phase" for the CPU pattern or "apply" for the CMA pattern.

Deserializing

From JSON

from b01t import exact_program_from_json

restored = exact_program_from_json(json_str)
print(restored.name)           # "oracle"
print(restored.certification)  # Certification.SAFE

From dict

from b01t import exact_program_from_dict

restored = exact_program_from_dict(data)
Deserialization validates the "format" field. If it is missing or wrong, a DSLValidationError is raised:
DSLValidationError: unsupported exact oracle format: 'my-format' (expected 'exact-oracle-v1')
All structural invariants — wire declarations, ancilla discipline, gate classifications — are re-checked on load. A program that was safe when serialized is safe when restored.

Round-trip example

from b01t import coherent, QReg, cx, z, Certification
from b01t import ancilla, compute, phase, uncompute
from b01t import exact_program_to_json, exact_program_from_json

@coherent
def oracle(sys: QReg):
    with ancilla(1) as anc:
        compute(lambda: cx(sys[0], anc[0]))
        phase(lambda: z(anc[0]))
        uncompute()

# Build
prog = oracle.build_exact(("sys", 1))
assert prog.certification == Certification.SAFE

# Serialize
json_str = exact_program_to_json(prog)

# Deserialize
restored = exact_program_from_json(json_str)

# Verify
assert restored.name == prog.name
assert restored.certification == prog.certification
assert len(restored.ops) == len(prog.ops)

Managing collections with PackageRegistry

PackageRegistry lets you publish, save, and load a collection of programs. Each entry is a PackageMeta that holds a program alongside metadata like tags, version, and documentation.
from b01t import PackageRegistry, PackageMeta, Certification
from b01t import coherent, QReg, cx, z
from b01t import ancilla, compute, phase, uncompute

registry = PackageRegistry()

# Build a program
@coherent
def oracle(sys: QReg):
    with ancilla(1) as anc:
        compute(lambda: cx(sys[0], anc[0]))
        phase(lambda: z(anc[0]))
        uncompute()

prog = oracle.build_exact(("sys", 1))

# Publish it to the registry
registry.publish(PackageMeta(
    name="oracle",
    effect="coherent",
    safe=True,
    tags=["oracle", "phase"],
    docs="Single-qubit phase oracle.",
    inputs=[("sys", 1)],
    exact_program=prog,
))

# Save the entire registry to a file
registry.save("my_programs.json")
Load the registry back later:
registry2 = PackageRegistry()
registry2.load("my_programs.json")

meta = registry2.get("oracle")
print(meta.exact_program.certification)  # Certification.SAFE
The saved file is a JSON array. Each entry that has an exact_program includes it under the "exact_oracle" key in exact-oracle-v1 format, with full structural validation on load.
Use registry.find_by_tag("oracle") to retrieve all programs with a particular tag. This is useful when you have a collection of related circuits and want to filter by purpose.