Skip to main content

Haiqu.flow(program, circuits, shots=1000, parameters=None, observables=None, job_name=None, job_description=None, device_credentials=None, dry_run=False)

Run a flow (hybrid program). This flexible method supports multiple execution scenarios, with different combinations of circuits, parameters, and observables. When multiple values are provided for any of them, the results are returned as nested lists with up to 3 layers, ordered by circuits, then observables, and finally parameters.
  • Parameters:
    • program (HybridProgram) — The hybrid program to execute.
    • circuits (QuantumCircuit | list *[*QuantumCircuit ] | CircuitModel | list *[*CircuitModel ]) — The quantum circuit(s) to pass to the hybrid program. Can be a single circuit or a list of circuits.
    • shots (int) — The number of shots for each circuit execution. Defaults to 1000.
    • parameters (list | None) — The parameters for the circuits. Can be a single set of parameters or nested lists of parameter sets. For multiple circuits, must be a list where each element corresponds to parameters for that circuit. Defaults to None, in which case the circuits must not have any parameters. Each inner list must have length circuit.num_parameters. Values are bound positionally in the order of Qiskit’s QuantumCircuit.parameters. When parameters are created one-by-one, that order is typically alphabetical by name (e.g. theta10 before theta2), independent of gate addition order; ParameterVector circuits use vector index order instead (e.g. theta[0], theta[1]). Inspect list(circuit.parameters) for the exact order.
    • observables (SparsePauliOp | list *[*SparsePauliOp ] | list *[*list *[*SparsePauliOp ] ] | None) — The observable(s) to measure. The order of Pauli terms in a single string follows the Qiskit reversed-order convention (e.g., "IZ" measures qubit 0 in the Z basis). Defaults to None, in which case the circuits must include their own measurements. Accepted shapes:
      • Single circuit: a single SparsePauliOp, the nested form [[op1, op2, ...]], or a bare list [op1, op2, ...].
      • Multiple circuits: a list of length num_circuits, where each element is independently either a single SparsePauliOp (one observable on that circuit) or a list of SparsePauliOp (multiple observables on that circuit). Mixing is allowed — [[op1, op2], op3] for two circuits is valid.
      The fully-nested form is the unambiguous canonical shape and is recommended when the same code path handles both single and multi-circuit submissions.
    • job_name (str | None) — The name for the job. If None (default), a name will be automatically generated.
    • job_description (str | None) — The description for the job.
    • device_credentials (dict | None) — Credentials for device access.
    • dry_run (bool) — Whether to stop just prior to backend execution for QPU cost estimation. Defaults to False. When True, the job result will be empty since execution on the device is skipped. The estimated QPU cost is then available via job.estimated_qpu_cost. Wall-clock time to run hybrid program layers up to (but not including) the device layer is available via job.pre_device_pipeline_time (also on full runs).
  • Returns: The Hybrid job that will execute the hybrid program. : Call job.result() to retrieve the execution results as a nested list ordered by circuits → observables → parameters:
    • Without observables: list of measurement distributions (dict[str, float]), one per circuit, in Qiskit bit-order.
    • With observables, no parameter sweep: 2D list of expectation values, indexed [circuit][observable].
    • With observables and a parameter sweep: 3D list of expectation values, indexed [circuit][observable][parameter].

    Dry runs (dry_run=True): result() is empty. Use job.estimated_qpu_cost for the QPU cost estimate and job.pre_device_pipeline_time for classical hybrid time before the device layer. job.time is 0 because the device phase does not run.
    Full runs (dry_run=False): job.time is the device-phase wall clock (from when device execution starts to job completion). job.pre_device_pipeline_time reports classical hybrid time before the device layer. job.info also exposes auxiliary metadata (uncertainty when observables are supplied, qpu_cost on full runs). Run help(job.result) for the full description of result and info contents.
  • Return type: HybridJobModel

Examples

Single circuit, no parameters, no observables:
Single circuit, multiple parameters, no observables:
Single circuit, no parameters, multiple observables:
Single circuit, multiple parameters, multiple observables:
Multiple circuits, no parameters, no observables:
Multiple circuits, multiple parameters, no observables:
Multiple circuits, no parameters, multiple observables:
Multiple circuits, multiple parameters, multiple observables:

Hybrid program layers

A HybridProgram is an ordered list of layers. Grouped error mitigation is handled by EstimatorLayer (observable expectation values) or DistributionMitigationLayer (raw measurement distributions). For hand-built pipelines, compose explicit processing steps instead. Advanced mitigation uses separate wire types for each mitigation path: Layers that make up a hybrid program. A program is an ordered list of layers describing how your circuits are processed and run. It starts with an InputLayer and ends with a DeviceLayer. Use EstimatorLayer or DistributionMitigationLayer for grouped error mitigation, or compose finer processing steps by hand. For advanced mitigation in manual pipelines, pick the layer for the mitigation path: AdvancedObsMitigationLayer for observable-based mitigation and AdvancedDistMitigationLayer for distribution-based mitigation.

