iqm.error_reduction_tools.twirling.twirling_api.CircuitTwirler#

class iqm.error_reduction_tools.twirling.twirling_api.CircuitTwirler(client=None, config=None, compilation_options=None)#

Bases: object

Manages the twirl → submit → retrieve lifecycle for readout-twirled circuits.

Parameters:
  • client (Pulla | None) – Client instance for connecting to an IQM quantum computer. Used for topology look-up (only required for the "LOCAL" readout-twirling strategy), compilation, and job submission. May be None when the twirler is used purely as a circuit transformer — i.e. when calling only twirl() (with a non-LOCAL strategy) and get_twirled_circuits() to drive submission externally. Required by submit() and by the "LOCAL" strategy.

  • config (TwirlingConfiguration | None) – Twirling configuration. Defaults are sensible for most cases.

  • compilation_options (dict[str, Any] | None) –

    Extra key-value pairs passed to the Pulla compiler context when submit() compiles circuits. Use this to activate compiler features such as dynamical decoupling. For example:

    compilation_options={"DDStrategy": my_dd_strategy}
    

Example — full lifecycle (requires client):

twirler = CircuitTwirler(client, config=TwirlingConfiguration(readout_twirl_strategy="LOCAL", seed=42))
twirler.twirl(circuits).submit(shots=20_000)
mitigated_counts = twirler.retrieve_counts()

Example — circuit-twirling-only, no client needed:

config = TwirlingConfiguration(readout_twirl_strategy="NONE", circuit_twirling=True)
twirler = CircuitTwirler(config=config)
randomized = twirler.twirl(circuits).get_twirled_circuits()

Methods

_convert_circuits(circuits)

Convert heterogeneous input circuits to TwirledCircuit.

_extract_qubit_to_bit_mapping(circuit)

Derive the qubit → classical-bit mapping from measurement operations.

from_dict(data, client)

Reconstruct a CircuitTwirler from a dictionary.

get_job()

Return job from submit().

get_qubit_to_bit_mapping()

Return qubit-to-classical-bit mappings extracted during twirl().

get_rot_strings()

Return rotation strings produced by twirl().

get_twirled_circuits([return_qiskit])

Return the randomized circuits produced by twirl().

get_twirled_circuits_flat([return_qiskit])

Return all randomized circuits as a single flat list.

load_twirling_info(path, client)

Load twirling state from a JSON file.

retrieve_counts()

Wait for job completion, untwirl, and sum counts per input circuit.

save_twirling_info(path)

Save twirling state to a JSON file.

submit([shots, client])

Compile and submit all randomized circuits to the quantum computer for execution.

to_dict()

Serialize twirling state to a plain dictionary.

twirl(circuits)

Convert input circuits to pulse form, generate rotation strings, and randomize.

twirl(circuits)#

Convert input circuits to pulse form, generate rotation strings, and randomize.

Parameters:

circuits (list[TwirledCircuit | QuantumCircuit | QuantumCircuit | Circuit]) – Input circuits to twirl.

Returns:

self, to allow method chaining.

Raises:
Return type:

CircuitTwirler

submit(shots=20000, client=None)#

Compile and submit all randomized circuits to the quantum computer for execution.

shots refers to the number of shots per input (target) circuit. It is distributed evenly across that circuit’s twirled instances, so the untwirled, aggregated counts for each input circuit are based on (approximately) shots shots regardless of how many input circuits are submitted.

Parameters:
  • shots (int) – Number of shots per input circuit, split across its twirled instances.

  • client (Pulla | None) –

    Client for submitting the task to the quantum computer. If provided, it overrides the client supplied at construction time and is also stored on the instance for any subsequent calls (e.g. retrieve_counts()). This makes it possible to construct a client-less CircuitTwirler purely as a circuit transformer and only bind a client at submission time.

    When the strategy used at twirl() time was "LOCAL", the rotation strings are tied to the exact quantum computer that was used during twirl(). Using a different quantum computer here raises ValueError; re-run twirl() with the new QC first.

Returns:

self, to allow method chaining.

Raises:
  • RuntimeError – If twirl() has not been called yet, or if no client is available (neither at construction nor here).

  • ValueError – If a different client instance is passed here while the "LOCAL" strategy was used at twirl() time.

Return type:

CircuitTwirler

retrieve_counts()#

Wait for job completion, untwirl, and sum counts per input circuit.

Uses untwirl_and_sum_counts() (the same function used in the tutorial notebooks) to untwirl and aggregate the raw counts.

Returns:

One count dictionary per original input circuit.

Raises:

RuntimeError – If submit() has not been called yet.

Return type:

list[dict[str, float]]

get_twirled_circuits(return_qiskit=False)#

Return the randomized circuits produced by twirl().

Parameters:

return_qiskit (bool) – When True, convert each circuit to a Qiskit QuantumCircuit before returning. Defaults to False (returns Circuit).

Returns:

Nested list with one inner list of randomized variants per input circuit, in the same order as the circuits passed to twirl().

Raises:

RuntimeError – If twirl() has not been called yet.

Return type:

list[list[Circuit]] | list[list[QuantumCircuit]]

get_twirled_circuits_flat(return_qiskit=False)#

Return all randomized circuits as a single flat list.

Parameters:

return_qiskit (bool) – When True, convert each circuit to a Qiskit QuantumCircuit before returning. Defaults to False (returns Circuit).

Returns:

Flat list of all randomized circuits, matching the order used internally by submit().

Raises:

RuntimeError – If twirl() has not been called yet.

Return type:

list[Circuit] | list[QuantumCircuit]

get_rot_strings()#

Return rotation strings produced by twirl().

Returns:

Nested list — one inner list per input circuit, each containing one rot string (e.g. "IXXI") per randomized variant.

Raises:

RuntimeError – If twirl() has not been called yet.

Return type:

list[list[str]]

get_qubit_to_bit_mapping()#

Return qubit-to-classical-bit mappings extracted during twirl().

Returns:

{qubit_name: classical_bit_index}.

Return type:

One mapping per input circuit

Raises:

RuntimeError – If twirl() has not been called yet.

get_job()#

Return job from submit().

Raises:

RuntimeError – If submit() has not been called yet.

Return type:

object

to_dict()#

Serialize twirling state to a plain dictionary.

Includes rotation strings, qubit-to-bit mappings, and the configuration — enough to reconstruct the twirler for post-processing without re-running on hardware.

Return type:

dict[str, Any]

classmethod from_dict(data, client)#

Reconstruct a CircuitTwirler from a dictionary.

The restored instance has rotation strings and mappings populated but no circuits or job — it can be used for post-processing only.

Parameters:
  • data (dict[str, Any]) – Dictionary as returned by to_dict().

  • client (Pulla) – Client for connecting to the quantum computer.

Returns:

A CircuitTwirler with restored state.

Return type:

CircuitTwirler

save_twirling_info(path)#

Save twirling state to a JSON file.

Parameters:

path (str) – Destination file path.

Return type:

None

classmethod load_twirling_info(path, client)#

Load twirling state from a JSON file.

Parameters:
  • path (str) – Path to a JSON file previously written by save_twirling_info().

  • client (Pulla) – Client for connecting to the quantum computer.

Returns:

A CircuitTwirler with restored state.

Return type:

CircuitTwirler