---
title: Qiskit SDK 2.2 release notes
description: Changes made in Qiskit SDK 2.2
source: https://eu-de.quantum.cloud.ibm.com/docs/en/api/qiskit/release-notes/2.2
---

# Qiskit SDK 2.2 release notes

## 2.2.3

### Prelude

Qiskit 2.2.3 fixes a bug that was introduced by Qiskit 2.2.2 when using the [`run()`](/docs/api/qiskit/2.2/qiskit.transpiler.PassManager#run "qiskit.transpiler.PassManager.run") method on a [`PassManager`](/docs/api/qiskit/2.2/qiskit.transpiler.PassManager "qiskit.transpiler.PassManager") for more than one circuit.

### Upgrade Notes

- [`ConsolidateBlocks`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ConsolidateBlocks "qiskit.transpiler.passes.ConsolidateBlocks") now reads a [`PropertySet`](/docs/api/qiskit/2.2/qiskit.passmanager.PropertySet "qiskit.passmanager.PropertySet") key `ConsolidateBlocks_qubit_map` on entry. This key and its value are not public and should not be read or written to by other passes.

### Bug Fixes

- Fixed re-use of the same [`ConsolidateBlocks`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ConsolidateBlocks "qiskit.transpiler.passes.ConsolidateBlocks") instance on multiple circuits, including calls to [`transpile()`](/docs/api/qiskit/2.2/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile") with more than one circuit and no process-based parallelization. A bug introduced in Qiskit 2.2.2 caused the pass to panic or produce invalid output if the same instance was re-used on differing circuits.

## 2.2.2

### Prelude

Qiskit 2.2.2 is a bugfix release for the v2.2 minor version series.

### Bug Fixes

- Fixed the implementation of [`__deepcopy__()`](https://docs.python.org/3/library/copy.html#object.__deepcopy__) in [`QuantumCircuit`](/docs/api/qiskit/2.2/qiskit.circuit.QuantumCircuit "qiskit.circuit.QuantumCircuit") which did not deep-copy circuit parameters. As a consequence, mutating a [`BoxOp`](/docs/api/qiskit/2.2/qiskit.circuit.BoxOp "qiskit.circuit.BoxOp") in a copied circuit no longer affects the original circuit.

- Fixed an issue in the [`Optimize1qGatesDecomposition`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.Optimize1qGatesDecomposition "qiskit.transpiler.passes.Optimize1qGatesDecomposition") pass when the pass is initialized with a [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") containing 1-qubit gates with fixed angle parameters. Previously, the pass would potentially output gates not included in the target as it did not check whether the gates in the target supported arbitrary parameter values. Fixed [#14743](https://github.com/Qiskit/qiskit/issues/14743).

- Fixed incorrect behavior in the [`BasisTranslator`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.BasisTranslator "qiskit.transpiler.passes.BasisTranslator") pass where a multi-qubit gate within a [`ControlFlowOp`](/docs/api/qiskit/2.2/qiskit.circuit.ControlFlowOp "qiskit.circuit.ControlFlowOp") block would track using its local qubit indices instead of using the absolute indices from the source circuit.

- The [`ConsolidateBlocks`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ConsolidateBlocks "qiskit.transpiler.passes.ConsolidateBlocks") transpiler pass will now correctly evaluate whether a given gate is hardware-supported while recursing into control-flow operations.

- [`qpy.dump()`](/docs/api/qiskit/2.2/qpy#qiskit.qpy.dump "qiskit.qpy.dump") can now handle writing out to `.gz` files opened using the standard-library [`gzip`](https://docs.python.org/3/library/gzip.html#module-gzip) module with QPY versions 16 or greater. See [#15157](https://github.com/Qiskit/qiskit/pull/15157) for details.

- Fixed the method [`MCPhaseGate.inverse()`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCPhaseGate#inverse "qiskit.circuit.library.MCPhaseGate.inverse") to preserve the control states of open-controlled gates when computing their inverses.

- [`ConsolidateBlocks`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ConsolidateBlocks "qiskit.transpiler.passes.ConsolidateBlocks") will now return a Python-space exception instead of panicking when it detects invalid or out-of-date analysis in the legacy `run_list` or `block_list` [`PropertySet`](/docs/api/qiskit/2.2/qiskit.passmanager.PropertySet "qiskit.passmanager.PropertySet") keys. Fixed [#14646](https://github.com/Qiskit/qiskit/issues/14646).

- [`Optimize1qGatesDecomposition`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.Optimize1qGatesDecomposition "qiskit.transpiler.passes.Optimize1qGatesDecomposition") will now raise a [`TranspilerError`](/docs/api/qiskit/2.2/transpiler#qiskit.transpiler.TranspilerError "qiskit.transpiler.TranspilerError") instead of a Rust-space panic when attempting to run on a circuit that is too large for the [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target"). Fixed [#15116](https://github.com/Qiskit/qiskit/issues/15116).

- The scheduling passes, [`ALAPScheduleAnalysis`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ALAPScheduleAnalysis "qiskit.transpiler.passes.ALAPScheduleAnalysis") and [`ASAPScheduleAnalysis`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ASAPScheduleAnalysis "qiskit.transpiler.passes.ASAPScheduleAnalysis"), will now correctly handle circuits with no operations in them. Previously they raised a [`TranspilerError`](/docs/api/qiskit/2.2/transpiler#qiskit.transpiler.TranspilerError "qiskit.transpiler.TranspilerError") falsely claiming “No durations provided”. Fixed [#15145](https://github.com/Qiskit/qiskit/issues/15145).

- Fixed a failure in the circuit text drawer, which could occur when circuit blocks inside control flow operations were defined on different registers than the outer circuit. This situation could for example happen when appending [`ControlFlowOp`](/docs/api/qiskit/2.2/qiskit.circuit.ControlFlowOp "qiskit.circuit.ControlFlowOp") operations directly, or for circuits after transpilation.

## 2.2.1

### Prelude

Qiskit 2.2.1 is a small patch release that fixes several bugs identified in the 2.2.0 release.

### Transpiler Upgrade Notes

- The maximum call and trial limits for the exact-matching run of [`VF2PostLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2PostLayout "qiskit.transpiler.passes.VF2PostLayout") at `optimization_level=3` have been reduced to avoid excessive runtimes for highly symmetric trial circuits being mapped to large coupling maps.

### Bug Fixes

- [`DAGCircuit.apply_operation_back()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#apply_operation_back "qiskit.dagcircuit.DAGCircuit.apply_operation_back"), [`apply_operation_back()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#apply_operation_back "qiskit.dagcircuit.DAGCircuit.apply_operation_back") and `circuit_to_dag()` will now add new edges in a deterministic order. The previous behavior could cause certain transpiler passes (such as [`SabreSwap`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.SabreSwap "qiskit.transpiler.passes.SabreSwap")) to traverse the DAG in non-deterministic orders.

- [`DAGCircuit.apply_operation_front()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#apply_operation_front "qiskit.dagcircuit.DAGCircuit.apply_operation_front") can no longer insert invalid self loops when handling nodes that include classical conditions.

- Fixed an issue with [`pickle`](https://docs.python.org/3/library/pickle.html#module-pickle) support for the [`SabreSwap`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.SabreSwap "qiskit.transpiler.passes.SabreSwap") where a [`SabreSwap`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.SabreSwap "qiskit.transpiler.passes.SabreSwap") instance would error when being pickled after the [`SabreSwap.run()`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.SabreSwap#run "qiskit.transpiler.passes.SabreSwap.run") method was run. Fixed [#15071](https://github.com/Qiskit/qiskit/issues/15071).

- Fixed an issue where [`is_unitary()`](/docs/api/qiskit/2.2/qiskit.quantum_info.SparsePauliOp#is_unitary "qiskit.quantum_info.SparsePauliOp.is_unitary") was not properly respecting the input tolerance values when checking if an operator is unitary. The method now correctly uses the provided `atol` and `rtol` parameters when simplifying the operator and checking if it equals the identity. This fixes [#14107](https://github.com/Qiskit/qiskit/issues/14107).

## 2.2.0

### Prelude

The Qiskit v2.2 adds several enhancements for the C API and the transpiler as well as many other improvements and bug fixes. The major features of this new release are:

> - **C API transpile function:** The C API now includes a function for transpiling a quantum circuit: [`qk_transpile()`](/docs/api/qiskit-c/2.2/qk-transpiler). This function is equivalent to the Python [`transpile()`](/docs/api/qiskit/2.2/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile") function for a standalone C context.
> - **Litinski transformation pass:** A new transformation pass [`LitinskiTransformation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.LitinskiTransformation "qiskit.transpiler.passes.LitinskiTransformation") that implements the transform described [arXiv:1808.02892](https://arxiv.org/abs/1808.02892). This is pass is typically used in compilation for fault tolerant architectures.
> - **Angle bound support for targets:** The [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") class now supports specifying bounds for the allowed values for parameterized operations added to the target. When an instruction is added to the [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") you can add the optional argument angle\_bounds to specify the higher and lower bounds for parameterized rotation gates. A new transpiler pass [`WrapAngles`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.WrapAngles "qiskit.transpiler.passes.WrapAngles") was added to enforce the angle constraints as part of a transpilation pipeline.

The v2.2 release series is the final minor release series with support Python 3.9. The minimum supported Rust version use to build Qiskit from source is now Rust v1.85, raised from 1.79 in 2.1.0. For more information about the above and other changes made, please see the release notes below and review the updated documentation.

### C API Features

- Added new standalone transpiler pass functions to the C API. These functions take in a `QkCircuit` to run the pass on and are equivalent to calling an instantiated pass.

  > | Transpiler pass                                                                                                                                                                  | C API Counterpart                                                                                                     |
  > | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
  > | [`BasisTranslator`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.BasisTranslator "qiskit.transpiler.passes.BasisTranslator")                                                    | [`qk_transpiler_pass_standalone_basis_translator()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                     |
  > | [`CommutativeCancellation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.CommutativeCancellation "qiskit.transpiler.passes.CommutativeCancellation")                            | [`qk_transpiler_pass_standalone_commutative_cancellation()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)             |
  > | [`ConsolidateBlocks`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ConsolidateBlocks "qiskit.transpiler.passes.ConsolidateBlocks")                                              | [`qk_transpiler_pass_standalone_consolidate_blocks()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                   |
  > | [`ElidePermutations`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ElidePermutations "qiskit.transpiler.passes.ElidePermutations")                                              | [`qk_transpiler_pass_standalone_elide_permutations()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                   |
  > | [`CheckGateDirection`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.CheckGateDirection "qiskit.transpiler.passes.CheckGateDirection")                                           | [`qk_transpiler_pass_standalone_check_gate_direction()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                 |
  > | [`GateDirection`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.GateDirection "qiskit.transpiler.passes.GateDirection")                                                          | [`qk_transpiler_pass_standalone_gate_direction()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                       |
  > | [`InverseCancellation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.InverseCancellation "qiskit.transpiler.passes.InverseCancellation")                                        | [`qk_transpiler_pass_standalone_inverse_cancellation()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                 |
  > | [`Optimize1qGatesDecomposition`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.Optimize1qGatesDecomposition "qiskit.transpiler.passes.Optimize1qGatesDecomposition")             | [`qk_transpiler_standalone_optimize_1q_sequences()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                     |
  > | [`RemoveDiagonalGatesBeforeMeasure`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.RemoveDiagonalGatesBeforeMeasure "qiskit.transpiler.passes.RemoveDiagonalGatesBeforeMeasure") | [`qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes) |
  > | [`RemoveIdentityEquivalent`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.RemoveIdentityEquivalent "qiskit.transpiler.passes.RemoveIdentityEquivalent")                         | [`qk_transpiler_pass_standalone_remove_identity_equivalent()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)           |
  > | [`SabreLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.SabreLayout "qiskit.transpiler.passes.SabreLayout")                                                                | [`qk_transpiler_pass_standalone_sabre_layout()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                         |
  > | [`Split2QUnitaries`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.Split2QUnitaries "qiskit.transpiler.passes.Split2QUnitaries")                                                 | [`qk_transpiler_pass_standalone_split_2q_unitaries()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                   |
  > | [`UnitarySynthesis`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.UnitarySynthesis "qiskit.transpiler.passes.UnitarySynthesis")                                                 | [`qk_transpiler_pass_standalone_unitary_synthesis()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                    |
  > | [`VF2Layout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2Layout "qiskit.transpiler.passes.VF2Layout")                                                                      | [`qk_transpiler_pass_standalone_vf2_layout()`](/docs/api/qiskit-c/2.2/qk-transpiler-passes)                           |

- The `QkTarget` type can now represent targets that support parameterized `QkGate` types that accept any parameter value. Previously, these gates could only be added to the target with a fixed angle value supported by using [`qk_target_entry_new_fixed()`](/docs/api/qiskit-c/2.2/qk-target-entry) to create the `QkTargetEntry`. Now, the [`qk_target_entry_new()`](/docs/api/qiskit-c/2.2/qk-target-entry) function can be used with parameterized gates. When it is used with parameterized gates, this function indicates that the gate in the target supports any value for all of the gate’s parameters. For example:

  ```c
  #include <qiskit.h>

  QkTarget *target = qk_target_new(5);
  QkTargetEntry *rz_entry = qk_target_entry_new(QkGate_RZ);
  for (uint32_t i = 0; i < 5; i++) {
      uint32_t qargs[1] = {i};
      qk_target_entry_add_property(rz_entry, qargs, 1, 1.2e-6, 1.3e-9);
  }
  qk_target_add_instruction(target, rz_entry);

  // Clean up after using target
  qk_target_free(target);
  ```

  This creates a 5 qubit target that will accept an RZ gate on any qubit with any parameter value being supported by that gate.

- Added [`qk_obs_apply_layout()`](/docs/api/qiskit-c/2.2/qk-obs) to apply new qubit layouts to a `QkObs` observable. This function takes the observable, the new qubit indices, and an output number of qubits. Importantly, this function allows applying transpile layouts, usually given as `QkTranspileLayout` by a transpiler pass, to an observable. For example:

  ```c
  // get the number of output qubits -- transpile_layout is a QkTranspileLayout*
  uint32_t num_output_qubits = qk_transpile_layout_num_output_qubits(transpile_layout);

  // get the layout including the ancillas (hence the ``false`` in the function call)
  uint32_t *layout = malloc(sizeof(uint32_t) * num_output_qubits);
  qk_transpile_layout_final_layout(transpile_layout, false, layout);

  // apply the layout -- obs is a QkObs*
  int exit = qk_obs_apply_layout(obs, layout, num_output_qubits);

  // free the layout array
  free(layout);
  ```

- Added a new function [`qk_transpile()`](/docs/api/qiskit-c/2.2/qk-transpiler) to the Qiskit C API. This function is used for transpiling quantum circuits in a standalone C context without using Python. This is the last major component needed in the C API for typical hardware execution workflows using Qiskit.

  This function mirrors the preset pass managers that are used for the Python transpiler except for some passes and functionality is skipped if it is not relevant for circuits constructed using the C API. This makes the function only suitable for standalone C contexts.

- Added a new type `QkTranspileLayout` to the C API. This type is used for reasoning about the permutations caused by the transpiler.

### Circuits Features

- A new method, [`QuantumCircuit.ensure_physical()`](/docs/api/qiskit/2.2/qiskit.circuit.QuantumCircuit#ensure_physical "qiskit.circuit.QuantumCircuit.ensure_physical"), is provided to ensure that a circuit is defined over physical qubits, with the qubit indices referring to physical qubits. See the [new discussion on abstract- and physical-circuit representations in the documentation](/docs/api/qiskit/2.2/qiskit.circuit.QuantumCircuit#circuit-abstract-physical) for more detail on the metadata concepts. The concepts of “abstract” and “physical” circuits are not at all new to Qiskit, just the explicit documentation.

- The `Duration` class has gained a new `ps` variant, which can be used to represent a duration in picoseconds.

- Improved [`PauliEvolutionGate.control()`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate#control "qiskit.circuit.library.PauliEvolutionGate.control"), [`PauliEvolutionGate.power()`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate#power "qiskit.circuit.library.PauliEvolutionGate.power") and [`PauliEvolutionGate.inverse()`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate#inverse "qiskit.circuit.library.PauliEvolutionGate.inverse") to return more efficient representations in terms of a [`PauliEvolutionGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate "qiskit.circuit.library.PauliEvolutionGate"). For computing the controlled and exponentiated versions of the evolution gate this change leads to significantly shallower circuits and lower gate counts compared to the previously used generic mechanisms. The inverse decomposition does not change but is now generated more efficiently and allows for better compiler optimizations.

- A new fast-path method [`ParameterExpression.bind_all()`](/docs/api/qiskit/2.2/qiskit.circuit.ParameterExpression#bind_all "qiskit.circuit.ParameterExpression.bind_all") is added to support the use-case of binding many different [`ParameterExpression`](/docs/api/qiskit/2.2/qiskit.circuit.ParameterExpression "qiskit.circuit.ParameterExpression") instances to numeric values using the same mappings dictionary. The existing [`bind()`](/docs/api/qiskit/2.2/qiskit.circuit.ParameterExpression#bind "qiskit.circuit.ParameterExpression.bind") method has a large amount of overhead and unnecessary allocations, since it always returns a [`ParameterExpression`](/docs/api/qiskit/2.2/qiskit.circuit.ParameterExpression "qiskit.circuit.ParameterExpression") for typing consistency.

### OpenQASM Features

- Added partial support for `defcal` symbols in the OpenQASM3 exporter. This enables downstream packages to export custom instructions that operate on both quantum and classical bits using [`qiskit.qasm3.dumps()`](/docs/api/qiskit/2.2/qasm3#qiskit.qasm3.dumps "qiskit.qasm3.dumps"). Users can now define custom instructions (e.g., a `CustomMeasure` that acts on a qubit and returns a classical bit) and specify their behavior using `DefcalInstruction`. These defcals are passed to the exporter via the `implicit_defcals` argument in [`qiskit.qasm3.dumps()`](/docs/api/qiskit/2.2/qasm3#qiskit.qasm3.dumps "qiskit.qasm3.dumps").

  For example:

  ```python
  from qiskit.circuit import Instruction, QuantumCircuit
  from qiskit.qasm3 import dumps
  from qiskit.qasm3.exporter import DefcalInstruction, types

  custom_measure = Instruction("measure_2", 1, 1, [])
  qc = QuantumCircuit(1, 1)
  qc.h(0)
  qc.append(custom_measure, [0], [0])
  qc.measure(0, 0)

  defcals = {
      "measure_2": DefcalInstruction("measure_2", 0, 1, types.Bool()),
  }

  out_qasm = dumps(qc, implicit_defcals=defcals)
  print(out_qasm)
  ```

  Would output the following valid OpenQASM3 string:

  ```python
  OPENQASM 3.0;
  bit[1] c;
  qubit[1] q;
  h q[0];
  c[0] = measure_2 q[0];
  c[0] = measure q[0];
  ```

  This approach assumes that the grammar definition for the defcal is provided externally (e.g., in a header file), although such a file is not strictly required for the exporter to function.

- The functions [`qasm3.loads()`](/docs/api/qiskit/2.2/qasm3#qiskit.qasm3.loads "qiskit.qasm3.loads") and [`qasm3.load()`](/docs/api/qiskit/2.2/qasm3#qiskit.qasm3.load "qiskit.qasm3.load") now have an extra argument called `num_qubits`. If provided, the functions will return circuits that will have qubits equal to `num_qubits`. If not provided, the returned circuit will have qubits equal to the maximum index seen in the serialized circuit. Refer to [#14435](https://github.com/Qiskit/qiskit/issues/14435) for more details

### QPY Features

- Added a setting named `min_qpy_version` in the user configuration file. When set, it defines the minimum allowed QPY version for [`qpy.load()`](/docs/api/qiskit/2.2/qpy#qiskit.qpy.load "qiskit.qpy.load"). If the format version of a QPY file is lower than the `minimum_qpy_version` than the `minimum_qpy_version` setting it will raise an exception.

- Introduced QPY format version 16. This new version introduces a new circuit start table to the file header which contains the byte offsets of the start of each circuit in a QPY file. This allows for a potentially more efficient loading of circuits from QPY files, and a potentially multi-threaded Rust implementation in the future. Additionally, the new format version adds support for the new `DURATION` variant of picoseconds.

### Quantum Information Features

- Added the [`PauliLindbladMap.drop_qubits()`](/docs/api/qiskit/2.2/qiskit.quantum_info.PauliLindbladMap#drop_qubits "qiskit.quantum_info.PauliLindbladMap.drop_qubits") and [`PauliLindbladMap.keep_qubits()`](/docs/api/qiskit/2.2/qiskit.quantum_info.PauliLindbladMap#keep_qubits "qiskit.quantum_info.PauliLindbladMap.keep_qubits") methods to trace subsystems out of Pauli Lindblad maps.

- Added methods [`QubitSparsePauli.to_pauli()`](/docs/api/qiskit/2.2/qiskit.quantum_info.QubitSparsePauli#to_pauli "qiskit.quantum_info.QubitSparsePauli.to_pauli") and [`QubitSparsePauliList.to_pauli_list()`](/docs/api/qiskit/2.2/qiskit.quantum_info.QubitSparsePauliList#to_pauli_list "qiskit.quantum_info.QubitSparsePauliList.to_pauli_list"), which convert the sparse objects into the corresponding dense versions, [`Pauli`](/docs/api/qiskit/2.2/qiskit.quantum_info.Pauli "qiskit.quantum_info.Pauli") and [`PauliList`](/docs/api/qiskit/2.2/qiskit.quantum_info.PauliList "qiskit.quantum_info.PauliList"), respectively.

- Added the [`PhasedQubitSparsePauli`](/docs/api/qiskit/2.2/qiskit.quantum_info.PhasedQubitSparsePauli "qiskit.quantum_info.PhasedQubitSparsePauli") and [`PhasedQubitSparsePauliList`](/docs/api/qiskit/2.2/qiskit.quantum_info.PhasedQubitSparsePauliList "qiskit.quantum_info.PhasedQubitSparsePauliList") classes. These classes represent a single Pauli operator and a list of Pauli operators respectively stored in qubit-sparse format. These classes are very similar to [`QubitSparsePauli`](/docs/api/qiskit/2.2/qiskit.quantum_info.QubitSparsePauli "qiskit.quantum_info.QubitSparsePauli") and [`QubitSparsePauliList`](/docs/api/qiskit/2.2/qiskit.quantum_info.QubitSparsePauliList "qiskit.quantum_info.QubitSparsePauliList"), except they additionally contain phase information.

- Added the method [`QubitSparsePauliList.to_dense_array()`](/docs/api/qiskit/2.2/qiskit.quantum_info.QubitSparsePauliList#to_dense_array "qiskit.quantum_info.QubitSparsePauliList.to_dense_array"). This returns the list as an array of integers with the values of [`Pauli`](/docs/api/qiskit/2.2/qiskit.quantum_info.QubitSparsePauli#pauli "qiskit.quantum_info.QubitSparsePauli.Pauli").

### Synthesis Features

- Added new synthesis algorithm for [`ModularAdderGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.ModularAdderGate "qiskit.circuit.library.ModularAdderGate") that requires no ancillary qubits and has better CX count compared to [`adder_qft_d00()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.adder_qft_d00 "qiskit.synthesis.adder_qft_d00"):

  - [`adder_modular_v17()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.adder_modular_v17 "qiskit.synthesis.adder_modular_v17")

- Added a new synthesis algorithm, [`synth_mcx_noaux_hp24()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.synth_mcx_noaux_hp24 "qiskit.synthesis.synth_mcx_noaux_hp24"), for [`MCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate") that does not require any auxiliary qubits. This method produces a linear, rather than a quadratic number of CX gates, compared to the existing [`synth_mcx_noaux_v24()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.synth_mcx_noaux_v24 "qiskit.synthesis.synth_mcx_noaux_v24") algorithm. In particular, the new method is better when the number of control qubits is greater than five. The algorithm is based on the paper “Compiling Conditional Quantum Gates without Using Helper Qubits” by Huang and Palsberg ([https://dl.acm.org/doi/10.1145/3656436](https://dl.acm.org/doi/10.1145/3656436)).

- Improved the [`qs_decomposition()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.qs_decomposition "qiskit.synthesis.qs_decomposition") function which was originally based on Shende et. al. ([https://arxiv.org/abs/quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176)). The new synthesis method is based on Krol and Al-Ars ([https://arxiv.org/abs/2403.13692](https://arxiv.org/abs/2403.13692)), and reduce the total number of [`CXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CXGate "qiskit.circuit.library.CXGate")s of a general n-qubit unitary by $\frac{4^{n − 2} − 1}{3}$ [`CXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CXGate "qiskit.circuit.library.CXGate")s. With the improved decomposition, a general 3-qubit unitary can be decomposed using 19 [`CXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CXGate "qiskit.circuit.library.CXGate")s (rather than 20).

- Added [`synth_mcmt_xgate()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.synth_mcmt_xgate "qiskit.synthesis.synth_mcmt_xgate") to synthesize the multi-control multi-target gate when the base gate is [`XGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.XGate "qiskit.circuit.library.XGate"). It has a decomposition in linear number of CX gates and 0 ancilla qubits along with the high-level synthesis plugin [`MCMTSynthesisXGate`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.MCMTSynthesisXGate "qiskit.transpiler.passes.synthesis.hls_plugins.MCMTSynthesisXGate").

### Transpiler Features

- Added new high-level-synthesis plugin for synthesizing a [`ModularAdderGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.ModularAdderGate "qiskit.circuit.library.ModularAdderGate"):

  - [`ModularAdderSynthesisV17`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.ModularAdderSynthesisV17 "qiskit.transpiler.passes.synthesis.hls_plugins.ModularAdderSynthesisV17"), based on [`adder_modular_v17()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.adder_modular_v17 "qiskit.synthesis.adder_modular_v17").

  The [`ModularAdderSynthesisDefault`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.ModularAdderSynthesisDefault "qiskit.transpiler.passes.synthesis.hls_plugins.ModularAdderSynthesisDefault") has also been updated to follow the following sequence of modular adder synthesizers: `"ModularAdder.qft_d00"` when the number of qubits is $\leq 4$, `"ModularAdder.modular_v17"` in all other cases.

- Added a new transpiler pass [`LitinskiTransformation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.LitinskiTransformation "qiskit.transpiler.passes.LitinskiTransformation") that implements the transform described in [arXiv:1808.02892](https://arxiv.org/abs/1808.02892).

  The input to the pass is a circuit with Clifford and single-qubit RZ-rotation gates, and the output is a circuit with multi-qubit Pauli rotations (implemented as [`PauliEvolutionGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate "qiskit.circuit.library.PauliEvolutionGate") gates) followed by Clifford gates. The pass raises a [`TranspilerError`](/docs/api/qiskit/2.2/transpiler#qiskit.transpiler.TranspilerError "qiskit.transpiler.exceptions.TranspilerError") exception if the circuit contains non-supported gates.

  The pass supports all of the Clifford gates in the list returned by [`get_clifford_gate_names()`](/docs/api/qiskit/2.2/qiskit.quantum_info.get_clifford_gate_names "qiskit.quantum_info.get_clifford_gate_names"), namely `["id", "x", "y", "z", "h", "s", "sdg", "sx", "sxdg", "cx", "cz", "cy", "swap", "iswap", "ecr", "dcx"]`. The list of supported RZ-rotations is `["t", "tdg", "rz"]` (we automatically convert T and Tdg gates to RZ-rotations).

  In addition, the [`LitinskiTransformation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.LitinskiTransformation "qiskit.transpiler.passes.LitinskiTransformation") constructor accepts an argument `fix_clifford`. When `False` (non-default), the returned circuit contains only [`PauliEvolutionGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate "qiskit.circuit.library.PauliEvolutionGate") gates, with the final Clifford gates omitted. Note that in this case the operators of the original and synthesized circuits will generally not be equivalent.

  For example:

  ```python
  from qiskit.circuit import QuantumCircuit
  from qiskit.transpiler.passes import LitinskiTransformation
  from qiskit.quantum_info import Operator

  # The following quantum circuit consists of 5 Clifford gates
  # and two single-qubits RZ-rotation gates (note that Tdg is
  # an RZ-rotation).
  qc = QuantumCircuit(2)
  qc.cx(0, 1)
  qc.rz(0.1, 0)
  qc.cz(0, 1)
  qc.tdg(1)
  qc.h(1)
  qc.s(1)
  qc.cz(1, 0)

  # The transformed circuit consists of two PauliEvolution gates
  # and the same Clifford gates as in the original circuit.
  qct = LitinskiTransformation()(qc)

  # The circuits before and after the transformation are equivalent
  assert Operator(qc) == Operator(qct)
  ```

- Added a new high-level synthesis plugin [`MCXSynthesisNoAuxHP24`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesisNoAuxHP24 "qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesisNoAuxHP24") for [`MCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate") objects. Furthermore, the default synthesis plugin [`MCXSynthesisDefault`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesisDefault "qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesisDefault") for [`MCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate") objects was updated to always choose the best synthesis method depending on the available number of auxiliary qubits.

- Added support for a [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") to specify angle bounds on instructions. Prior to this release a [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") could specify that an operation that took a parameter either would allow any valid value or a specific value. For example, if `RZGate(Parameter("theta"))` were added to the target that would indicate an [`RZGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.RZGate "qiskit.circuit.library.RZGate") with any value for theta were allowed. While if `RZGate(math.pi)` were added to the target that would indicate [`RZGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.RZGate "qiskit.circuit.library.RZGate") that only $\pi$ is the only allowed value on the target. This new feature enables restricting the allowed angles to be any `float` value between a an inclusive bound. For example, you can add `RZGate(math.pi)` to a [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") and restrict the angle value between the values 0 and $2\pi$.

  There are several methods available for working with the angle bounds on the target. The first is [`Target.add_instruction()`](/docs/api/qiskit/2.2/qiskit.transpiler.Target#add_instruction "qiskit.transpiler.Target.add_instruction") which has a new `angle_bounds` keyword argument that is used to add an angle bound to an instruction in the [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target"). To work with angle bounds you will also want to register a callback function to the global [`WRAP_ANGLE_REGISTRY`](/docs/api/qiskit/2.2/transpiler_passes#qiskit.transpiler.passes.qiskit.transpiler.passes.utils.wrap_angles.WRAP_ANGLE_REGISTRY "qiskit.transpiler.passes.qiskit.transpiler.passes.utils.wrap_angles.WRAP_ANGLE_REGISTRY") registry that will tell the transpiler and [`WrapAngles`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.WrapAngles "qiskit.transpiler.passes.WrapAngles") pass how to adjust gates for angle bounds. The callback function will take a list of arbitrary `float` values representing the gate angles from the circuit, as well as the qubit indices in the circuit the gate was operating on and it will return a [`DAGCircuit`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit") that represents an equivalent circuit for the gate with that angle but respecting the angle bounds and other [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") constraints. For example:

  ```python
  import math

  from qiskit.dagcircuit import DAGCircuit
  from qiskit.transpiler import Target
  from qiskit.transpiler.passes.utils.wrap_angles import WRAP_ANGLE_REGISTRY

  target = Target(num_qubits=1)
  target.add_instruction(RZGate(Parameter("theta")), angle_bounds=[(-math.pi, math.pi)])

  def callback(angles: List[float], qubits: List[int]) -> DAGCircuit:
      """Callback function to wrap RZ gate angles

      Args:
          angles: The list of floating point parameter values for the instance of RZGate in
              the circuit
          qubits: The physical qubit indices that this gate is operating on

      Returns:
          The DAGCircuit of the equivalent circuit"""

      angle = angles[0]
      dag = DAGCircuit()
      dag.add_qubits([Qubit()])
      if angle > 0:
          divisor = math.pi
      else:
          divisor = -math.pi
      gate_counts = int(angles[0] // divisor)
      rem = angles[0] % divisor
      for _ in range(gate_counts):
          dag.apply_operation_back(RZGate(math.pi), [dag.qubits[0]], check=True)
      dag.apply_operation_back(rem, [dag.qubits[0]], check=True)

  WRAP_ANGLE_REGISTRY.add_wrapper("rz", callback)
  ```

  [`Target.has_angle_bounds()`](/docs/api/qiskit/2.2/qiskit.transpiler.Target#has_angle_bounds "qiskit.transpiler.Target.has_angle_bounds") can be used to check whether there are any angle bounds set in the target, and [`Target.gate_has_angle_bounds()`](/docs/api/qiskit/2.2/qiskit.transpiler.Target#gate_has_angle_bounds "qiskit.transpiler.Target.gate_has_angle_bounds").

  If you want to apply the angle bounds from a target to any gates in a circuit the [`WrapAngles`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.WrapAngles "qiskit.transpiler.passes.WrapAngles") transpiler pass should be used to do this.

- Added a new kwarg `check_angle_bounds` to the [`Target.instruction_supported()`](/docs/api/qiskit/2.2/qiskit.transpiler.Target#instruction_supported "qiskit.transpiler.Target.instruction_supported") method. When set to `True` (the default) the method will check if the specified `parameters` also conforms to any angle bounds that may exist for the instruction being queried.

- Added a new transpiler pass [`WrapAngles`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.WrapAngles "qiskit.transpiler.passes.WrapAngles") which is used to apply angle constraints on gates in the [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target"). If a [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") has defined angle bounds this pass will analyze all the parameters for the gates in the circuit and check that against the bounds specified in the target. For example, if a target contains a custom gate that has angle bounds the pass will decompose that gate into a gate which conforms to the bounds:

  ```python
  from qiskit.circuit import Gate, Parameter, QuantumCircuit, Qubit
  from qiskit.dagcircuit import DAGCircuit
  from qiskit.transpiler import Target, WrapAngleRegistry
  from qiskit.transpiler.passes import WrapAngles

  class MyCustomGate(Gate):

      def __init__(self, angle):
          super().__init__("my_custom", 1, [angle])

  param = Parameter("a")
  circuit = QuantumCircuit(1)
  circuit.append(MyCustomGate(6.0), [0])
  target = Target(num_qubits=1)
  target.add_instruction(MyCustomGate(param), angle_bounds=[(0, 0.5)])

  def callback(angles, _qubits):
      angle = angles[0]
      if angle > 0:
          number_of_gates = angle / 0.5
      else:
          number_of_gates = (6.28 - angle) / 0.5
      dag = DAGCircuit()
      dag.add_qubits([Qubit()])
      for _ in range(int(number_of_gates)):
          dag.apply_operation_back(MyCustomGate(0.5), [dag.qubits[0]])
      return dag

  registry = WrapAngleRegistry()
  registry.add_wrapper("my_custom", callback)
  wrap_pass = WrapAngles(target, registry)
  res = wrap_pass(circuit)
  res.draw('mpl')
  ```

  ![\_images/release\_notes-1.png](https://eu-de.quantum.cloud.ibm.com/docs/images/api/qiskit/2.2/release_notes-1.avif)

- [`DAGCircuit`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit") now has a manual implementation of [`__deepcopy__()`](https://docs.python.org/3/library/copy.html#object.__deepcopy__). This is orders of magnitude faster than the previous implicit implementation from the pickle protocol, especially for large circuits. This also directly benefits compilation performance when running [`transpile()`](/docs/api/qiskit/2.2/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile") or running the preset pass managers returned by [`generate_preset_pass_manager()`](/docs/api/qiskit/2.2/qiskit.transpiler.generate_preset_pass_manager "qiskit.transpiler.generate_preset_pass_manager") at `optimization_level=3` as optimization level 3 internally deep copies the [`DAGCircuit`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit") for each iteration of the optimization loop in the `optimization` stage.

- A new method, [`DAGCircuit.make_physical()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#make_physical "qiskit.dagcircuit.DAGCircuit.make_physical"), is provided, which efficiently replaces the qubits in the [`DAGCircuit`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit") with the canonical physical-qubit register, potentially including expansion. A similar method, [`QuantumCircuit.ensure_physical()`](/docs/api/qiskit/2.2/qiskit.circuit.QuantumCircuit#ensure_physical "qiskit.circuit.QuantumCircuit.ensure_physical") is also available.

- A new method, [`DAGCircuit.structurally_equal()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#structurally_equal "qiskit.dagcircuit.DAGCircuit.structurally_equal"), can be used to if two [`DAGCircuit`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit") instances have been created and modified in the exact same order. This is a much stronger test than the standard semantic equivalence check of the `==` overload, and can be used by transpiler-pass authors to verify that their modification orders are deterministic.

- Custom subclasses of [`BasePassManager`](/docs/api/qiskit/2.2/qiskit.passmanager.BasePassManager "qiskit.passmanager.BasePassManager") can now modify their `property_set` attribute during their `_passmanager_frontend()` method, to seed initial properties. This provides symmetry, as it was previously only possible to read the final properties during `_passmanager_backend()`.

- Added a new class [`OptimizationMetric`](/docs/api/qiskit/2.2/qiskit.transpiler.OptimizationMetric "qiskit.transpiler.OptimizationMetric") which specifies the optimization criterion in the [`HighLevelSynthesis`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.HighLevelSynthesis "qiskit.transpiler.passes.HighLevelSynthesis") pass. Currently the two supported metrics are:

  - `COUNT_2Q`: optimizes the number of two-qubit gates.
  - `COUNT_T`: optimizes the number of T-gates, when transpiling into a Clifford+T basis set.

  The transpiler automatically selects the target metric based on the basis gate set, e.g. it will use `COUNT_T` if a Clifford+T basis set is detected. However, this class can not be currently set manually when running [`transpile()`](/docs/api/qiskit/2.2/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile") or running a preset pass manager generated by [`generate_preset_pass_manager()`](/docs/api/qiskit/2.2/qiskit.transpiler.generate_preset_pass_manager "qiskit.transpiler.generate_preset_pass_manager").

- Added a new argument `optimization_metric` to the constructor for [`HighLevelSynthesis`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.HighLevelSynthesis "qiskit.transpiler.passes.HighLevelSynthesis") transpiler pass which takes an [`OptimizationMetric`](/docs/api/qiskit/2.2/qiskit.transpiler.OptimizationMetric "qiskit.transpiler.OptimizationMetric") object. When set to `COUNT_T`, the pass chooses decompositions that are more suitable for the Clifford+T gate set.

- The default high-level synthesis plugins for [`ModularAdderGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.ModularAdderGate "qiskit.circuit.library.ModularAdderGate") and [`MultiplierGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.MultiplierGate "qiskit.circuit.library.MultiplierGate") produce better T-counts when transpiling into Clifford+T basis set.

- The default high-level synthesis plugin for [`MCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate") produces better T-counts when transpiling into Clifford+T basis set, provided at least 1 ancilla qubit is available.

- Added a default set of inverse gates for the [`InverseCancellation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.InverseCancellation "qiskit.transpiler.passes.InverseCancellation") transpiler pass. Previously, an explicit list of gates or gate pairs to cancel was a required argument for the constructor of the pass object. Now this list is optional and if no list is provided the self inverse gates are:

  > - [`CXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CXGate "qiskit.circuit.library.CXGate")
  > - [`ECRGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.ECRGate "qiskit.circuit.library.ECRGate")
  > - [`CYGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CYGate "qiskit.circuit.library.CYGate")
  > - [`CZGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CZGate "qiskit.circuit.library.CZGate")
  > - [`XGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.XGate "qiskit.circuit.library.XGate")
  > - [`YGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.YGate "qiskit.circuit.library.YGate")
  > - [`ZGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.ZGate "qiskit.circuit.library.ZGate")
  > - [`HGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.HGate "qiskit.circuit.library.HGate")
  > - [`SwapGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.SwapGate "qiskit.circuit.library.SwapGate")
  > - [`CHGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CHGate "qiskit.circuit.library.CHGate")
  > - [`CCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CCXGate "qiskit.circuit.library.CCXGate")
  > - [`CCZGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CCZGate "qiskit.circuit.library.CCZGate")
  > - [`RCCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.RCCXGate "qiskit.circuit.library.RCCXGate")
  > - [`CSwapGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CSwapGate "qiskit.circuit.library.CSwapGate")
  > - [`C3XGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.C3XGate "qiskit.circuit.library.C3XGate")

  and the inverse pairs:

  > - [`TGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.TGate "qiskit.circuit.library.TGate") and [`TdgGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.TdgGate "qiskit.circuit.library.TdgGate")
  > - [`SGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.SGate "qiskit.circuit.library.SGate") and [`SdgGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.SdgGate "qiskit.circuit.library.SdgGate")
  > - [`SXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.SXGate "qiskit.circuit.library.SXGate") and [`SXdgGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.SXdgGate "qiskit.circuit.library.SXdgGate")
  > - [`CSGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CSGate "qiskit.circuit.library.CSGate") and [`CSdgGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CSdgGate "qiskit.circuit.library.CSdgGate")

  will be cancelled by the pass.

- Added a new argument to the [`InverseCancellation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.InverseCancellation "qiskit.transpiler.passes.InverseCancellation") constructor, `run_default`, which when set to `True` will run the new default inverse cancellation gate list in addition to the any custom gates provided. This is intended for use cases where you want to run a custom set of inverse cancellations in addition to the default gates.

- [`TranspileLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout "qiskit.transpiler.TranspileLayout") has two new methods: [`from_property_set()`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout#from_property_set "qiskit.transpiler.TranspileLayout.from_property_set") and [`write_into_property_set()`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout#write_into_property_set "qiskit.transpiler.TranspileLayout.write_into_property_set"), which formalize the current ad-hoc structure of transpilation properties, and how they are converted into a [`TranspileLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout "qiskit.transpiler.TranspileLayout"). This makes it possible for passes *during* a transpiler pipeline to access what the [`TranspileLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout "qiskit.transpiler.TranspileLayout") will be, modify it in the fully structured form, and then write it back out in canonical form.

  It is expected that in the future version 3.0 of Qiskit, the [`TranspileLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout "qiskit.transpiler.TranspileLayout") (or something akin to it) will be a direct attribute of the [`DAGCircuit`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit") transpiler intermediate representation, and required by passes to be kept in sync with the rest of the [`DAGCircuit`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit").

- Re-enabled running [`VF2PostLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2PostLayout "qiskit.transpiler.passes.VF2PostLayout") transpiler pass in the `optimization` stage for `optimization_level=3` with the [`transpile()`](/docs/api/qiskit/2.2/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile") function and the generated pass manager objects returned by the [`generate_preset_pass_manager()`](/docs/api/qiskit/2.2/qiskit.transpiler.generate_preset_pass_manager "qiskit.transpiler.generate_preset_pass_manager") function. The pass runs with `strict_direction=True` after all the physical optimizations performed in the stage to attempt and improve the layout one final time with the exact output circuit. This was previously enabled in Qiskit v2.1.0 but was reverted in 2.1.2 due to issues with the initial implementation. These issues have been fixed and the layout will be properly applied if a better one is found.

### Visualization Features

- A new option, `measure_arrows`, has been added to the `mpl` and `text` backends for the circuit drawer [`qiskit.visualization.circuit_drawer()`](/docs/api/qiskit/2.2/qiskit.visualization.circuit_drawer "qiskit.visualization.circuit_drawer") and [`qiskit.circuit.QuantumCircuit.draw()`](/docs/api/qiskit/2.2/qiskit.circuit.QuantumCircuit#draw "qiskit.circuit.QuantumCircuit.draw"). When this option is set to `True`, the drawer will draw an arrow from the `measure` box to the classical bits below. This was the previous behavior in the drawers. If it is set to `False`, no arrows will be drawn and instead the classical register and bit being used by the `measure` will be indicated inside the `measure` box. This allows `measure` boxes to be stacked within a vertical layer.

  If no option is set, the default is `True`. The user can change the default in the user config file, by default in the `~/.qiskit` directory, in the file `settings.conf`. Under the `[Default]` heading, a user can enter `circuit_measure_arrows = False` to change the default.

### Upgrade Notes

- The minimum support Rust version for building Qiskit from source (including building the C API in standalone mode) has been increased from Rust 1.79 to Rust 1.85. This change was necessary to enable using a newer version of the Rust linear algebra library [faer](https://crates.io/crates/faer) that is used inside Qiskit. There were issues identified when running Qiskit on Windows with the previous version of faer. These were fixed in the newer release, however a newer version of the Rust compiler is required to build the newer version of faer.

### Circuits Upgrade Notes

- The circuit definition of [`ModularAdderGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.ModularAdderGate "qiskit.circuit.library.ModularAdderGate") has been upgraded to use [`adder_modular_v17()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.adder_modular_v17 "qiskit.synthesis.adder_modular_v17"). To obtain the old behaviour, use the definition of [`adder_qft_d00()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.adder_qft_d00 "qiskit.synthesis.adder_qft_d00") instead.

- The methods [`XGate.control()`](/docs/api/qiskit/2.2/qiskit.circuit.library.XGate#control "qiskit.circuit.library.XGate.control"), [`CXGate.control()`](/docs/api/qiskit/2.2/qiskit.circuit.library.CXGate#control "qiskit.circuit.library.CXGate.control"), [`CCXGate.control()`](/docs/api/qiskit/2.2/qiskit.circuit.library.CCXGate#control "qiskit.circuit.library.CCXGate.control"), [`C3XGate.control()`](/docs/api/qiskit/2.2/qiskit.circuit.library.C3XGate#control "qiskit.circuit.library.C3XGate.control"), [`C4XGate.control()`](/docs/api/qiskit/2.2/qiskit.circuit.library.C4XGate#control "qiskit.circuit.library.C4XGate.control"), and [`MCXGate.control()`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate#control "qiskit.circuit.library.MCXGate.control") no longer return an [`AnnotatedOperation`](/docs/api/qiskit/2.2/qiskit.circuit.AnnotatedOperation "qiskit.circuit.AnnotatedOperation") when the argument `annotated` is set to `True`, and instead return the same explicit [`MCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate") that one would get when `annotated` is `False`. This is consistent with how the argument `annotated` is used across the standard circuit library, where we generally avoid introducing an [`AnnotatedOperation`](/docs/api/qiskit/2.2/qiskit.circuit.AnnotatedOperation "qiskit.circuit.AnnotatedOperation") when a native gate class is already available. In practice, this leads to more efficient decompositions of control-annotated gates in the MCX family.

### C API Upgrade Notes

- Most usage of `uintptr_t` has been changed to `size_t`. Specifically the following usages have been changed:

  > - [`QkOpCount.count`](/docs/api/qiskit-c/2.2/qk-circuit)
  > - [`QkOpCounts.len`](/docs/api/qiskit-c/2.2/qk-circuit)
  > - [`QkObsTerm.len`](/docs/api/qiskit-c/2.2/qk-obs-term)
  > - The return type of [`qk_circuit_num_instructions()`](/docs/api/qiskit-c/2.2/qk-circuit).
  > - The `index` argument in [`qk_circuit_get_instruction()`](/docs/api/qiskit-c/2.2/qk-circuit).
  > - The `boundaries` argument in [`qk_obs_new()`](/docs/api/qiskit-c/2.2/qk-obs).
  > - The return types of [`qk_obs_num_terms()`](/docs/api/qiskit-c/2.2/qk-obs), [`qk_obs_len()`](/docs/api/qiskit-c/2.2/qk-obs), and [`qk_obs_boundaries()`](/docs/api/qiskit-c/2.2/qk-obs).
  > - The return type of [`qk_target_entry_num_properties()`](/docs/api/qiskit-c/2.2/qk-target-entry), and [`qk_target_num_instructions()`](/docs/api/qiskit-c/2.2/qk-target).

  This change was necessary because the tool used to generate the C header files from Qiskit’s rust code, [cbindgen](https://github.com/mozilla/cbindgen?tab=readme-ov-file) was using `uintptr_t` by default in places where `size_t` more accurately aligned with the type usage in Rust. This change was made to make it more clear how the values in the C API are intended to be used.

### QPY Upgrade Notes

- The default version of QPY emitted by [`qpy.dump()`](/docs/api/qiskit/2.2/qpy#qiskit.qpy.dump "qiskit.qpy.dump") is now QPY format version 16. If you require a different format version you can use the `version` argument to specify an earlier format version.

### Quantum Information Upgrade Notes

- [`SparsePauliOp.assign_parameters()`](/docs/api/qiskit/2.2/qiskit.quantum_info.SparsePauliOp#assign_parameters "qiskit.quantum_info.SparsePauliOp.assign_parameters") will now set the dtype of the output [`coeffs`](/docs/api/qiskit/2.2/qiskit.quantum_info.SparsePauliOp#coeffs "qiskit.quantum_info.SparsePauliOp.coeffs") array to [`complex`](https://docs.python.org/3/library/functions.html#complex) if all parameters are fully bound to numeric values.

### Synthesis Upgrade Notes

- The default values of the arguments `opt_a1` and `opt_a2` of [`qs_decomposition()`](/docs/api/qiskit/2.2/synthesis#qiskit.synthesis.qs_decomposition "qiskit.synthesis.qs_decomposition") are now `opt_a1 = None` and `opt_a2 = None`. The new defaults will choose the optimal value based on whether the input unitary for the `mat` argument is controlled or not to result in the minimal [`CXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CXGate "qiskit.circuit.library.CXGate") count by default. If you require the previous behavior you can explicitly call `opt_a1 = True` and `opt_a2 = True` to maintain the same behavior as previous releases.

### Transpiler Upgrade Notes

- The circuit [`PassManager`](/docs/api/qiskit/2.2/qiskit.transpiler.PassManager "qiskit.transpiler.PassManager") now always sets the properties `original_circuit_indices` and `num_input_qubits` before execution starts on individual passes. These are properties of the input circuit, which it was previously up to individual passes to set, often as a side effect of their primary purpose.

### Circuits Deprecations

- The following classes in the circuit library are deprecated as of Qiskit 2.2 and will be removed in Qiskit 3.0. They have been replaced with modern gate equivalents.

  > - [`ExactReciprocal`](/docs/api/qiskit/2.2/qiskit.circuit.library.ExactReciprocal "qiskit.circuit.library.ExactReciprocal") `-->` [`ExactReciprocalGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.ExactReciprocalGate "qiskit.circuit.library.ExactReciprocalGate")
  > - [`LinearAmplitudeFunction`](/docs/api/qiskit/2.2/qiskit.circuit.library.LinearAmplitudeFunction "qiskit.circuit.library.LinearAmplitudeFunction") `-->` [`LinearAmplitudeFunctionGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.LinearAmplitudeFunctionGate "qiskit.circuit.library.LinearAmplitudeFunctionGate")
  > - [`PhaseOracle`](/docs/api/qiskit/2.2/qiskit.circuit.library.PhaseOracle "qiskit.circuit.library.PhaseOracle") `-->` [`PhaseOracleGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PhaseOracleGate "qiskit.circuit.library.PhaseOracleGate")
  > - [`PiecewisePolynomialPauliRotations`](/docs/api/qiskit/2.2/qiskit.circuit.library.PiecewisePolynomialPauliRotations "qiskit.circuit.library.PiecewisePolynomialPauliRotations") `-->` [`PiecewisePolynomialPauliRotationsGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PiecewisePolynomialPauliRotationsGate "qiskit.circuit.library.PiecewisePolynomialPauliRotationsGate")
  > - [`QuantumVolume`](/docs/api/qiskit/2.2/qiskit.circuit.library.QuantumVolume "qiskit.circuit.library.QuantumVolume") `-->` [`quantum_volume()`](/docs/api/qiskit/2.2/qiskit.circuit.library.quantum_volume "qiskit.circuit.library.quantum_volume")

### Bug Fixes

- [`ApplyLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ApplyLayout "qiskit.transpiler.passes.ApplyLayout") will now correctly handle the case of applying a zero-qubit [`Layout`](/docs/api/qiskit/2.2/qiskit.transpiler.Layout "qiskit.transpiler.Layout"). Previously, it would claim that no layout had been set, even if the `"layout"` field of the [`PropertySet`](/docs/api/qiskit/2.2/qiskit.passmanager.PropertySet "qiskit.passmanager.PropertySet") was equal to `Layout()`.

- Fixed memory leakage issues during the creation of a [`QkOpCounts`](/docs/api/qiskit-c/2.2/qk-circuit) instance and during any calls to [`qk_opcounts_clear()`](/docs/api/qiskit-c/2.2/qk-circuit) whenever an empty instance is passed.

- Previously one could define an invalid [`PauliEvolutionGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate "qiskit.circuit.library.PauliEvolutionGate") from a list of operators, where the operators were not all defined on the same number of qubits. This is now fixed, and we now raise an error when the gate is defined:

  ```python
  from qiskit.quantum_info import Pauli, SparsePauliOp
  from qiskit.circuit.library import PauliEvolutionGate

  pauli = Pauli("XYZ")  # 3 qubits
  op = SparsePauliOp(["XYIZ"], [1])  # 4 qubits
  evo = PauliEvolutionGate([pauli, op], time=1)
  ```

- Fixed an issue in the [`VF2Layout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2Layout "qiskit.transpiler.passes.VF2Layout") transpiler pass where even with a fixed seed set the output from the pass was potentially non-deterministic; specifically if the input circuit had any active qubits that only contained single qubit operations. Fixed [#14729](https://github.com/Qiskit/qiskit/issues/14729)

- Fixed a bug in [`PassManager.run()`](/docs/api/qiskit/2.2/qiskit.transpiler.PassManager#run "qiskit.transpiler.PassManager.run") where the `callback` function was not invoked when running with multiple circuits. The callback is now correctly triggered for each pass on each circuit, including in parallel execution.

- Fixed several problems in the [`CommutativeInverseCancellation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.CommutativeInverseCancellation "qiskit.transpiler.passes.CommutativeInverseCancellation") transpiler pass. The pass now works correctly on circuits containing [`Clifford`](/docs/api/qiskit/2.2/qiskit.quantum_info.Clifford "qiskit.quantum_info.Clifford") operations, control-flow operations, and non-invertible operations such as [`Initialize`](/docs/api/qiskit/2.2/qiskit.circuit.library.Initialize "qiskit.circuit.library.Initialize").

  In addition, the pass now always performs a syntactic (non-matrix-based) check first, when identifying inverse gate pairs. If the gates are not syntactically equal, the argument `matrix_based` is set to `True`, and the operation does not act on more than `max_qubits` qubits, then a matrix-based check is also performed. This slightly improves the reduction potential of the pass.

  Fixed [#14407](https://github.com/Qiskit/qiskit/issues/14407), [#14635](https://github.com/Qiskit/qiskit/issues/14635), and [#14645](https://github.com/Qiskit/qiskit/issues/14645).

- Fixed several issues in the [`CommutativeCancellation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.CommutativeCancellation "qiskit.transpiler.passes.CommutativeCancellation") transpiler pass (and thereby in [`transpile()`](/docs/api/qiskit/2.2/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile")), where the global phase of the circuit was not updated correctly. In particular, merging an X-gate and an RX-gate introduced a phase mismatch, while removing a Pauli rotation gate with angle of the form $(2 + 4k)\pi$, $k \in \mathbb Z$ incorrectly produced a phase shift of $-1$.

- Fixed a problem in [`CommutationChecker`](/docs/api/qiskit/2.2/qiskit.circuit.CommutationChecker "qiskit.circuit.CommutationChecker"), where standard controlled gates were not handled correctly if they were controlled on something other than the all-ones state. Fixed [#14974](https://github.com/Qiskit/qiskit/issues/14974)

- Fixed a non-determinism in [`CommutativeCancellation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.CommutativeCancellation "qiskit.transpiler.passes.CommutativeCancellation"). This did not affect the order returned by [`DAGCircuit.topological_nodes()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#topological_nodes "qiskit.dagcircuit.DAGCircuit.topological_nodes") or [`topological_op_nodes()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#topological_op_nodes "qiskit.dagcircuit.DAGCircuit.topological_op_nodes"), which typically should be used when node-order determinism is important, due to their built-in canonical sorting function. However, if inspecting the nodes by arbitrary order ([`DAGCircuit.op_nodes()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#op_nodes "qiskit.dagcircuit.DAGCircuit.op_nodes")) or the edge structure ([`DAGCircuit.edges()`](/docs/api/qiskit/2.2/qiskit.dagcircuit.DAGCircuit#edges "qiskit.dagcircuit.DAGCircuit.edges")), the iteration order would be non-deterministic after a call to [`CommutativeCancellation`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.CommutativeCancellation "qiskit.transpiler.passes.CommutativeCancellation").

- Fixed a bug in [`MCXGate.control()`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate#control "qiskit.circuit.library.MCXGate.control"), where adding more controls to an open-controlled [`MCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate") did not take the `ctrl_state` of the controlled MCX gate into account, thus leading to an incorrect `ctrl_state` of the extended MCX gate. Note that the explicit MCX classes [`CXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CXGate "qiskit.circuit.library.CXGate"), [`CCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.CCXGate "qiskit.circuit.library.CCXGate"), [`C3XGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.C3XGate "qiskit.circuit.library.C3XGate"), and [`C4XGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.C4XGate "qiskit.circuit.library.C4XGate") were already handled correctly.

- Fixed the deprecation warning for Python 3.9 so that it correctly is identified as being caused by user code when importing Qiskit. Previously, it would not be identified as being caused by user code and this meant that Python’s default warning filters would not display the warning to the user.

- Fixed a bug in [`PhaseOracle`](/docs/api/qiskit/2.2/qiskit.circuit.library.PhaseOracle "qiskit.circuit.library.PhaseOracle"), [`PhaseOracleGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PhaseOracleGate "qiskit.circuit.library.PhaseOracleGate") and [`BitFlipOracleGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.BitFlipOracleGate "qiskit.circuit.library.BitFlipOracleGate") where trying to load from dimacs file raised a `TypeError`.

- Fixed a bug in the [`ElidePermutations`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.ElidePermutations "qiskit.transpiler.passes.ElidePermutations") transpiler pass, where the qubit mapping was not updated correctly in the presence of [`PermutationGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PermutationGate "qiskit.circuit.library.PermutationGate")s, leading to incorrect circuits and updates to the pass manager’s property set.

- Built-in transpiler passes that set the `final_layout` property will now correctly handle updating this field if it was already set. This can be observed as the method [`TranspileLayout.routing_permutation`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout#routing_permutation "qiskit.transpiler.TranspileLayout.routing_permutation") now returning a correct permutation after running more than one pass that sets `final_layout`.

  This did not affect any normal calls to [`transpile()`](/docs/api/qiskit/2.2/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile") or [`generate_preset_pass_manager()`](/docs/api/qiskit/2.2/qiskit.transpiler.generate_preset_pass_manager "qiskit.transpiler.generate_preset_pass_manager") using Qiskit’s built-in plugins; no pipeline constructed in this form would attempt to set `final_layout` more than once.

- Fixed a bug in the [`HighLevelSynthesis`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.HighLevelSynthesis "qiskit.transpiler.passes.HighLevelSynthesis") pass where, if the circuit contained high level objects with classical registers, these would get mapped to the relative index in the object instead of the corresponding index in the outer circuit. The classical registers are now correctly mapped to the outer circuit index.

- Fixed a bug in [`Target.instruction_supported()`](/docs/api/qiskit/2.2/qiskit.transpiler.Target#instruction_supported "qiskit.transpiler.Target.instruction_supported") where the check of instruction’s qubit order was skipped when the method was called with `operation_name` and `parameters` arguments that matched an existing instruction.

- Fixed the behavior of the `max_trials` argument for [`VF2Layout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2Layout "qiskit.transpiler.passes.VF2Layout") when set to `None` or a negative number. The pass was documented as limiting the search to being based on the size of the circuit or target if the option was set to `None` and as accepting negative values to specify an unbounded search. However in the 2.1.0 this behavior was incorrectly changed so that `None` ran an unbounded search and trying to use a negative number would raise an error. These oversights have been corrected so that the pass behaves as documented and is consistent with previous releases.

- Fixed a problem in high-level synthesis plugins [`MCXSynthesis1DirtyKG24`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesis1DirtyKG24 "qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesis1DirtyKG24") and [`MCXSynthesis2DirtyKG24`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesis2DirtyKG24 "qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesis2DirtyKG24") for [`MCXGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate"), where the plugins did not consider available clean auxiliary qubits as available dirty auxiliary qubits. In particular, the plugin [`MCXSynthesis2DirtyKG24`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesis2DirtyKG24 "qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesis2DirtyKG24") did not apply when one clean and one dirty auxiliary qubits were available.

- The [`PauliEvolutionGate.to_matrix()`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate#to_matrix "qiskit.circuit.library.PauliEvolutionGate.to_matrix") method now returns the exact matrix exponential $\exp(-it H)$, where $H$ is the `operator` and $t$ the `time` passed to the gate. This fixes an unexpected behavior, since the [`PauliEvolutionGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate "qiskit.circuit.library.PauliEvolutionGate") is documented to represent the *exact* time evolution, but previously the matrix was dependent on how the compiler approximates the time evolution. The `to_matrix` method is now consistent with the documentation.

- Fixed a performance regression when incrementally building [`ParameterExpression`](/docs/api/qiskit/2.2/qiskit.circuit.ParameterExpression "qiskit.circuit.ParameterExpression") from combining a large number of sub-expressions. Fixed [#14653](https://github.com/Qiskit/qiskit/issues/14653)

- Fixed a correctness bug when exporting circuits with delay instructions using ‘ps’ units to QASM3.

- Fixed an edge case in the display of the [`QFT`](/docs/api/qiskit/2.2/qiskit.circuit.library.QFT "qiskit.circuit.library.QFT") circuit. Previously, when [`QFT.inverse()`](/docs/api/qiskit/2.2/qiskit.circuit.library.QFT#inverse "qiskit.circuit.library.QFT.inverse") was called and then the attributes of the QFT circuit were modified, the QFT was displayed as `"IQFT_dg"`. This was incorrect, and now it correctly shows `"IQFT"`. Fixed [#14758](https://github.com/Qiskit/qiskit/issues/14758).

- Fixed a bug in the [`PauliEvolutionSynthesisRustiq`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisRustiq "qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisRustiq") plugin that produced incorrect circuits in the case that the operator of a [`PauliEvolutionGate`](/docs/api/qiskit/2.2/qiskit.circuit.library.PauliEvolutionGate "qiskit.circuit.library.PauliEvolutionGate") contains objects of type [`SparseObservable`](/docs/api/qiskit/2.2/qiskit.quantum_info.SparseObservable "qiskit.quantum_info.SparseObservable").

  For example:

  ```python
  from qiskit.circuit.library import PauliEvolutionGate
  from qiskit.quantum_info import SparseObservable, Operator
  from qiskit.transpiler.passes.synthesis.hls_plugins import PauliEvolutionSynthesisRustiq

  obs = SparseObservable.from_sparse_list([("1+XY", (0, 1, 2, 3), 1.5)], num_qubits=4)
  evo = PauliEvolutionGate(obs, 1)
  qct = PauliEvolutionSynthesisRustiq().run(evo)
  assert Operator(qct) == Operator(evo)
  ```

- Fixed an issue with the [`generate_preset_pass_manager()`](/docs/api/qiskit/2.2/qiskit.transpiler.generate_preset_pass_manager "qiskit.transpiler.generate_preset_pass_manager") function where it would incorrectly ignore the timing constraints data contained in a [`Target`](/docs/api/qiskit/2.2/qiskit.transpiler.Target "qiskit.transpiler.Target") object provided when the `backend` argument was not set. Fixed [#14329](https://github.com/Qiskit/qiskit/issues/14329)

- Fixed a bug in `ObservablesArray.coerce_observable()` where an exception that an observable was not Hermitian was over-triggered. Observables equal to `zero` are not allowed and now invoke a graceful failure.

- [`qiskit.circuit.library.quantum_volume()`](/docs/api/qiskit/2.2/qiskit.circuit.library.quantum_volume "qiskit.circuit.library.quantum_volume") was updated to handle a [`numpy.random.Generator`](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator) as input for its `seed` argument. Previously, such a generator argument would result in a `TypeError`.

- [`QuantumCircuit.compose()`](/docs/api/qiskit/2.2/qiskit.circuit.QuantumCircuit#compose "qiskit.circuit.QuantumCircuit.compose") will now correctly remap anyway variables and stretches used in [`Delay`](/docs/api/qiskit/2.2/circuit#qiskit.circuit.Delay "qiskit.circuit.Delay") instructions when the `var_remap` argument is specified.

- [`SabreLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.SabreLayout "qiskit.transpiler.passes.SabreLayout") uses a “dense subset” layout as one of its trials, following the same algorithm as [`DenseLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.DenseLayout "qiskit.transpiler.passes.DenseLayout"). Previously, however, the version used by Sabre was assigning all virtual qubits, including dummy ancillas, to a physical qubit, compromising the effectiveness of the algorithm, but not its correctness. Sabre will now only use the virtual qubits defined by the user for this initial trial, which may result in small improvements in layout selection when averaged over large classes of circuit.

- Fixed a bug in [`SparsePauliOp.simplify()`](/docs/api/qiskit/2.2/qiskit.quantum_info.SparsePauliOp#simplify "qiskit.quantum_info.SparsePauliOp.simplify") where the method removed Pauli terms based on their coefficients’ magnitudes before combining duplicates. This caused incorrect behavior in two key edge cases:

  1. When multiple identical Pauli terms had small coefficients that were individually below the simplification threshold but whose sum exceeded the threshold, those terms were incorrectly removed.
  2. When multiple identical Pauli terms had coefficients above the threshold but summed to near-zero, they were incorrectly kept.

  See [#14194](https://github.com/Qiskit/qiskit/issues/14194) for more detail.

- [`TranspileLayout.initial_index_layout()`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout#initial_index_layout "qiskit.transpiler.TranspileLayout.initial_index_layout") will now correctly handle the `filter_ancillas=True` argument if the virtual qubits in the [`initial_layout`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout#initial_layout "qiskit.transpiler.TranspileLayout.initial_layout") were not specified by the constructor in index order.

- [`VF2Layout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2Layout "qiskit.transpiler.passes.VF2Layout") and [`VF2PostLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2PostLayout "qiskit.transpiler.passes.VF2PostLayout") will now correctly include (arbitrary) layout assignments for completely idle qubits. Previously this might have been observed by calls to [`TranspileLayout.initial_index_layout()`](/docs/api/qiskit/2.2/qiskit.transpiler.TranspileLayout#initial_index_layout "qiskit.transpiler.TranspileLayout.initial_index_layout") failing after a compilation.

- Fixed an issue in the [`VF2PostLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2PostLayout "qiskit.transpiler.passes.VF2PostLayout") transpiler pass. In certain situations when the pass is being run with the argument `strict_direction=True` there was a potential runtime scaling issue when the interaction graph of the circuit contained any qubits that only had 1 qubit operations. These mapping problems result in a combinatorial complexity for scoring that would lead to the pass almost always hitting the scoring timeout and typically not improving the layout. In `strict_direction=False` mode there is an optimized search implementation for these problems, but the additional constraints for `strict_direction=True` don’t make this approach viable. Instead in these cases [`VF2PostLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.VF2PostLayout "qiskit.transpiler.passes.VF2PostLayout") will now skip the search since the layout problem isn’t viable for the pass.

### Other Notes

- The implementation of Sabre routing used by [`SabreLayout`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.SabreLayout "qiskit.transpiler.passes.SabreLayout") and [`SabreSwap`](/docs/api/qiskit/2.2/qiskit.transpiler.passes.SabreSwap "qiskit.transpiler.passes.SabreSwap") now compresses runs of nodes that will automatically become eligible for routing at the same time within its internal virtual-interaction representation. This improves the efficiency of the routing, reduces intermediate memory use, and avoids runs of 2q gates biasing the `lookahead` heuristic components.

## 2.1.0rc1

### Deprecation Notes

- Support for running Qiskit with Python 3.9 has been deprecated and will be removed in the Qiskit 2.3.0 release. The 2.3.0 is the first release after Python 3.9 goes end of life and is no longer supported. \[1] This means that starting in the 2.3.0 release you will need to upgrade the Python version you’re using to Python 3.9 or above.

  \[1] [https://devguide.python.org/versions/](https://devguide.python.org/versions/)