class haiqu.sdk.hybrid.layers.AdvancedDistMitigationLayer(*, type=‘advanced_dist_mitigation’)

Advanced distribution-based error mitigation for hand-built pipelines. Use this in place of the advanced_mitigation flag on grouped mitigation layers when manually enabling distribution-based advanced mitigation.
  • Parameters: type (Literal [ ‘advanced_dist_mitigation’ ])

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.AdvancedObsMitigationLayer(*, type=‘advanced_obs_mitigation’)

Advanced observable-based error mitigation for hand-built pipelines. Use this in place of the advanced_mitigation flag on grouped mitigation layers when manually enabling observable-based advanced mitigation.
  • Parameters: type (Literal [ ‘advanced_obs_mitigation’ ])

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.AdvancedReadoutMitigationLayer(*, type=‘advanced_readout_mitigation’)

Advanced measurement (readout) error mitigation.
  • Parameters: type (Literal [ ‘advanced_readout_mitigation’ ])

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.DeviceLayer(*, type=‘device’, device_id, options=)

Runs the circuits on a backend; every program ends with one. device_id selects the backend; options carries backend-specific settings (e.g. credentials). For real IBM QPUs, pass options={"use_fractional_gates": True} to use fractional gates (continuous-angle rx / rzz, etc.). Outside hybrid programs, set the same flag on get_device() instead.
  • Parameters:
    • type (Literal [ ‘device’ ])
    • device_id (str)
    • options (dict)

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.DistributionMitigationLayer(*, type=‘distribution_mitigation’, mitigation_enabled=True, advanced_mitigation=True, readout_mitigation=True, noise_tailoring=False, dynamical_decoupling=True, readout_mitigation_options=)

Mitigate errors on the raw measured probability distribution. Use this when the job reads measurement outcomes (no observables).
  • Parameters:
    • type (Literal [ ‘distribution_mitigation’ ])
    • mitigation_enabled (bool)
    • advanced_mitigation (bool)
    • readout_mitigation (bool)
    • noise_tailoring (bool)
    • dynamical_decoupling (bool)
    • readout_mitigation_options (dict)

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.DynamicalDecouplingLayer(*, type=‘dynamical_decoupling’)

Suppress idle-qubit errors with dynamical-decoupling sequences.
  • Parameters: type (Literal [ ‘dynamical_decoupling’ ])

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.EstimatorLayer(*, type=‘estimator’, mitigation_enabled=False, advanced_mitigation=True, readout_mitigation=True, noise_tailoring=False, dynamical_decoupling=True, readout_mitigation_options=)

Measure observable expectation values with error mitigation. Use this when the job supplies observables. Error mitigation is opt-in.
  • Parameters:
    • type (Literal [ ‘estimator’ ])
    • mitigation_enabled (bool)
    • advanced_mitigation (bool)
    • readout_mitigation (bool)
    • noise_tailoring (bool)
    • dynamical_decoupling (bool)
    • readout_mitigation_options (dict)

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.InputLayer(*, type=‘input’)

The program’s entry point. Every program starts with one.
  • Parameters: type (Literal [ ‘input’ ])

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.NoiseTailoringLayer(*, type=‘noise_tailoring’)

Tailor device noise with Pauli twirling.
  • Parameters: type (Literal [ ‘noise_tailoring’ ])

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.ObservableSplitLayer(*, type=‘observable_split’)

Split a task with several observables into one task per observable.
  • Parameters: type (Literal [ ‘observable_split’ ])

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.PackingLayer(*, type=‘packing’, pack_size=None)

Pack several copies of a circuit into one run to use spare device qubits. pack_size is the number of copies; leave it unset to pick a value automatically from the circuit and device sizes.
  • Parameters:
    • type (Literal [ ‘packing’ ])
    • pack_size (Annotated *[*int , FieldInfo *(*annotation=NoneType , required=True , metadata= *[*Ge *(*ge=2 ) ] ) ] | None)

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.QWCComputeLayer(*, type=‘qwc_compute’)

Compute observable expectation values from grouped commuting measurements.
  • Parameters: type (Literal [ ‘qwc_compute’ ])

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class haiqu.sdk.hybrid.layers.TranspilationLayer(*, type=‘transpilation’, optimization_level=None)

Transpile the circuits for the target backend. optimization_level (0-3) sets the optimization effort; leave it unset for the default.
  • Parameters:
    • type (Literal [ ‘transpilation’ ])
    • optimization_level (Literal *[*0 , 1 , 2 , 3 ] | None)

model_config : ClassVar[ConfigDict] =

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].