Skip to main content
A hybrid program is a pipeline that you assemble yourself from small building blocks called layers. Each layer is one processing step — transpile the circuits, pack them onto spare qubits, apply error mitigation, run them on a device. Stacking layers into a program lets you describe exactly how your circuits are prepared, executed, and post-processed, combining classical processing with quantum execution in a single object. You then execute the program with haiqu.flow.
  • Layer — one processing step (transpilation, packing, mitigation, device execution, …).
  • Program — an ordered pipeline of layers, from an InputLayer to a DeviceLayer.
  • Hybrid program — a program that interleaves classical pre/post-processing with quantum execution; “hybrid” because both kinds of work live in the same pipeline.
  • Flow — running a hybrid program against concrete circuits with haiqu.flow(...).

Flow vs. run

haiqu.run executes circuits through one fixed, built-in pipeline controlled by keyword flags (use_mitigation, use_packing, …). haiqu.flow runs a pipeline that you compose layer by layer, so you control which steps run and in what order. Both accept the same circuits, parameters, and observables, and both return a job whose result() follows the same nested-list ordering.

Anatomy of a program

Every program starts with an InputLayer (the entry point for your circuits) and ends with a DeviceLayer (the backend that runs them). Anything in between is optional processing. The smallest valid program just feeds circuits straight to a device:
Add processing steps between the two ends to shape the pipeline:
A program is validated when you build it. The rules are:
  • The first layer must be an InputLayer, and the last must be a DeviceLayer.
  • There is exactly one of each — no InputLayer or DeviceLayer in the middle.
  • At most one grouped error-mitigation layer (EstimatorLayer or DistributionMitigationLayer); the two are mutually exclusive.

The layer catalog

LayerPurposeKey parameters
InputLayerEntry point; every program starts with one.
TranspilationLayerTranspile the circuits for the target backend.optimization_level (0–3)
PackingLayerPack several copies of a circuit into one run to use spare device qubits.pack_size (≥ 2)
EstimatorLayerMeasure observable expectation values with error mitigation.mitigation flags
DistributionMitigationLayerMitigate errors on the raw measured distribution.mitigation flags
DeviceLayerRun the circuits on a backend; every program ends with one.device_id, options
Leave a layer’s parameters unset to take its defaults (for example, TranspilationLayer() uses the backend’s default optimization level, and PackingLayer() picks a pack size automatically).
Handling observables. A program that supplies observables must include a layer that computes them — either the grouped EstimatorLayer (expectation values with error mitigation) or the fine-grained ObservableSplitLayerQWCComputeLayer pair. When you read the raw measurement distribution instead (no observables), reach for DistributionMitigationLayer. A program uses at most one grouped mitigation layer — EstimatorLayer or DistributionMitigationLayer.
For full control you can assemble the pipeline by hand from individual steps instead of the grouped layers: ObservableSplitLayer and QWCComputeLayer compute observables, while NoiseTailoringLayer, DynamicalDecouplingLayer, and AdvancedReadoutMitigationLayer apply individual mitigation techniques. See the hybrid program reference for every layer and its fields.

Next steps

Building and running flows

Compose a program from layers and execute it with haiqu.flow, step by step.
Before running a flow you need to authenticate with haiqu.login and start an experiment — see the Get Started guide.