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

# Qiskit SDK 2.6 release notes

## 2.6.1

### Prelude

Qiskit v2.6.1 is a patch release that includes bug fixes for issues identified since the release of v2.6.0.

### Bug Fixes

- Various C-API functions that return strings (either directly or as error messages) will no longer panic if the backing string contains interior nul bytes.

- Fixed an issue on Linux systems when using Qiskit with other Python packages that dynamically load shared libraries (such as [Qiskit Aer](https://qiskit.github.io/qiskit-aer/) or [scikit-learn](https://scikit-learn.org/stable/)) that also were using thread local storage and in some cases could fill the available static TLS space from glibc. This would result in an [`ImportError`](https://docs.python.org/3/builtins/exceptions.html#ImportError) with an error message like `cannot allocate memory in static TLS block`. This was fixed by changing how Qiskit build’s mimalloc to use a different [TLS model](https://www.akkadia.org/drepper/tls.pdf) that doesn’t use the static TLS. See [#17213](https://github.com/Qiskit/qiskit/issues/17213).

- Fixed an issue where [`CPhaseGate.power()`](/docs/api/qiskit/qiskit.circuit.library.CPhaseGate#power "qiskit.circuit.library.CPhaseGate.power"), [`CSGate.power()`](/docs/api/qiskit/qiskit.circuit.library.CSGate#power "qiskit.circuit.library.CSGate.power"), and [`CSdgGate.power()`](/docs/api/qiskit/qiskit.circuit.library.CSdgGate#power "qiskit.circuit.library.CSdgGate.power") dropped the `ctrl_state` attribute of the gate, causing open-controlled gates (`ctrl_state=0`) to lose their control state and fall back to the default control state: `1`.

  Fixed [#17222](https://github.com/Qiskit/qiskit/issues/17222).

- Fixed [`TwoQubitBasisDecomposer.decomp0()`](/docs/api/qiskit/qiskit.synthesis.TwoQubitBasisDecomposer#decomp0 "qiskit.synthesis.TwoQubitBasisDecomposer.decomp0"), [`TwoQubitBasisDecomposer.decomp1()`](/docs/api/qiskit/qiskit.synthesis.TwoQubitBasisDecomposer#decomp1 "qiskit.synthesis.TwoQubitBasisDecomposer.decomp1"), [`TwoQubitBasisDecomposer.decomp2_supercontrolled()`](/docs/api/qiskit/qiskit.synthesis.TwoQubitBasisDecomposer#decomp2_supercontrolled "qiskit.synthesis.TwoQubitBasisDecomposer.decomp2_supercontrolled"), and [`TwoQubitBasisDecomposer.decomp3_supercontrolled()`](/docs/api/qiskit/qiskit.synthesis.TwoQubitBasisDecomposer#decomp3_supercontrolled "qiskit.synthesis.TwoQubitBasisDecomposer.decomp3_supercontrolled") so they correctly accept [`TwoQubitWeylDecomposition`](/docs/api/qiskit/qiskit.synthesis.TwoQubitWeylDecomposition "qiskit.synthesis.TwoQubitWeylDecomposition") arguments.

## 2.6.0

### Prelude

Qiskit v2.6.0 is a new feature release of the Qiskit SDK.

This release introduces important new functionality into the Qiskit SDK, including the following:

- **A Multi-IR Pass Manager in C and Python:** Added a new pass manager framework which can use different Intermediate Representations (IRs) as input and outputs. This framework is exposed to Python via the [`LoweringPassManager`](/docs/api/qiskit/passmanager#qiskit.passmanager.LoweringPassManager "qiskit.passmanager.LoweringPassManager") class and to the C API too. Refer to the C API [Pass-manager infrastructure](/docs/api/qiskit-c/pass-manager#capi-pass-manager) documentation for more details on using this new pass manager from C.

- **Custom Operations in C:** Users are now able to create custom [`Operation`](/docs/api/qiskit/qiskit.circuit.Operation "qiskit.circuit.Operation") types using the C API. See the [QkCustomOp](/docs/api/qiskit-c/qk-operation#capi-operations) documentation for more details.

- **QPY 18 and C API:**

  - QPY serialization and de-serialization is now available via the C API. Users are now able to use QPY for roundtrip serialization from C as well as inter-operate with Python workflows. Please note that loading QPY from C is only supported for payloads using QPY v13 and onwards. Refer to [the QPY C API documentation](/docs/api/qiskit-c/qk-qpy#capi-qpy) for more details.
  - QPY v18 which introduces a new format version and produces payloads with smaller footprints. Refer to [the QPY Version 18 documentation](/docs/api/qiskit/qpy#qpy-version-18) for more details on the changes in the new format revision.

### C API Features

- Custom operations can now be defined via the C API using `QkCustomOp`. Any implementors should refer to the documentation defined in [QkCustomOp](/docs/api/qiskit-c/qk-operation#capi-operations) for further information.

- Add [`qk_circuit_custom_operation()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_custom_operation "qk_circuit_custom_operation") and [`qk_dag_apply_custom_operation()`](/docs/api/qiskit-c/qk-dag#qk_dag_apply_custom_operation "qk_dag_apply_custom_operation") to add custom operations defined in C to a circuit.

- Added ability to add [`Delay`](/docs/api/qiskit/circuit#qiskit.circuit.Delay "qiskit.circuit.Delay") in terms of `Dt` to a `QkCircuit` (via [`qk_circuit_delay_dt()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_delay_dt "qk_circuit_delay_dt")).

- Add [`qk_circuit_delay_unit()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_delay_unit "qk_circuit_delay_unit") to retrieve the unit type of a [`Delay`](/docs/api/qiskit/circuit#qiskit.circuit.Delay "qiskit.circuit.Delay") instruction in the C API.

- Add [`qk_param_kind()`](/docs/api/qiskit-c/qk-param#qk_param_kind "qk_param_kind") to obtain an enumeration ([`QkParamKind`](/docs/api/qiskit-c/qk-param#QkParamKind "QkParamKind")) describing the kind of any `QkParam` instance before using functions such as [`qk_param_as_real()`](/docs/api/qiskit-c/qk-param#qk_param_as_real "qk_param_as_real") or [`qk_param_as_int()`](/docs/api/qiskit-c/qk-param#qk_param_as_int "qk_param_as_int") to obtain its bound value.

- Add [`qk_param_as_int()`](/docs/api/qiskit-c/qk-param#qk_param_as_int "qk_param_as_int") to obtain the integer value of a parameter that can only be represented by an integer.

- [`qk_circuit_barrier()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_barrier "qk_circuit_barrier") can now accept a null pointer as the `qubits` argument, in which case `num_qubits` is ignored, and the barrier is applied to all qubits.

- Two new functions, [`qk_circuit_view_instruction()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_view_instruction "qk_circuit_view_instruction") and [`qk_dag_view_instruction()`](/docs/api/qiskit-c/qk-dag#qk_dag_view_instruction "qk_dag_view_instruction"), were added as mirrors to [`qk_circuit_get_instruction()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_get_instruction "qk_circuit_get_instruction") and [`qk_dag_get_instruction()`](/docs/api/qiskit-c/qk-dag#qk_dag_get_instruction "qk_dag_get_instruction"), respectively, writing out a new [`QkCircuitInstructionView`](/docs/api/qiskit-c/qk-circuit#QkCircuitInstructionView "QkCircuitInstructionView") object.

  These `view` functions produce direct views into the internal data without any allocations, which is more performant, but requires some special handling to use the non-idiomatic data formats from C; see the documentation of [`QkCircuitInstructionView`](/docs/api/qiskit-c/qk-circuit#QkCircuitInstructionView "QkCircuitInstructionView").

- Added [`qk_param_stride()`](/docs/api/qiskit-c/qk-param#qk_param_stride "qk_param_stride"), which returns the runtime size in bytes needed to offset `QkParam *` pointers that point to contiguous arrays.

- The C API now has a pass manager framework for writing and executing compiler passes. The new `QkPassManager` manages the execution; it can be populated with [`QkPass`](/docs/api/qiskit-c/pass-manager#QkPass "QkPass") objects via [`qk_passmanager_push_pass()`](/docs/api/qiskit-c/pass-manager#qk_passmanager_push_pass "qk_passmanager_push_pass") and be executed using [`qk_passmanager_run_simple()`](/docs/api/qiskit-c/pass-manager#qk_passmanager_run_simple "qk_passmanager_run_simple"). The pass manager and passes can report errors through [`QkCompilationError`](/docs/api/qiskit-c/pass-manager#QkCompilationError "QkCompilationError").

  Passes are defined through a vtable, [`QkPassVtable`](/docs/api/qiskit-c/pass-manager#QkPassVtable "QkPassVtable"), and declare their input and output IR with an [`QkIrHandle`](/docs/api/qiskit-c/pass-manager#QkIrHandle "QkIrHandle"), which can describe either a dynamically defined C IR or a built-in Qiskit IR. The pass manager uses these handles to verify the pipeline, enabling type-checked cross-language compiler pipelines.

  The functionality included in this release is limited and we expect to expand the C pass manager framework in a backward-compatible manner, for example, with additional execution modes of the pass manager, callbacks, and pass context handling.

- Added C API functions to construct n-local circuits:

  > - [`qk_circuit_library_n_local()`](/docs/api/qiskit-c/qk-circuit-library#qk_circuit_library_n_local "qk_circuit_library_n_local"): Constructs an n-local variational circuit.
  > - [`qk_circuit_library_n_local_settings_default()`](/docs/api/qiskit-c/qk-circuit-library#qk_circuit_library_n_local_settings_default "qk_circuit_library_n_local_settings_default"): Generates default options for [`qk_circuit_library_n_local()`](/docs/api/qiskit-c/qk-circuit-library#qk_circuit_library_n_local "qk_circuit_library_n_local").

  The following helper structs were also added:

  > - [`QkNLocalSettings`](/docs/api/qiskit-c/qk-circuit-library#QkNLocalSettings "QkNLocalSettings"): Holds settings needed to build the n-local circuit.
  > - [`QkEntanglementStrategy`](/docs/api/qiskit-c/qk-circuit-library#QkEntanglementStrategy "QkEntanglementStrategy"): Enum representing all the strategies that can be used for the circuit entanglement blocks.

- Added [`qk_obs_with_capacity()`](/docs/api/qiskit-c/qk-obs#qk_obs_with_capacity "qk_obs_with_capacity") for constructing empty `QkObs` instances with a pre-allocated capacity for terms.

- Added QPY serialization and deserialization to the C API. Multiple `QkCircuit` objects can now be serialized into a single QPY stream in the latest QPY version, either to a buffer with [`qk_qpy_dump_buffer()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_dump_buffer "qk_qpy_dump_buffer") or saved to a file with [`qk_qpy_dump_file()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_dump_file "qk_qpy_dump_file"). Both functions have an alternative `*_with_version` variant that allows specifying the QPY version used for serialization.

  These dump functions operate on native circuits without interacting with Python. If you’re using the C API in a Python extension you should use the Python functions: [`qpy.dump()`](/docs/api/qiskit/qpy#qiskit.qpy.dump "qiskit.qpy.dump") and [`qpy.load()`](/docs/api/qiskit/qpy#qiskit.qpy.load "qiskit.qpy.load") as the C API functions will return an error if Python is required to create or load a QPY payload from the circuit.

  All circuits in a QPY stream can be deserialized from a buffer or file with [`qk_qpy_load_buffer()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_load_buffer "qk_qpy_load_buffer") and [`qk_qpy_load_file()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_load_file "qk_qpy_load_file") (the version is handled automatically; no need for variants).

  To free the buffer returned by [`qk_qpy_dump_buffer()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_dump_buffer "qk_qpy_dump_buffer") and [`qk_qpy_dump_buffer_with_version()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_dump_buffer_with_version "qk_qpy_dump_buffer_with_version"), call [`qk_qpy_free_buffer()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_free_buffer "qk_qpy_free_buffer"). Circuit arrays returned by [`qk_qpy_load_buffer()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_load_buffer "qk_qpy_load_buffer") and [`qk_qpy_load_file()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_load_file "qk_qpy_load_file") must be released with `qk_qpy_free_circuits()`.

  Each function that can fail accepts a nullable output pointer for a diagnostic error string. When populated, the string contains details from the underlying QPY error and must be released with [`qk_str_free()`](/docs/api/qiskit-c/qk-obs#qk_str_free "qk_str_free").

  Also added [`qk_qpy_read_min_version()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_read_min_version "qk_qpy_read_min_version") and [`qk_qpy_write_min_version()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_write_min_version "qk_qpy_write_min_version"), which return the oldest QPY format versions the loaded library can read and write, respectively.

  The new functions are:

  - [`qk_qpy_dump_file()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_dump_file "qk_qpy_dump_file")
  - [`qk_qpy_dump_file_with_version()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_dump_file_with_version "qk_qpy_dump_file_with_version")
  - [`qk_qpy_load_file()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_load_file "qk_qpy_load_file")
  - [`qk_qpy_dump_buffer()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_dump_buffer "qk_qpy_dump_buffer")
  - [`qk_qpy_dump_buffer_with_version()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_dump_buffer_with_version "qk_qpy_dump_buffer_with_version")
  - [`qk_qpy_load_buffer()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_load_buffer "qk_qpy_load_buffer")
  - [`qk_qpy_free_buffer()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_free_buffer "qk_qpy_free_buffer")
  - `qk_qpy_free_circuits()`
  - [`qk_qpy_read_min_version()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_read_min_version "qk_qpy_read_min_version")
  - [`qk_qpy_write_min_version()`](/docs/api/qiskit-c/qk-qpy#qk_qpy_write_min_version "qk_qpy_write_min_version")

- The C circuit drawer now renders [`Barrier`](/docs/api/qiskit/circuit#qiskit.circuit.Barrier "qiskit.circuit.Barrier") labels, matching the behavior of the Python text drawer. The label is drawn above the top-most wire of the barrier and is truncated, with `"..."` appended, when it is longer than the configured number of characters (16 by default).

- [`QkCircuitDrawerConfig`](/docs/api/qiskit-c/qk-circuit#QkCircuitDrawerConfig "QkCircuitDrawerConfig") has a new `barrier_label_len` field, which controls the number of characters to display for barrier labels. Longer labels are truncated at that length and `"..."` is appended. Setting the field to `0` applies the default truncation length of 16 characters, so existing initializers that omit the field keep the default behavior.

### Circuits Features

- The type that backs [`QuantumCircuit._data`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#_data "qiskit.circuit.QuantumCircuit._data") is now nameable as [`qiskit.circuit.CircuitData`](/docs/api/qiskit/circuit#qiskit.circuit.CircuitData "qiskit.circuit.CircuitData"). All methods and attributes on the object are still private, regardless of their naming convention.

- A new public constructor, [`QuantumCircuit.from_circuit_data()`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#from_circuit_data "qiskit.circuit.QuantumCircuit.from_circuit_data"), allows reconstruction of a full circuit from the [`_data`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#_data "qiskit.circuit.QuantumCircuit._data") attribute.

- Conversions between [`DAGCircuit`](/docs/api/qiskit/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit") and [`QuantumCircuit`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit "qiskit.circuit.QuantumCircuit") now shallow-copy any [`metadata`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#metadata "qiskit.circuit.QuantumCircuit.metadata") if the `copy_operations=True` argument is set in [`circuit_to_dag()`](/docs/api/qiskit/converters#qiskit.converters.circuit_to_dag "qiskit.converters.circuit_to_dag"), [`dag_to_circuit()`](/docs/api/qiskit/converters#qiskit.converters.dag_to_circuit "qiskit.converters.dag_to_circuit"), [`QuantumCircuit.to_dag()`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#to_dag "qiskit.circuit.QuantumCircuit.to_dag") or [`DAGCircuit.to_circuit()`](/docs/api/qiskit/qiskit.dagcircuit.DAGCircuit#to_circuit "qiskit.dagcircuit.DAGCircuit.to_circuit"). This transitively affects compilation functions such as [`PassManager.run()`](/docs/api/qiskit/qiskit.transpiler.PassManager#run "qiskit.transpiler.PassManager.run") and [`transpile()`](/docs/api/qiskit/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile").

- Added support for passing an iterable of operation types to [`DAGCircuit.op_nodes()`](/docs/api/qiskit/qiskit.dagcircuit.DAGCircuit#op_nodes "qiskit.dagcircuit.DAGCircuit.op_nodes"), for example `dag.op_nodes(op=(Measure, Reset))`. This allows collecting multiple instruction types in a single DAG iteration.

- Updated [`QuantumCircuit.mcp()`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#mcp "qiskit.circuit.QuantumCircuit.mcp") so that it automatically selects the best decomposition technique based on the number of control qubits. This improves the performance of [`MCPhaseGate`](/docs/api/qiskit/qiskit.circuit.library.MCPhaseGate "qiskit.circuit.library.MCPhaseGate"), with circuit depth growing linearly in the number of qubits rather than quadratically as before. For gates with 2, 3, or 4 control qubits, the previous method is better in CNOT count, but for 5 or more control qubits, the new method is better.

- Improve the default CX count in the definition of [`QuantumCircuit.mcx()`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#mcx "qiskit.circuit.QuantumCircuit.mcx") and [`MCXGate`](/docs/api/qiskit/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate") with no ancilla qubits.

- Added a compact exact decomposition for a singly-controlled [`RCCXGate`](/docs/api/qiskit/qiskit.circuit.library.RCCXGate "qiskit.circuit.library.RCCXGate"). Calling [`RCCXGate.control()`](/docs/api/qiskit/qiskit.circuit.library.RCCXGate#control "qiskit.circuit.library.RCCXGate.control") with one control now uses [`RC3XGate`](/docs/api/qiskit/qiskit.circuit.library.RC3XGate "qiskit.circuit.library.RC3XGate") and [`CSdgGate`](/docs/api/qiskit/qiskit.circuit.library.CSdgGate "qiskit.circuit.library.CSdgGate"), requiring 8 CX gates and 11 T or Tdg gates without ancillas. This also reduces the synthesis cost of higher-level controlled circuits containing RCCX gates, such as controlled modular adders.

- Added [`ParameterExpression.structurally_equal()`](/docs/api/qiskit/qiskit.circuit.ParameterExpression#structurally_equal "qiskit.circuit.ParameterExpression.structurally_equal"), which can be used to compare whether two expressions have equal internal structures. This is mostly useful for testing Qiskit itself.

- Added a `label` argument to single-gate instruction methods on [`QuantumCircuit`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit "qiskit.circuit.QuantumCircuit") that previously did not expose one. This lets labels be set directly when adding these gates to a circuit using a method call (e.g. `circuit.cp(..., label=...)`).

- Added a `label` argument to the [`RVGate`](/docs/api/qiskit/qiskit.circuit.library.RVGate "qiskit.circuit.library.RVGate") constructor.

- Added a new [`ParameterExpression.simplify()`](/docs/api/qiskit/qiskit.circuit.ParameterExpression#simplify "qiskit.circuit.ParameterExpression.simplify") method that returns an algebraically simplified copy of the expression using the native symbolic engine. It collapses cancelling terms such as `a + b - a - b` to zero.

### OpenQASM Features

- The OpenQASM 2 importer ([`qasm2.load()`](/docs/api/qiskit/qasm2#qiskit.qasm2.load "qiskit.qasm2.load") and [`qasm2.loads()`](/docs/api/qiskit/qasm2#qiskit.qasm2.loads "qiskit.qasm2.loads")) can now handle arbitrarily deep classical expressions. They no longer issue [`RecursionError`](https://docs.python.org/3/builtins/exceptions.html#RecursionError) based on the system recursion limit ([`sys.getrecursionlimit()`](https://docs.python.org/3/library/sys.html#sys.getrecursionlimit)).

### QPY Features

- QPY format version 18 significantly decreases the data size for most [`ClassicalRegister`](/docs/api/qiskit/circuit#qiskit.circuit.ClassicalRegister "qiskit.circuit.ClassicalRegister") and [`QuantumRegister`](/docs/api/qiskit/circuit#qiskit.circuit.QuantumRegister "qiskit.circuit.QuantumRegister") objects in a [`QuantumCircuit`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit "qiskit.circuit.QuantumCircuit"). The constant overhead for registers has increased by 1 byte, but then in the worst case for each bit contained in the register the overhead has decreased from 8 bytes per bit in the register to 4 bytes per bit in the register. In the common case where the registers are added to the circuit contiguously the space requirement goes from 8 bytes per bit to 4 bytes total to represent the register.

### Quantum Information Features

- The [`SparseObservable`](/docs/api/qiskit/qiskit.quantum_info.SparseObservable "qiskit.quantum_info.SparseObservable") has a new method [`to_matrix()`](/docs/api/qiskit/qiskit.quantum_info.SparseObservable#to_matrix "qiskit.quantum_info.SparseObservable.to_matrix"). This method returns the dense matrix representation of the observable. Its reduced time complexity is $O(4^n)$ where $n$ is the number of qubits. See the Python API docs for details.

### Synthesis Features

- Added [`synth_mcx_n_dirty_m15()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_n_dirty_m15 "qiskit.synthesis.synth_mcx_n_dirty_m15"), which implements Maslov’s Clifford+T-friendly dirty-ancilla MCX construction. It uses one ancilla for three or four controls and $\lceil(k - 2) / 2\rceil$ ancillas for larger gates.

- The clean-ancilla [`synth_mcx_n_clean_m15()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_n_clean_m15 "qiskit.synthesis.synth_mcx_n_clean_m15") implementation now also uses $\lceil(k - 2) / 2\rceil$ ancillas instead of $k - 2$, without changing its T or CX counts. Thus, [`QuantumCircuit.mcry()`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#mcry "qiskit.circuit.QuantumCircuit.mcry") with `mode=None` can automatically select `basic` mode when at least $\lceil(k - 2) / 2\rceil$ clean ancillas are available.

- Added a new plugin, [`PauliEvolutionSynthesisMcts`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisMcts "qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisMcts"), for synthesizing [`PauliEvolutionGate`](/docs/api/qiskit/qiskit.circuit.library.PauliEvolutionGate "qiskit.circuit.library.PauliEvolutionGate") objects. The implementation combines ideas from the papers *MonteQ: A Monte Carlo Tree Search Based Quantum Circuit Synthesis Framework* by Machiya et al. ([https://arxiv.org/abs/2604.19029](https://arxiv.org/abs/2604.19029)) and *Faster and shorter synthesis of Hamiltonian simulation circuits* by de Brugière et al. ([https://arxiv.org/abs/2404.03280](https://arxiv.org/abs/2404.03280)).

  Compared to the default plugin, [`PauliEvolutionSynthesisDefault`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisDefault "qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisDefault"), [`PauliEvolutionSynthesisMcts`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisMcts "qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisMcts") typically requires more runtime but often produces higher-quality circuits. It is also significantly faster than [`PauliEvolutionSynthesisRustiq`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisRustiq "qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisRustiq") while generally achieving better synthesis results.

  The quality of the generated circuits can be further improved by increasing the `num_simulations` option, at the cost of additional runtime. This overhead can be partially mitigated by executing simulations in parallel.

- Added three synthesis functions for multi-controlled phase gates. [`synth_mcp_noaux_v24()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcp_noaux_v24 "qiskit.synthesis.synth_mcp_noaux_v24") uses the newer no-auxiliary decomposition based on multi-controlled RZ gates, and is the better choice for up to 4 control qubits. [`synth_mcp_noaux_sp22()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcp_noaux_sp22 "qiskit.synthesis.synth_mcp_noaux_sp22") implements the linear-depth strategy from da Silva et al. and is used for 5 or more control qubits. [`synth_mcp_noaux_default()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcp_noaux_default "qiskit.synthesis.synth_mcp_noaux_default") is a dispatcher that selects between these two methods according to the number of control qubits.

- Added a synthesis function for multi-controlled X gates with no ancilla qubits, [`synth_mcx_noaux_sp22()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_noaux_sp22 "qiskit.synthesis.synth_mcx_noaux_sp22") that implements the linear-depth strategy from da Silva et al. This method provides better CX counts than [`synth_mcx_noaux_v24()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_noaux_v24 "qiskit.synthesis.synth_mcx_noaux_v24"). Note that although this synthesis method grows quadratically in the number of controls, while the method in [`synth_mcx_noaux_hp24()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_noaux_hp24 "qiskit.synthesis.synth_mcx_noaux_hp24") grows linearly in the number of controls, it still yields better CX counts where $n \leq 32$.

### Transpiler Features

- Added an `approximation_degree` parameter to the [`CommutativeCancellation`](/docs/api/qiskit/qiskit.transpiler.passes.CommutativeCancellation "qiskit.transpiler.passes.CommutativeCancellation") transpiler pass. The parameter accepts a floating-point value between `0` and `1` (with a default `1.0`). This parameter is forwarded to the underlying commutation analysis for identifying gates that can be cancelled. The preset pass managers pass `pass_manager_config.approximation_degree` to [`CommutativeCancellation`](/docs/api/qiskit/qiskit.transpiler.passes.CommutativeCancellation "qiskit.transpiler.passes.CommutativeCancellation"), using `1.0` when the config value is `None`.

- Added the `mcx.n_dirty_m15` high-level synthesis plugin. The default MCX synthesis plugin selects it for T-count optimization with three or more controls, and for two-qubit-count optimization with four or more controls, when enough dirty ancillas are available and no higher-priority clean-ancilla method applies. It can also be selected explicitly using [`HLSConfig`](/docs/api/qiskit/qiskit.transpiler.passes.HLSConfig "qiskit.transpiler.passes.HLSConfig"), for example as `HLSConfig(mcx=["n_dirty_m15"])`. The plugin requires $\lceil(k - 2) / 2\rceil$ clean or dirty ancillas for $k \geq 4$, and one ancilla for $k = 3$.

- Added a new high-level synthesis plugin [`MCXSynthesisNoAuxSP22`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesisNoAuxSP22 "qiskit.transpiler.passes.synthesis.hls_plugins.MCXSynthesisNoAuxSP22") for the synthesis of [`MCXGate`](/docs/api/qiskit/qiskit.circuit.library.MCXGate "qiskit.circuit.library.MCXGate") with no ancilla qubits.

- Added a new `optimization_level` argument to the [`HighLevelSynthesis`](/docs/api/qiskit/qiskit.transpiler.passes.HighLevelSynthesis "qiskit.transpiler.passes.HighLevelSynthesis") transpiler pass. This allows the pass to select synthesis methods that can produce more optimized circuits at the expense of increased runtime.

- Added the [`PauliEvolutionSynthesisMcts`](/docs/api/qiskit/qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisMcts "qiskit.transpiler.passes.synthesis.hls_plugins.PauliEvolutionSynthesisMcts") plugin to the default synthesis plugin for [`PauliEvolutionGate`](/docs/api/qiskit/qiskit.circuit.library.PauliEvolutionGate "qiskit.circuit.library.PauliEvolutionGate"). The plugin may be selected when `optimization_level >= 2` and the target has all-to-all connectivity.

- Added a new method [`SparseObservable.contains_projectors()`](/docs/api/qiskit/qiskit.quantum_info.SparseObservable#contains_projectors "qiskit.quantum_info.SparseObservable.contains_projectors") that returns whether the observable contains any projector terms.

- [`transpile()`](/docs/api/qiskit/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile") now accepts a [`Target`](/docs/api/qiskit/qiskit.transpiler.Target "qiskit.transpiler.Target") instance as the second positional argument (the `backend` parameter). When a [`Target`](/docs/api/qiskit/qiskit.transpiler.Target "qiskit.transpiler.Target") is passed this way, it is treated as if it had been passed via the `target` keyword argument, consistent with the existing behaviour of [`generate_preset_pass_manager()`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager "qiskit.transpiler.generate_preset_pass_manager"). This allows users to write:

  ```python
  tqc = transpile(circuit, target)
  ```

  instead of:

  ```python
  tqc = transpile(circuit, target=target)
  ```

  A [`TypeError`](https://docs.python.org/3/builtins/exceptions.html#TypeError) is raised if a [`Target`](/docs/api/qiskit/qiskit.transpiler.Target "qiskit.transpiler.Target") is passed positionally and `target` is also specified as a keyword argument. Fixed [#15066](https://github.com/Qiskit/qiskit/issues/15066).

### Visualization Features

- `pi_check` and circuit visualization now print rotation angles as π fractions with higher integers, up to 100 (for example `3π/35` or `17π` instead of decimal approximations).

  See [#16356](https://github.com/Qiskit/qiskit/issues/16356).

### C API Upgrade Notes

- Added variants [`QkDelayUnit_DT`](/docs/api/qiskit-c/qk-circuit#QkDelayUnit_DT "QkDelayUnit_DT"), [`QkDelayUnit_EXPR`](/docs/api/qiskit-c/qk-circuit#QkDelayUnit_EXPR "QkDelayUnit_EXPR"), and [`QkDelayUnit_Unknown`](/docs/api/qiskit-c/qk-circuit#QkDelayUnit_Unknown "QkDelayUnit_Unknown") to the [`QkDelayUnit`](/docs/api/qiskit-c/qk-circuit#QkDelayUnit "QkDelayUnit") enumeration. The C compiler may warn you about any switch statement that uses `QkDelayUnit` and misses the cases for the new variants.

- When adding a delay to a `QkCircuit` using [`qk_circuit_delay()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_delay "qk_circuit_delay") with units of [`QkDelayUnit_DT`](/docs/api/qiskit-c/qk-circuit#QkDelayUnit_DT "QkDelayUnit_DT"), [`QkDelayUnit_EXPR`](/docs/api/qiskit-c/qk-circuit#QkDelayUnit_EXPR "QkDelayUnit_EXPR"), or [`QkDelayUnit_Unknown`](/docs/api/qiskit-c/qk-circuit#QkDelayUnit_Unknown "QkDelayUnit_Unknown"), the operation will fail with an exit code. For more detail check the updated documentation for [`qk_circuit_delay()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_delay "qk_circuit_delay").

### Circuits Upgrade Notes

- The [`Delay`](/docs/api/qiskit/circuit#qiskit.circuit.Delay "qiskit.circuit.Delay") instruction in circuits now has an upper bound of `2**63 - 1` on `dt` durations. This is a consequence of the backing data model moving to Rust.

- The metadata attributes of [`DAGCircuit.metadata`](/docs/api/qiskit/qiskit.dagcircuit.DAGCircuit#metadata "qiskit.dagcircuit.DAGCircuit.metadata") and [`DAGCircuit.name`](/docs/api/qiskit/qiskit.dagcircuit.DAGCircuit#name "qiskit.dagcircuit.DAGCircuit.name") are no longer guaranteed to be preserved for any nested instance of [`ControlFlowOp`](/docs/api/qiskit/qiskit.circuit.ControlFlowOp "qiskit.circuit.ControlFlowOp") when they contain circuit blocks of type [`DAGCircuit`](/docs/api/qiskit/qiskit.dagcircuit.DAGCircuit "qiskit.dagcircuit.DAGCircuit"). This behavior was never supported/documented and therefore was never meant to be used in this context.

### OpenQASM Upgrade Notes

- OpenQASM 2 `gate`-body expressions are now evaluated in Rust. Real-valued expressions give the same results as before, but the exceptions raised for mathematically invalid ones have changed type: `sqrt`/`ln` of a non-positive argument, `^` with a negative base and non-integer exponent, and division by zero now all raise [`QASM2ParseError`](/docs/api/qiskit/qasm2#qiskit.qasm2.QASM2ParseError "qiskit.qasm2.QASM2ParseError"), where they previously raised [`ValueError`](https://docs.python.org/3/builtins/exceptions.html#ValueError), `CircuitError` and [`ZeroDivisionError`](https://docs.python.org/3/builtins/exceptions.html#ZeroDivisionError) respectively. They are still raised lazily, when the gate’s [`definition`](/docs/api/qiskit/qiskit.circuit.Gate#definition "qiskit.circuit.Gate.definition") is first built.

### QPY Upgrade Notes

- Added a new QPY format version, 18, which is now used by default in [`qpy.dump()`](/docs/api/qiskit/qpy#qiskit.qpy.dump "qiskit.qpy.dump"). If needed, users can specify a previous QPY format version by specifying the `version` argument of the on [`qpy.dump()`](/docs/api/qiskit/qpy#qiskit.qpy.dump "qiskit.qpy.dump"). For more information about the format changes see the [QPY Version 18 docs](/docs/api/qiskit/qpy#qpy-version-18).

### Miscellaneous Upgrade Notes

- The use of [`multiprocessing`](https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing) with [`parallel_map()`](/docs/api/qiskit/utils#qiskit.utils.parallel_map "qiskit.utils.parallel_map") to run Python code in parallel on Linux has been disabled by default. This also changes the default multiprocessing behavior for functions that internally use [`parallel_map()`](/docs/api/qiskit/utils#qiskit.utils.parallel_map "qiskit.utils.parallel_map") such as [`transpile()`](/docs/api/qiskit/compiler#qiskit.compiler.transpile "qiskit.compiler.transpile") and [`PassManager.run()`](/docs/api/qiskit/qiskit.transpiler.PassManager#run "qiskit.transpiler.PassManager.run"). In previous releases on Linux systems it would default to running in parallel; however, this has proven to be unreliable especially when mixing threading with multiprocessing. This could result in deadlocks when downstream provider packages, such as `qiskit-ibm-runtime`, would use async Python. In general the importance of leveraging multiprocessing for performance has significantly diminished since Qiskit 1.0 as more of the library has enabled parallelism via Rust and multithreading which was already mutually exclusive with Python multiprocessing. If you would like to continue to use multiprocessing with [`parallel_map()`](/docs/api/qiskit/utils#qiskit.utils.parallel_map "qiskit.utils.parallel_map") or other Qiskit functions using it internally you can explicitly opt-in to enable multiprocessing. To explicitly enable multiprocessing on Linux (or any platform) you can either set an explicit start method to `"fork"` or `"forkserver"` using [`multiprocessing.set_start_method()`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.set_start_method) (explicitly setting `"spawn"` still disables multiprocessing by default because of the extra overhead and complexities associated with it and you’ll need to enable multiprocessing with spawn using the other two options), set the environment variable `QISKIT_PARALLEL=TRUE`, or set `parallel` to `True` in your [user configuration file](/docs/guides/configure-qiskit-local#user-configuration-file).

### Build System Changes

- The minimum version of the build dependency `setuptools-rust` was bumped to 1.13, to use the new `Extension(generated_files=...)` argument.

- The minimum supported Rust version (MSRV) to build Qiskit from source is now 1.89.

- [`SparsePauliOp.simplify()`](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp#simplify "qiskit.quantum_info.SparsePauliOp.simplify") no longer requires the optional `sympy` dependency when simplifying operators with [`ParameterExpression`](/docs/api/qiskit/qiskit.circuit.ParameterExpression "qiskit.circuit.ParameterExpression") coefficients. It instead relies on Qiskit’s internal symbolic engine.

### Bug Fixes

- Fixed [`CommutativeCancellation`](/docs/api/qiskit/qiskit.transpiler.passes.CommutativeCancellation "qiskit.transpiler.passes.CommutativeCancellation") incorrectly shifting the global phase by $-\pi$ when accumulating a $2\pi$ rotation using a [`PhaseGate`](/docs/api/qiskit/qiskit.circuit.library.PhaseGate "qiskit.circuit.library.PhaseGate") or [`U1Gate`](/docs/api/qiskit/qiskit.circuit.library.U1Gate "qiskit.circuit.library.U1Gate"). Fixed [#16377](https://github.com/Qiskit/qiskit/issues/16377).

- Fixed [`Initialize.gates_to_uncompute()`](/docs/api/qiskit/qiskit.circuit.library.Initialize#gates_to_uncompute "qiskit.circuit.library.Initialize.gates_to_uncompute") to return a circuit with the correct number of qubits, when the gate was constructed using an integer form (e.g. `Initialize(1, num_qubits=2)`). Fixed [#16413](https://github.com/Qiskit/qiskit/issues/16413).

- Fixed `qasm3.dump_experimental()` and `dumps_experimental()` incorrectly outputting a `us` suffix for delays specified in `ms`.

- Fixed the conversion to `ns` in `qasm3.dump_experimental()` and `dumps_experimental()` when outputting delays specified in `ps`.

- [`qk_control_flow_instruction_free()`](/docs/api/qiskit-c/qk-circuit#qk_control_flow_instruction_free "qk_control_flow_instruction_free") now safely accepts null pointers, consistent with the rest of the C API. See [#17049](https://github.com/Qiskit/qiskit/issues/17049).

- Fixed a bug in [`CommutationChecker`](/docs/api/qiskit/qiskit.circuit.CommutationChecker "qiskit.circuit.CommutationChecker") when checking commutativity of parameterized gates, such as [`RXGate`](/docs/api/qiskit/qiskit.circuit.library.RXGate "qiskit.circuit.library.RXGate"), when the `gates` argument is specified. Fixed [#16407](https://github.com/Qiskit/qiskit-terra/pull/16407).

- Fixed a bug in [`CommutationChecker`](/docs/api/qiskit/qiskit.circuit.CommutationChecker "qiskit.circuit.CommutationChecker") where passing an empty `gates` set now returns `False` instead of behaving like no filter was specified.

- The `qargs` parameter is now correctly marked as `const` (`const uint32_t *`) in both [`qk_target_entry_add_property()`](/docs/api/qiskit-c/qk-target-entry#qk_target_entry_add_property "qk_target_entry_add_property") and [`qk_target_update_property()`](/docs/api/qiskit-c/qk-target#qk_target_update_property "qk_target_update_property").

- [`CouplingMap`](/docs/api/qiskit/qiskit.transpiler.CouplingMap "qiskit.transpiler.CouplingMap") no longer stores parallel edges. A coupling given more than once, whether to the constructor or to [`add_edge()`](/docs/api/qiskit/qiskit.transpiler.CouplingMap#add_edge "qiskit.transpiler.CouplingMap.add_edge"), now collapses onto the existing edge instead of being stored twice. Fixed [#16987](https://github.com/Qiskit/qiskit/issues/16987).

- Fixed a bug where [`CouplingMap.is_symmetric`](/docs/api/qiskit/qiskit.transpiler.CouplingMap#is_symmetric "qiskit.transpiler.CouplingMap.is_symmetric") could falsely report `True` when an edge was duplicated.

- Fixed a bug in [`Optimize1qGatesDecomposition`](/docs/api/qiskit/qiskit.transpiler.passes.Optimize1qGatesDecomposition "qiskit.transpiler.passes.Optimize1qGatesDecomposition") where the choice among the possible Euler bases for a resynthesized run ignored the error rates of the `target` and was made on gate count alone, with ties broken by an internal fixed ordering. The pass now selects the candidate decomposition with the lowest total error according to the `target`, as it did before the pass was ported to Rust. When no `target` is given (or it has no error rates), the selection still minimizes the gate count. Fixed [#16460](https://github.com/Qiskit/qiskit/issues/16460).

- [`BitArray.from_counts()`](/docs/api/qiskit/qiskit.primitives.BitArray#from_counts "qiskit.primitives.BitArray.from_counts") and [`BitArray.from_samples()`](/docs/api/qiskit/qiskit.primitives.BitArray#from_samples "qiskit.primitives.BitArray.from_samples") now raise a [`ValueError`](https://docs.python.org/3/builtins/exceptions.html#ValueError) with a descriptive message, instead of an obscure [`OverflowError`](https://docs.python.org/3/builtins/exceptions.html#OverflowError) (`int too big to convert`), when a value does not fit in the requested `num_bits`.

- Fixed a deadlock in [`CommutationAnalysis`](/docs/api/qiskit/qiskit.transpiler.passes.CommutationAnalysis "qiskit.transpiler.passes.CommutationAnalysis") and [`CommutativeCancellation`](/docs/api/qiskit/qiskit.transpiler.passes.CommutativeCancellation "qiskit.transpiler.passes.CommutativeCancellation") when running multithreaded and the commutation of custom Python-defined gates had to be computed from their matrices. Fixed [#16937](https://github.com/Qiskit/qiskit/issues/16937).

- Fixed parameter loss in `Commuting2qBlock` where the `params` attribute was hardcoded to an empty list, causing all parameters from input parametric gates to be lost. The fix properly extracts and preserves parameters from gate operations, including those in [`ParameterExpression`](/docs/api/qiskit/qiskit.circuit.ParameterExpression "qiskit.circuit.ParameterExpression") objects. Fixed [#16456](https://github.com/Qiskit/qiskit/issues/16456).

- Fixed an inconsistency in [`ConsolidateBlocks`](/docs/api/qiskit/qiskit.transpiler.passes.ConsolidateBlocks "qiskit.transpiler.passes.ConsolidateBlocks"), which removed identity-equivalent sequences differently from how [`RemoveIdentityEquivalent`](/docs/api/qiskit/qiskit.transpiler.passes.RemoveIdentityEquivalent "qiskit.transpiler.passes.RemoveIdentityEquivalent") and Qiskit’s other transpiler passes do. This has been fixed and [`ConsolidateBlocks`](/docs/api/qiskit/qiskit.transpiler.passes.ConsolidateBlocks "qiskit.transpiler.passes.ConsolidateBlocks") now behaves consistently by using the average gate fidelity to check whether a sequence is close to the identity. This implies that sequences that are equivalent to the identity up to global phase are now also being removed.

- Fixed [`ConsolidateBlocks`](/docs/api/qiskit/qiskit.transpiler.passes.ConsolidateBlocks "qiskit.transpiler.passes.ConsolidateBlocks") incorrectly removing non-identity gates wider than 2 qubits with two unit roots present at the beginning of their main diagonal. Fixed [#16852](https://github.com/Qiskit/qiskit/issues/16852).

- [`UnitarySynthesis`](/docs/api/qiskit/qiskit.transpiler.passes.UnitarySynthesis "qiskit.transpiler.passes.UnitarySynthesis") no longer interprets an empty basis as a Clifford+T-only basis. In particular, unitaries are now left unchanged when no basis or target is supplied. Fixes [#16688](https://github.com/Qiskit/qiskit/issues/16688).

- Fixed [`ParameterExpression`](/docs/api/qiskit/qiskit.circuit.ParameterExpression "qiskit.circuit.ParameterExpression") equality so that mathematically equivalent expressions built via division and negative exponentiation (for example, `1 / x` and `x ** -1`) now compare equal. Previously these produced structurally different expression trees and were treated as unequal even though they represent the same value. Fixed [#16840](https://github.com/Qiskit/qiskit/issues/16840).

- [`OneQubitEulerDecomposer`](/docs/api/qiskit/qiskit.synthesis.OneQubitEulerDecomposer "qiskit.synthesis.OneQubitEulerDecomposer") with the `"U"` or `"U3"` basis no longer emits a one-qubit gate that is equal to the identity. When the rotation angle is zero the gate only depends on `phi + lam`, but the two angles were checked separately, so a case like `U(0, -pi, -pi)` was not recognised as an identity. This also removes the redundant one-qubit gates that [`TwoQubitBasisDecomposer`](/docs/api/qiskit/qiskit.synthesis.TwoQubitBasisDecomposer "qiskit.synthesis.TwoQubitBasisDecomposer") produced with those bases, for example when decomposing [`CXGate`](/docs/api/qiskit/qiskit.circuit.library.CXGate "qiskit.circuit.library.CXGate") in the `CX` basis. Fixes [#9315](https://github.com/Qiskit/qiskit/issues/9315).

- Fixed an issue with [`qpy.load()`](/docs/api/qiskit/qpy#qiskit.qpy.load "qiskit.qpy.load") not respecting the `min_qpy_version` [user config file](/docs/guides/configure-qiskit-local) option if the specified version was > 13.

- Fixed an issue with the [`qpy.dump()`](/docs/api/qiskit/qpy#qiskit.qpy.dump "qiskit.qpy.dump") function where in several cases it would previously crash the process if the payload specified it needed more memory than was available. For several of the cases fixed it will now raise a [`QpyError`](/docs/api/qiskit/qpy#qiskit.qpy.QpyError "qiskit.qpy.QpyError") which can be caught and handled. However, in general QPY deserialization is not safe against resource exhaustion and running it may still cause an OOM failure that results in a hard process crash either from the operating system or the allocator. Fixes [#16898](https://github.com/Qiskit/qiskit/issues/16898).

- Fixed a bug in [`OptimizeSwapBeforeMeasure`](/docs/api/qiskit/qiskit.transpiler.passes.OptimizeSwapBeforeMeasure "qiskit.transpiler.passes.OptimizeSwapBeforeMeasure") that caused it to retarget measurements to the wrong qubits when loose qubits preceded the measured qubit. Fixes [#16874](https://github.com/Qiskit/qiskit/issues/16874).

- Fixed an issue in [`qpy.load()`](/docs/api/qiskit/qpy#qiskit.qpy.load "qiskit.qpy.load") where it would potentially panic when parsing a malformed payload that contained register bit indices not defined in the circuit. This will now properly return a [`QpyError`](/docs/api/qiskit/qpy#qiskit.qpy.QpyError "qiskit.qpy.QpyError") instead.

- Fixed a bug in QPY serialization where [`ParameterExpression`](/docs/api/qiskit/qiskit.circuit.ParameterExpression "qiskit.circuit.ParameterExpression") objects containing expressions that can be evaluated to concrete values were not being deserialized correctly, resulting in a crash. Fixed [#17164](https://github.com/Qiskit/qiskit/issues/17164).

- Fixed an issue in [`qasm3.dumps()`](/docs/api/qiskit/qasm3#qiskit.qasm3.dumps "qiskit.qasm3.dumps") where Qiskit objects (registers, parameters, gates) whose names collide with OpenQASM 3 built-in constants (`pi`, `tau`, `euler` and their Unicode letter aliases `π`, `τ`) were exported without renaming. The resulting programs could not be re-parsed with [`qasm3.loads()`](/docs/api/qiskit/qasm3#qiskit.qasm3.loads "qiskit.qasm3.loads") because the names collided with the predefined symbols in the OpenQASM 3 global scope. These names are now escaped using the same mechanism that already handles reserved keywords (for example, a [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter "qiskit.circuit.Parameter") named `pi` is exported as `pi_0`). See [#16169](https://github.com/Qiskit/qiskit/issues/16169).

- Fixed a bug with the QPY serialization and deserialization of ancilla registers that made them load as non-ancilla registers. Fixed [#11619](https://github.com/Qiskit/qiskit/issues/11619).

- Fixed a bug with the QPY serialization and deserialization of instructions containing [`SparseObservable`](/docs/api/qiskit/qiskit.quantum_info.SparseObservable "qiskit.quantum_info.SparseObservable") data. Fixed [#16722](https://github.com/Qiskit/qiskit/issues/16722).

- Fixed a panic in [`qs_decomposition()`](/docs/api/qiskit/synthesis#qiskit.synthesis.qs_decomposition "qiskit.synthesis.qs_decomposition") (and therefore in [`UnitaryGate.definition`](/docs/api/qiskit/qiskit.circuit.library.UnitaryGate#definition "qiskit.circuit.library.UnitaryGate.definition")) when called on a $1 \times 1$ unitary, that is, a unitary acting on zero qubits. The function now returns a zero-qubit [`QuantumCircuit`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit "qiskit.circuit.QuantumCircuit") whose global phase matches the phase of the input matrix. Fixed [#17036](https://github.com/Qiskit/qiskit/issues/17036).

- Fixed an issue where drawing an empty circuit with no qubits and no classical bits using the C circuit drawer (e.g. via [`qk_circuit_draw()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_draw "qk_circuit_draw")) caused a panic. Fixes [#16723](https://github.com/Qiskit/qiskit/issues/16723).

- Fixed [`sampled_expectation_value()`](/docs/api/qiskit/result#qiskit.result.sampled_expectation_value "qiskit.result.sampled_expectation_value") silently dropping the imaginary component of expectation values when the operator has complex coefficients. The function now returns `complex` values when the input coefficients are complex, and `float` values otherwise. Fixed [#11393](https://github.com/Qiskit/qiskit/issues/11393).

- Fix a correctness bug in [`TwoQubitBasisDecomposer`](/docs/api/qiskit/qiskit.synthesis.TwoQubitBasisDecomposer "qiskit.synthesis.TwoQubitBasisDecomposer") that provided faulty synthesis of certain unitary matrices U near the 2-CX / 3-CX boundary or where the U\[0]\[0] element was 0.

  Fixed [#17057](https://github.com/Qiskit/qiskit/issues/17057).

- Fixed a bug in [`synth_cnot_phase_aam()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_cnot_phase_aam "qiskit.synthesis.synth_cnot_phase_aam") where the angles were reduced modulo $\pi$ instead of $2 * \pi$.

- Fixed a stack overflow when destructing very deeply nested trees of [`ParameterExpression`](/docs/api/qiskit/qiskit.circuit.ParameterExpression "qiskit.circuit.ParameterExpression").

- [`PassManager.run()`](/docs/api/qiskit/qiskit.transpiler.PassManager#run "qiskit.transpiler.PassManager.run") no longer clobbers the `original_qubit_indices` or `num_input_qubits` keys if they are set in a given `property_set` argument. See [#8622](https://github.com/Qiskit/qiskit/issues/8622).

### Performance Improvements

- [`qk_circuit_barrier()`](/docs/api/qiskit-c/qk-circuit#qk_circuit_barrier "qk_circuit_barrier") no longer re-allocates a temporary buffer to view the `qubits` array.

- Improves runtime performance of the [`add_register()`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit#add_register "qiskit.circuit.QuantumCircuit.add_register") method on [`QuantumCircuit`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit "qiskit.circuit.QuantumCircuit"). Consequently, this change improves performance when creating [`QuantumCircuit`](/docs/api/qiskit/qiskit.circuit.QuantumCircuit "qiskit.circuit.QuantumCircuit") as well. Generally, the time complexity of checking register name presence was reduced to $O(1)$ from $O(n)$. This was achieved by removing redundant error checking.

- Improved the runtime performance of [`synth_qft_full()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_qft_full "qiskit.synthesis.synth_qft_full") by migrating the implementation to Rust. Benchmarks show speedups ranging from \~9x at 5 qubits to \~30x at 200 qubits, and \~11x at 1000 qubits. See [#16789](https://github.com/Qiskit/qiskit/pull/16789).

- Ported [`synth_cnot_phase_aam()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_cnot_phase_aam "qiskit.synthesis.synth_cnot_phase_aam") to Rust. The new implementation is about 850x faster than the previous Python implementation when synthesizing a parity network with 120 terms on 150 qubits. See [#12937](https://github.com/Qiskit/qiskit/pull/12937) for more details.

- [`Pauli.evolve()`](/docs/api/qiskit/qiskit.quantum_info.Pauli#evolve "qiskit.quantum_info.Pauli.evolve") and [`PauliList.evolve()`](/docs/api/qiskit/qiskit.quantum_info.PauliList#evolve "qiskit.quantum_info.PauliList.evolve") are faster in many cases where `other` is a [`Clifford`](/docs/api/qiskit/qiskit.quantum_info.Clifford "qiskit.quantum_info.Clifford") and `frame` is `'h'` (Heisenberg).

- The methods [`Pauli.evolve()`](/docs/api/qiskit/qiskit.quantum_info.Pauli#evolve "qiskit.quantum_info.Pauli.evolve") and [`PauliList.evolve()`](/docs/api/qiskit/qiskit.quantum_info.PauliList#evolve "qiskit.quantum_info.PauliList.evolve") are now significantly faster at Schrödinger-frame evolution by a [`Clifford`](/docs/api/qiskit/qiskit.quantum_info.Clifford "qiskit.quantum_info.Clifford") when the Paulis have few non-identity terms. See [#16835](https://github.com/Qiskit/qiskit/pull/16835).

- QPY version 18 now stores each [`ParameterVector`](/docs/api/qiskit/qiskit.circuit.ParameterVector "qiskit.circuit.ParameterVector") once per circuit payload, in a new `PARAMETER_VECTOR_TABLE`. QPY now avoids repeating the vector’s name and size for each element, and instead refers to each by index. An element now occupies 10 bytes instead of 34 plus the length of the vector’s name. For example: a circuit using a 100-element vector is now around 29% smaller.

- QPY version 18 narrows the bit-term elements of the `SPARSE_OBSERVABLE` payload from `uint16_t` to `uint8_t`, reducing the representation for [`SparseObservable`](/docs/api/qiskit/qiskit.quantum_info.SparseObservable "qiskit.quantum_info.SparseObservable") instances in QPY by 2 bytes per term in the observable.

- Improved the performance of compilation into Clifford+T basis sets (for example, using [`generate_preset_clifford_t_pass_manager()`](/docs/api/qiskit/qiskit.transpiler.generate_preset_clifford_t_pass_manager "qiskit.transpiler.generate_preset_clifford_t_pass_manager")) by removing transpiler passes that have little or no impact on the quality of the resulting circuit. See [#16406](https://github.com/Qiskit/qiskit/pull/16406) for more details.

- Improved the runtime performance of [`synth_mcx_n_clean_m15()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_n_clean_m15 "qiskit.synthesis.synth_mcx_n_clean_m15") function by migrating the implementation to Rust. The function synthesizes multi-controlled X gates using clean ancillary qubits (Maslov 2016). Benchmarks show **1.5-1.6x speedup** across control qubit counts from 50 to 5000. There are no API changes. See [#16703](https://github.com/Qiskit/qiskit/pull/16703/) for more details

- Improved the runtime performance of [`synth_mcx_1_clean_kg24()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_1_clean_kg24 "qiskit.synthesis.synth_mcx_1_clean_kg24"), [`synth_mcx_1_dirty_kg24()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_1_dirty_kg24 "qiskit.synthesis.synth_mcx_1_dirty_kg24"), [`synth_mcx_2_clean_kg24()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_2_clean_kg24 "qiskit.synthesis.synth_mcx_2_clean_kg24"), and [`synth_mcx_2_dirty_kg24()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_2_dirty_kg24 "qiskit.synthesis.synth_mcx_2_dirty_kg24") by migrating the implementation to Rust. Benchmarks show a significant speedup across control qubit counts from 50 to 1000. See [#16783](https://github.com/Qiskit/qiskit/pull/16783) for more details.

- [`SparsePauliOp.to_matrix()`](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp#to_matrix "qiskit.quantum_info.SparsePauliOp.to_matrix") now allocates dense matrices in a way that is more likely to get OS/kernel-level optimizations, especially for large matrices with few nonzero terms.

- Improved runtime of [`synth_mcp_noaux_sp22()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcp_noaux_sp22 "qiskit.synthesis.synth_mcp_noaux_sp22") synthesis function by migrating implementation to Rust, resulting in approximately 25-34x speedup across circuit sizes (n=50 to n=1000). See [#16755](https://github.com/Qiskit/qiskit/pull/16755) for more details.

- Improved runtime of [`synth_mcx_noaux_sp22()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_noaux_sp22 "qiskit.synthesis.synth_mcx_noaux_sp22") synthesis function by migrating implementation to Rust, resulting in approximately 2x-2.6x speedup across circuit sizes (n=50 to n=1000). See [#16818](https://github.com/Qiskit/qiskit/pull/16818) for more details.

- Improved runtime of [`synth_mcx_1_clean_b95()`](/docs/api/qiskit/synthesis#qiskit.synthesis.synth_mcx_1_clean_b95 "qiskit.synthesis.synth_mcx_1_clean_b95") synthesis function by migrating implementation to Rust, resulting in approximately 6x speedup across circuit sizes (k=50 to k=1000). See [#16710](https://github.com/Qiskit/qiskit/pull/16710) for more details.
