Qiskit SDK 2.3 release notes
2.3.0
Prelude
Qiskit v2.3.0 is a new feature release of the Qiskit SDK.
This new version significantly expands the C API for transpilation, making more of the Target (QkTarget) available for inspection from C, and allowing the DAGCircuit (QkDag) to be created and manipulated. This makes it possible to write custom transpiler passes when compiling against the stand-alone libqiskit object. There are individual transpilation-stage functions in the C API (for example, qk_transpile_stage_layout()), to make it easier to insert custom logic into transpilation without having to recreate the entire pipeline manually.
The performance and feature set of transpilation to early fault-tolerant targets has also been improved. With the new PauliProductMeasurement instruction, which represents a projective measurement into a Pauli product basis, Qiskit now fully supports transpiling circuits to a Pauli-based computation basis using the existing LitinskiTransformation pass. The new unitary synthesis method, RossSelingerSynthesis, which can be set in the transpiler using unitary_synthesis_method="gridsynth", enables using the asymptotically optimal Ross-Selinger algorithm for single-qubit Clifford+T synthesis. Other improvements include, for example, a better OptimizeCliffordT pass or the CommutativeOptimization pass, which takes into account commutative optimizations of Pauli-based circuits.
Internally, the representation of ControlFlowOp objects has changed to be Rust-native. This transformation is not yet complete; you may see some performance regression in Qiskit 2.3 around control-flow operations. Later versions of Qiskit should take this further, solving long-standing performance and API concerns around control-flow operations.
Note that from this release onwards, Python 3.9 is no longer supported due to having passed its end of life in October 2025, and macOS on Intel processors has been downgraded to tier 2 platform support due to Apple beginning to sunset the platform. All versions of CPython from 3.10 onwards are supported. See Operating system support for the current support tiers of different platforms.
There will be further feature releases of Qiskit in the 2.x series; we do not expect to release Qiskit 3.0 until much later in 2026, as there is currently no need for breaking changes.
C API Features
-
Added the function
qk_target_instruction_supported()to check the compatibility of any gate or instruction with the instance ofQkTarget. This check is performed based on the provided instruction’s name, qargs, and parameters. -
Added the function
qk_target_entry_set_name()to set the name of an existing target entry. -
Added a new function
qk_circuit_library_quantum_volume()to generate a quantum volume model circuit. -
Added ways of iterating and checking the gate map of a
QkTarget. The following methods were added:qk_target_op_num_properties()qk_target_op_index()qk_target_op_name()qk_target_op_qargs_index()qk_target_op_qargs()qk_target_op_props()
And the following representation was added:
QkInstructionProperties: to represent theInstructionProperties.
Example:
// Create Target with a mix of global and non-global gates. QkTarget *target = qk_target_new(2); // Create a CX entry QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX); uint32_t qarg_samples[2][2] = { {0, 1}, {1, 0}, }; double props[2][2] = { {2.7022e-11, 0.00713}, {3.0577e-11, 0.00713} }; for (int i = 0; i < 2; i++) { qk_target_entry_add_property(cx_entry, qarg_samples[i], 2, props[i][0], props[i][1]); } qk_target_add_instruction(target, cx_entry); // Create an SX entry QkTargetEntry *sx_entry = qk_target_entry_new(QkGate_SX); for (int i = 0; i < 2; i++) { uint32_t qargs[1] = {i}; qk_target_entry_add_property(sx_entry, qargs, 1, 35.5e-9, 0.); } qk_target_add_instruction(target, sx_entry); // Create an H entry qk_target_add_instruction(target, qk_target_entry_new(QkGate_H)); // Get the size of the size_t target_length = qk_target_num_instructions(target); for (size_t op_idx = 0; op_idx < target_length; op_idx++) { // Allocate space for qargs and props uint32_t *qargs; uint32_t qargs_len; QkInstructionProperties props; // Retrieve the operation's name char *name = qk_target_op_name(target, op_idx); size_t num_props = qk_target_op_num_properties(target, op_idx); for (size_t props_idx = 0; props_idx < num_props; props_idx++) { // Populate qargs qk_target_op_qargs(target, op_idx, props_idx, &qargs, &qargs_len); // Populate properties qk_target_op_props(target, op_idx, props_idx, &props); } // Free the name string qk_str_free(name); } -
QkTargetnow gives its users the ability to retrieve operations directly from it. The following methods have been added:And the following representation was added:
QkTargetOp: To represent an operation in theQkTarget.
-
The C API now exposes
QkParamto represent gate parameters, including symbols and parameterized expressions. TheQkParaminterface itself supports symbolic calculations including standard arithmetic operations and trigonometric functions. For example:QkParam *x = qk_symbol_new("x"); // a symbol called "x" QkParam *y = qk_symbol_new("y"); // a symbol called "y" QkParam *val = qk_symbol_from_double(2.0); // the value 2.0 QkParam *out = qk_symbol_zero(); // to store the final expression // build 2 sin(x + y) qk_param_add(out, x, y); // out = x + y qk_param_sin(out, out); // out = sin(out) qk_param_mul(out, out, val); // out = out * 2 qk_param_free(x); qk_param_free(y); qk_param_free(val); qk_param_free(out); -
The C API can now represent and manipulate
DAGCircuitas the opaqueQkDag. The following functions have been added in relation to the DAG:qk_dag_new()qk_dag_add_quantum_register()qk_dag_add_classical_register()qk_dag_free()qk_dag_copy_empty_like()qk_dag_num_qubits()qk_dag_num_clbits()qk_dag_num_op_nodes()qk_dag_node_type()qk_dag_qubit_in_node()qk_dag_qubit_out_node()qk_dag_clbit_in_node()qk_dag_clbit_out_node()qk_dag_wire_node_value()qk_dag_op_node_clbits()qk_dag_op_node_gate_op()qk_dag_op_node_kind()qk_dag_op_node_num_clbits()qk_dag_op_node_num_params()qk_dag_op_node_num_qubits()qk_dag_op_node_qubits()qk_dag_op_node_unitary()qk_dag_apply_barrier()qk_dag_apply_gate()qk_dag_apply_measure()qk_dag_apply_reset()qk_dag_apply_unitary()qk_dag_get_instruction()qk_dag_compose()qk_dag_topological_op_nodes()qk_dag_substitute_node_with_dag()qk_dag_predecessors()qk_dag_successors()
-
Added the
QkDagNodeTypeenumeration to distinguish the type of a DAG node. This is the return type ofqk_dag_node_type(). -
Added the
QkOperationKindenumeration to distinguish different native operation types. This is the return type ofqk_dag_op_node_kind(). -
Added
qk_circuit_copy_empty_like()to create a copy of the given circuit, as a mirror ofQuantumCircuit.copy_empty_like(). -
Added new enumerations for use with some circuit and DAG API functions to specify copying modes:
-
Added the
QkDagNeighborsstruct, which is the return type ofqk_dag_successors()andqk_dag_predecessors(), and its associated freeing functionqk_dag_neighbors_clear(). -
A new struct,
QkNeighbors, is added, which is a representation of two-qubit coupling graph implied by aTarget. It is initialized by the new functionqk_neighbors_from_target(), cleared withqk_neighbors_clear(), and has a helper functionqk_neighbors_is_all_to_all(). -
Added the
qk_dag_to_circuit()andqk_circuit_to_dag()functions to support DAG to circuit and circuit to DAG conversions, respectively. -
The
qk_transpiler_pass_standalone_unitary_synthesis()andqk_transpile()functions now support synthesizing 3+ qubitUnitaryGateobjects in a circuit. In Qiskit 2.2 this was not supported as the underlying synthesis algorithmqs_decomposition()used for 3+ qubit unitary synthesis was previously written in Python, but now that it has been ported to Rust this functionality is available from C. -
Added new functions for running transpiler stages to the C API. These functions are:
These function are used to run these stages from the preset pass manager on a
QkDagobject. The goal of these functions are to enable composable transpilation workflows from C when combined with custom transpiler passes. -
Added a new function
qk_transpile_layout_generate_from_mapping()which is used to generate a customQkTranspileLayoutwith an initial layout set from a mapping array. The intent of this function is to enable creating a layout object for custom layout transpiler passes. -
The two forms of “perfect” layout selection via the VF2 subgraph-isomorphism algorithm are now available as standalone transpiler passes in the C API. These functions are
These differ in how the directionality and gatesets of interactions are handled;
exactrequires matches to directly support all gates natively, whereasaverageexpects that further transpiler passes will decompose gates into the supported set of a given qubit or link.These functions use an encapsulated version of the VF2 configuration (
QkVF2LayoutConfiguration), which has setter methods for each of the options. This includes allowing access to the new two-limit form of thecall_limitargument.
Circuits Features
-
Added a new instruction class,
PauliProductMeasurement, which represents a joint projective measurement on multiple qubits, where the measured observable is a tensor product of Pauli operators. The outcome of this measurement is a single eigenvalue, either or , indicating the eigenstate of the Pauli product.For additional background, see A Game of Surface Codes: Large-Scale Quantum Computing with Lattice Surgery by Daniel Litinski.
A
PauliProductMeasurementcan be instantiated from aPauli, where the Pauli may include a phase of , but not of or . The instruction has the same number of qubits as the Pauli, and a single classical bit.As an example:
from qiskit.circuit import QuantumCircuit from qiskit.quantum_info import Pauli from qiskit.circuit.library import PauliProductMeasurement ppm = PauliProductMeasurement(Pauli("XZ")) qc = QuantumCircuit(6, 2) qc.append(ppm, [4, 1], [1]) -
A new
QuantumCircuit.to_dag()method now provides a convenient wrapper aroundcircuit_to_dag(). -
ParameterExpressionnow has anum_parametersattribute, which is equal to the length of itsparametersset, but calculated with less overhead.
OpenQASM Features
- The OpenQASM 2 exporter (
qasm2.dumps()) now supports outputting simple single-instructionIfElseOpblocks, if the condition is a simple register–integer equality test. This corresponds to what the OpenQASM 2 language can represent.
QPY Features
- Version 17 of QPY now includes serialization formats for
SparseObservableobjects when used as parameters of objects. In particular, this allows to serializePauliEvolutionGateobjects that internally use this operator and the payload of the evolution gate is updated.
Quantum Information Features
-
Added
Statevector.from_circuit()as a mirror ofOperator.from_circuit(). This allows directly instantiating aStatevectorin the space of virtual qubits, even for circuits that have been transpiled to a physical-qubit space. -
Improved the performance of
Clifford.dot()and ofClifford.compose()when called withfront=Trueand aQuantumCircuitcontaining only Clifford gates. Previously, the circuit was completely consumed into aCliffordobject first, and then the two objects were combined. Now, the baseCliffordis updated iteratively, which is significantly faster for small circuits. -
Added the
PauliLindbladMap.parity_sample()method. This method is very similar to the pre-existingPauliLindbladMap.signed_sample()method, however it uses a sign convention that is more consistent with the rest of Qiskit, and therefore is the preferred method to use going forward. It has additional optional arguments to apply scalings to the rates when sampling without modifying the instance. -
Several of the
quantum_info“predicates” functions, such asis_identity_matrix(), were optimized to avoid unnecessary matrix allocations.
Synthesis Features
-
Added
gridsynth_rz(), which constructs a single-qubit quantum circuit approximating an RZ-rotation with a specified angle. The algorithm is described in the paper Optimal ancilla-free Clifford+T approximation of z-rotations by Neil J. Ross, Peter Selinger and is implemented in https://github.com/qiskit-community/rsgridsynth. -
Added
gridsynth_unitary(), which constructs a single-qubit quantum circuit approximating a given single-qubit unitary matrix. The algorithm works by decomposing the unitary matrix into RZ-rotation, RX-rotation, and another RZ-rotation, and applying the Ross-Selinger algorithm to each of the three rotations. -
The general unitary synthesis algorithm
qs_decomposition()has been rewritten in Rust greatly improving the runtime performance of the function.
Transpiler Features
-
Added a new transpiler pass,
CommutativeOptimization, which performs gate cancellation and merging, exploiting commutativity relations. The pass unifies and extends the functionality of bothCommutativeCancellationandCommutativeInverseCancellation.Specifically, the pass:
- Cancels pairs of inverse gates, including pairs that are inverse up to a global phase (adjusting the global phase if necessary).
- Attempts to merge consecutive gates when possible, for example sequences of RZ-gates, RX-gates, Pauli rotations, and so on.
-
Added a new option,
fallback_on_default, to theUnitarySynthesistranspiler pass. This option applies when the pass is called with a non-default synthesis plugin, specified via the argumentmethod.By default, the specified plugin is used to synthesize every unitary in the circuit (provided the plugin applies; for instance, it will not run if it does not support the number of qubits over which the unitary is defined). If the plugin cannot synthesize the unitary and returns
None, the original unitary is left unchanged in the circuit. Whenfallback_on_defaultis set toTrue, the pass will instead invokeDefaultUnitarySynthesisplugin when the specified method fails.This feature is particularly useful when custom plugins are intended to handle only a subset of all unitaries: users can rely on their custom logic when it applies and use the default synthesis where it does not.
-
Added a new unitary synthesis plugin,
RossSelingerSynthesis, which synthesizes single-qubit unitary gates using the Ross-Selinger algorithm and produces a single-qubit quantum circuit consisting of Clifford, and gates.The plugin is invoked by the
UnitarySynthesistranspiler pass when the parametermethodis set to"gridsynth". -
When transpiling to the Clifford+T basis, the
UnitarySynthesistranspiler pass now uses a Clifford+T synthesis algorithm by default to approximate single-qubit unitaries.Similarly, the
DefaultUnitarySynthesisplugin now uses the same Clifford+T synthesis algorithm to approximate single-qubit unitaries. -
A new
DAGCircuit.to_circuit()method now provides a convenient wrapper arounddag_to_circuit(). -
Added a new transpiler pass
SubstitutePi4Rotations, that converts single-qubitRZGate,RXGateandRYGaterotation gates whose angles are integer multiples of into discrete sets of Clifford,TGateandTdgGategates. Note that odd multiples of require a singleTGateandTdgGate, as well as some Clifford gates, while even multiples of , or equivalently, integer multiples of , can be written using only Clifford gates. -
The transpiler pass
LitinskiTransformationhas been extended to handle measurements. Thus, the transform now applies to a circuit containing Clifford, single-qubit RZ-rotation gates (including and ), and standard Z-measurements, and moves Clifford gates to the end of the circuit. In the process, it changes RZ-rotations to product Pauli rotations (implemented asPauliEvolutionGategates), and changes Z-measurements to product Pauli measurements (implemented usingPauliProductMeasurementinstructions). -
The
OptimizeCliffordTtranspiler optimization pass has been significantly enhanced and reimplemented in Rust.This pass performs a peephole optimization on circuits expressed using the Clifford+T gateset. More precisely, it collapses all chains of single-qubit gates containing Clifford+T into a minimal usage of (or ). The pass runs on a chain in time proportional to the number of gates in the chain.
-
Added
WrapAngles.DEFAULT_REGISTRYcontaining the default registry forWrapAngles. This new attribute supersedes the previousWRAP_ANGLE_REGISTRY, and we encourage downstream users to change to the new form as soon as possible. -
The
DAGCircuit.topological_op_nodes()andDAGCircuit.topological_nodes()methods now support areverseBoolean argument. When set toTrue, the methods yield nodes in a reverse topological order, from the outputs of the circuit towards the inputs. This provides a direct and efficient way to iterate over a DAG backwards without the overhead of explicitly reversing the list of nodes returned by the functions, creating a new, structurally reversed DAG withDAGCircuit.reverse_ops(). -
The
CommutationCheckernow supports efficient commutation checks between the Pauli-based gatesPauliGate,PauliEvolutionGateandPauliProductMeasurementby checking if the generating Pauli operators commute. This enables optimizations, in particular for circuits in Pauli-based computation format, expressed in terms of Pauli evolutions and Pauli product measurements. Note that commutations between these Pauli-based gates and other standard gates are not yet handled in the same efficient manner. -
Added a new argument,
matrix_max_num_qubits, toCommutationChecker.commute(). This allows to limit the size of instructions for which the commutation checker is allowed to compute the exponentially expensive matrix representation. This new argument allows to distinguish between the size limit on instructions to handle (set viamax_num_qubitswhich is newlyNoneper default, meaning no limit) and a matrix size limit. -
The functions
generate_preset_pass_manager()andtranspile()now take the argumentunitary_synthesis_methodinto account when compiling into Clifford+T basis set, thus allowing the invocation of custom unitary synthesis plugins. -
VF2LayoutandVF2PostLayoutnow track partial candidate-layout scores during subgraph isomorphism matching. This has no meaningful effect when there is no perfect layout to find, but can drastically reduce the cost of scoring layouts to choose the best candidate in high-symmetry cases. -
The
call_limitargument ofVF2LayoutandVF2PostLayoutcan now be a 2-tuple, where the first item is used before the first match is found, then the limit swaps to the second after. This is a more reliable runtime-limiter than themax_trialsargument, now that layouts are scored on the fly with more aggressive pruning.
Miscellaneous Features
- Added ability to compute the expectation value of a
SparseObservablefrom sampled bitstrings in the Z-basis by using thesampled_expectation_value()function.
Upgrade Notes
ConsolidateBlocksnow reads aPropertySetkeyConsolidateBlocks_qubit_mapon entry. This key and its value are not public and should not be read or written to by other passes.
C API Upgrade Notes
qk_target_entry_new_fixed()has an additionalnameparameter, to set the name of the target entry. Fixed-angle entries almost invariably require overriding the name of the standard gate to function correctly.
Circuits Upgrade Notes
-
The names of the circuits produced as definitions of standard circuit library gates are now set to
None. Previously, these circuits had the same name as the gate, making it very easy to construct opaque gates with names matching a standard gate. This violates a common assumption in Qiskit, where standard gate names should be unique. -
The internal representation of
ControlFlowOps has changed when they are added to aQuantumCircuitorDAGCircuit. The object stored in the circuit and returned on future access will not necessarily be the same instance added to the circuit. Users should not attempt to mutate any objects in-place once they have been added to a circuit. This is likely to corrupt the circuit, whether it is control flow or another object.As with all in-place mutations to Python objects stored within a
QuantumCircuitorDAGCircuit, you must re-assign the instruction to the circuit in order for Rust space to pick up the modifications. For example, when adding annotations to aBoxOpthat is already on a circuit, a transpiler pass should make sure to useDAGCircuit.substitute_node()to update the Rust-space object:from qiskit.circuit import QuantumCircuit, Annotation class MyAnnotation(Annotation): namespace = "my" qc = QuantumCircuit(2) with qc.box(): qc.cx(0, 1) dag = qc.to_dag() # Modifications to the box's annotations in-place require # writing back the information to Rust space. box_node = next(dag.topological_op_nodes()) box_node.op.annotations.append(MyAnnotation()) # Write back the operation. dag.substitute_node(box_node, box_node.op) -
Transpiler performance in the presence of
ControlFlowOpinstructions, includingBoxOp, is expected to be temporarily worse in Qiskit 2.3, as we transition the internal representation of control flow from its previously Python-centric version to a Rust-native one. We expect the performance to improve again in a later version of Qiskit, and to enable us to resolve long-standing API deficiencies in transpiler passes acting on control-flow operations. -
The blocks of
ControlFlowOpinstances will no longer tracknameormetadatafields. These were already unsettable with the control-flow builder interface, and their existence was an unintended implementation detail rather than an intentional API. -
The method
Gate.control()no longer returns anAnnotatedOperationwhen the argumentannotatedis set toTrueand a native controlled-gate class is available. This change is consistent with how the argumentannotatedis used across the standard circuit library, and enables more efficient decompositions of control-annotated gates. The affected gates are:- Single-controlled
H,S,Sdg,U3,Y,Z,SX,RX,RY,RZ,SwapandCZgates; - Double-controlled
Z-gate; - arbitrarily-controlled
Phase,CPhase,MCPhase,U1,CU1,MCU1andMCMTgates.
- Single-controlled
-
The default value of the argument
annotatedinQuantumCircuit.control()is nowNoneinstead ofFalse. This does not affect the actual circuits, but is consistent with the default value ofannotatedused across the circuit library.
QPY Upgrade Notes
- The default QPY version (
QPY_VERSION) used inqpy.dump()is now 17.
Quantum Information Upgrade Notes
- Improved the performance of
Statevector.expectation_value()for all-identity Pauli operators by relying on the optimized general-case implementation instead of a dedicated shortcut that scaled poorly with the number of qubits.
Transpiler Upgrade Notes
-
The maximum call and trial limits for the exact-matching run of
VF2PostLayoutatoptimization_level=3have been reduced to avoid excessive runtimes for highly symmetric trial circuits being mapped to large coupling maps. -
The preferred location for the default registry for the
WrapAnglestranspiler pass is nowWrapAngles.DEFAULT_REGISTRY. The previous deeply nestedWRAP_ANGLE_REGISTRYpath will continue to work for backwards compatibility, but we encourage downstream packages to use the new location. The previous path was an oversight in Qiskit 2.2, and traverses modules that were never intended to be part of the public API. -
While the interface to
VF2LayoutandVF2PostLayoutremain logically the same, themax_trialsargument now has much less effect as a runtime limiter, other than when set to the value1. This is because, with the new on-the-fly score-and-prune algorithm used internally by the class, “complete” layouts are encountered far more rarely, and the count of “trials” only increments when a new layout is encountered that is better in error rate than a previous one. You should instead usecall_limitas the deterministic runtime limiter; wheremax_trialsmeasures complete layouts encountered,call_limitmeasures partial-layout extensions.
Miscellaneous Upgrade Notes
-
The minimum supported version of Python is now 3.10, following the end of life of Python 3.9 in October 2025 and deprecation warnings in Qiskit since version 2.1.
-
Support for macOS x86-64 (Intel) has been downgraded from tier 1 to tier 2. Qiskit will still provide tested and pre-compiled wheels for this platform, but tests are only performed at the time of release, rather than at every change. This might cause delays in releasing the wheels for this platform.
This change was made because Apple has begun to sunset the platform, and the Qiskit team does not have the developer or CI resources left to continue tier 1 support. We can only support macOS x86-64 while GitHub continues to provide runners for it, and we expect this support to be removed in the second half of 2027.
C API Deprecations
-
The function
qk_transpiler_pass_standalone_vf2_layout()is deprecated, as callers should now useqk_transpiler_pass_standalone_vf2_layout_average(). The new function name is more descriptive of the scoring heuristic, and the API allows encapsulated access to the whole new configuration object, including the two-limit form ofcall_limit.This deprecation is not entirely necessary for users, but with the C API still explicitly unstable, we are using this as a trial of managing deprecations and compiler-specific warnings in the C API, before we reach stability guarantees.
Circuits Deprecations
-
Since Qiskit 1.0, the methods
Gate.control()andQuantumCircuit.control()accept the argumentannotatedwhich can be eitherFalse,TrueorNone. Presently, a controlled gate is represented using a dedicated controlled-gate class when it exists, regardless of the value ofannotated, for instance a two-controlled version of anXGateis aCCXGate. If a dedicated controlled-gate class does not exist, the controlled gate is represented as aControlledGatewhenannotated=Falseand as anAnnotatedOperationwhenannotated=True. The default valueannotated=Noneis treated exactly the same asFalse.In Qiskit 3.0, we will no longer allow setting
annotated=Noneand instead change set the default toannotated=True. This is recommended, as it defers the construction of the controlled circuit from the circuit construction to the transpiler, and enables additional controlled-gate optimizations, typically leading to higher-quality circuits (especially for hierarchical circuits).However, you will still be able to explicitly set
annotated=Falseto preserve the previous behavior.
Transpiler Deprecations
- Deprecated the legacy serialization format used in
SolovayKitaevDecomposition, which was based on pickling the basic approximations in the form of a Pythondict. The loading process is a potential security vulnerability and should only be used with trusted files. The new serialization format avoids this vulnerability. The functions to generate the legacy format,generate_basic_approximations(), and load it,SolovayKitaevDecomposition.load_basic_approximations()and in the initializer ofSolovayKitaevDecomposition, have been deprecated. Instead, useSolovayKitaevDecomposition.save_basic_approximations()to generate a format that can safely be loaded in the class initializer.
Build System Changes
- When building or packaging Qiskit from source, the version of setuptools required is now at least version 77.0 (released in March 2025). This is to support the new license-metadata specifications of PEP 639. This dependency is specified in the build requirements, and so no manual action should be needed.
Bug Fixes
-
Fixes the implementation of
__deepcopy__()inQuantumCircuitwhich did not deep-copy circuit parameters. As a consequence, mutating aBoxOpin a copied circuit no longer affects the original circuit. -
DAGCircuit.apply_operation_back(),apply_operation_back()andcircuit_to_dag()will now add new edges in a deterministic order. The previous behavior could cause certain transpiler passes (such asSabreSwap) to traverse the DAG in non-deterministic orders. -
DAGCircuit.apply_operation_front()can no longer insert invalid self loops when handling nodes that include classical conditions. -
Fixed an issue in the
Optimize1qGatesDecompositionwhen the pass was initialized with aTargetthat contains 1q gates with fixed angle parameters. Previously, the pass would potentially output gates outside the target as it wasn’t checking that the gate in the target supported arbitrary parameter values. Fixed #14743. -
Fixed incorrect behavior in the
BasisTranslatorpass where a multi-qubit gate within aControlFlowOpblock would track with its local qubit indices instead of using the absolute indices from the source circuit. -
Fixed re-use of the same
ConsolidateBlocksinstance on multiple circuits, including calls totranspile()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. -
The
ConsolidateBlockstranspiler pass will now correctly evaluate whether a given gate is hardware-supported while recursing into control-flow operations. -
qpy.dump()can now handle writing out to.gzfiles opened using the standard-librarygzipmodule with QPY versions 16 or greater. See #15157 for details. -
Fixed the methods
MCPhaseGate.inverse()andMCU1Gate.inverse()to preserve the control states of open-controlled gates when computing their inverses. -
ConsolidateBlockswill now return a Python-space exception instead of panicking when it detects invalid or out-of-date analysis in the legacyrun_listorblock_listPropertySetkeys. -
Optimize1qGatesDecompositionwill now raise aTranspilerErrorinstead of a Rust-space panic when attempting to run on a circuit that is too large for theTarget. -
Fixed an issue with
picklesupport for theSabreSwapwhere aSabreSwapinstance would error when being pickled after theSabreSwap.run()method was run. Fixed #15071. -
The scheduling passes,
ALAPScheduleAnalysisandASAPScheduleAnalysis, will now correctly handle circuits with no operations in them. Previously they would raise aTranspilerErrorfalsely claiming “No durations provided”. Fixed #15145. -
Fixed an issue where
is_unitary()was not properly respecting the input tolerance values when checking if an operator is unitary. The method now correctly uses the providedatolandrtolparameters when simplifying the operator and checking if it equals the identity. This fixes #14107. -
Fixed a bug in
UnitarySynthesistranspiler pass, when it is called with a non-default synthesis plugin (specified viamethod) that supportsbasis_gatesbut nottarget. The pass now correctly passes the basis gates from thetargetto the plugin. -
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
ControlFlowOpoperations directly, or for circuits after transpilation. -
Fixed support for serializing
PauliEvolutionGatewith operators of typeSparseObservable, when using QPY version 17. -
Fixed a mismatch in
QkTargetOpin which the length of the array stored inQkTargetOp.paramsdid not match the number exposed byQkTargetOp.num_params. Wildcard parameters are now represented byNAN, and the length of the array will always beQkTargetOp.num_params. This bug was only present in 2.3.0rc1. -
Fixed a regression in the classical expression representation of
Valueof typeUintof width greater than 64 bits. Previously, the value of expressions with these types was unintentionally coerced into a double floating point value internally, resulting in loss of precision. -
The
HighLevelSynthesispass will now correctly select the optimization metric according to the basis set: two-qubit gate count for continuous bases and T count for Clifford+T bases. Previously, this information was not correctly propagated, resulting in worse than expected T counts. -
Fixed the circuit text drawer so that circuit instructions with classical wires are drawn in separate layers.
-
Matrix multiplication (
@) betweenOperatorandStatevectorwill now apply the operator to the state and return the resultingStatevector. -
Fixed a bug in the
ElidePermutationstranspiler pass that caused it to crash when handling single-qubit permutations. -
Fixed a potential deadlock issue when running layout passes such as
SabreLayoutwith a disjoint connectivity in theTargetand in a multiprocessing context from runningPassManager.run()ortranspile()with more than one circuit. On Linux this is the default behavior when runningPassManager.run()ortranspile()with more than one circuit; on all other platforms, you must opt in to using a multiprocessing context.This was due to an underlying issue in CPython tracked in python/cpython#84559 when mixing multiprocessing and multithreading. Typically Qiskit guards against mixing the two methods of parallelism, but in the case of handling disjoint connectivity graphs this guard was missing around multithreaded Rust code.
-
The method
Statevector.to_dict()will now respect itsdecimalskeyword argument, which it previously ignored. -
Fixed an issue with the
timeline_drawer()visualization function where it would error when visualizing a scheduled circuit from a target that had parameterized gates in the target with a duration set. -
Fixed label generation for
PauliEvolutionGatewithSparseObservableoperators. Labels now display Pauli operators with qubit indices (e.g.,"X0 X2") instead of the concatenated string format (e.g.,"XX"), improving clarity when distinguishing between different operators. -
Pauli.evolve()now correctly handles quantum circuits containing certain parametrized rotation gates, when the angle is a multiple of , e.g.RZGate(math.pi/2)orRZZGate(math.pi/2). Formerly they were not recognized as Clifford gates, and an error was raised. -
BasePassManagerno longer replaces falsy but valid outputs from passes with the original input program. A pass returning0,Falseor another falsy value will now be preserved, and onlyNoneindicates failure. -
QuantumCircuit.compose()will now correctly remap any variables and stretches used inDelayinstructions when thevar_remapargument is specified.