Qiskit SDK 2.0 release notes
2.0.0
Prelude
We are pleased to release Qiskit v2.0.0, with new features that improve its performance and capabilities. The feature highlights of Qiskit v2.0.0 include:
- The introduction of a C API for building and interacting with
SparseObservable
objects. This first compiled language interface represents an important milestone in the evolution of Qiskit and will grow in scope throughout the v2.x release series. The initial iteration of the C API is an experimental feature, and there may be breaking API changes in minor versions following our version strategy.- The addition of a new
BoxOp
control-flow op that maps to the OpenQASM 3 concept of a box and allows to group series of instructions for later processing and custom scheduling. This operator is useful for applications such as twirling, noise-learning, and stretch-based scheduling among others.- The ability to create
stretch
durations forDelay
instructions, which enable expressing relationships between timing-aware instructions. The newStretch
type extends the existing classical expression system, allowing design intent to be captured at circuit construction time and resolved at compile time. See the OpenQASM documentation for details.- Improved synthesis when a
Target
contains fractional two qubit basis gates with support for arbitrary angles such asRZXGate
orRZZGate
, which significantly reduces gate counts in the synthesized circuits.- Improved runtime performance, particularly during the circuit construction step, where benchpress benchmarking shows a 2x speedup over Qiskit v1.3. This improvement is achieved through a combination of contributions, including leveraging additional native Rust gate representations, such as
UnitaryGate
, and removing legacy data model elements.
In line with our semantic versioning policy, documented at the time of the v1.0.0 release, this major release also includes API changes that are not backward-compatible with the v1.x release series. In particular, several deprecated components of the Qiskit data model have been removed, such as the .c_if()
method, the qobj
module, BackendV1
, and qiskit.pulse
, as well as the deprecated V1 primitive reference implementations. You can refer to the upgrade release notes sections for more details on all of these removals and API changes. The removed APIs are still supported in the Qiskit v1.4.x release which will receive bug fixes for another six months and will have security updates for one year.
New Features
-
Support for the Linux aarch64 platform has been promoted to tier 1 support as documented in:
https://quantum.cloud.ibm.com/docs/guides/install-qiskit#operating-system-support
from its previous support level of tier 2 in the v1.x release series.
-
Introduced a new C API to build and interact with sparse observables. While the API surface in this release is fairly small - covering only the
SparseObservable
class - it represents an important milestone in the evolution of Qiskit, as this is the first time the SDK exposes a public interface in C and it lays the foundation for future expansions of the Qiskit C interface. As this is the first public interface in C this is an experimental feature, and if necessary the API may change in a minor version release.Detailed syntax and additional information can be found in the C API documentation. A minimal example to construct the 100-qubit observable
2 X0 Y1 Z2
is:#include <complex.h> #include <qiskit.h> #include <stdint.h> #include <stdio.h> int main(int argc, char *argv[]) { // build a 100-qubit empty observable uint32_t num_qubits = 100; QkObs *obs = qk_obs_zero(num_qubits); // add the term 2 * (X0 Y1 Z2) to the observable complex double coeff = 2; QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z}; uint32_t indices[3] = {0, 1, 2}; QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits}; qk_obs_add_term(obs, &term); // print some properties printf("num_qubits: %u\n", qk_obs_num_qubits(obs)); printf("num_terms: %lu\n", qk_obs_num_terms(obs)); // free the memory allocated for the observable qk_obs_free(obs); return 0; }
Circuits Features
-
Added a new
get_control_flow_name_mapping()
convenience function that returns a mapping of Qiskit control-flow operation names to their corresponding classes.Example usage:
from qiskit.circuit import get_control_flow_name_mapping ctrl_flow_name_map = get_control_flow_name_mapping() if_else_object = ctrl_flow_name_map["if_else"] print(if_else_object)
<class 'qiskit.circuit.controlflow.if_else.IfElseOp'>
-
Added a new circuit method,
QuantumCircuit.estimate_duration()
, to estimate the duration of a scheduled circuit after transpilation. The circuit duration is estimated by finding the longest path on a scheduled circuit based on the durations provided by a givenTarget
. This method only works for simple circuits that do not contain control flow or other classical feed-forward operations.Use this method instead of the deprecated
QuantumCircuit.duration
attribute if you need an estimate of the full circuit duration.Example usage:
from qiskit import QuantumCircuit, transpile from qiskit.providers.fake_provider import GenericBackendV2 backend = GenericBackendV2(num_qubits=3, seed=42) circ = QuantumCircuit(3) circ.cx(0, 1) circ.measure_all() circ.delay(1e15, 2) circuit_dt = transpile(circ, backend, scheduling_method="asap") duration = circuit_dt.estimate_duration(backend.target, unit="s") print("Estimated duration: ", duration)
-
Added two new classes:
BitFlipOracleGate
andPhaseOracleGate
.BitFlipOracleGate
was introduced as an alternative to directly synthesizingBooleanExpression
, which has been removed in Qiskit v2.0.PhaseOracleGate
was added as an alternative toPhaseOracle
, as the latter will be deprecated throughout the v2.x releases. Both classes share the interface ofPhaseOracle
, except for theevaluate_bitstring
method, which is no longer present.BitFlipOracleGate
synthesizes a bit-flip oracle instead of a phase-flip oracle, meaning it acts on one additional qubit and can be viewed as applying a controlled-X operation, where the control is determined by the value of the expression encoded by the oracle.from qiskit import QuantumCircuit from qiskit.circuit.library.bit_flip_oracle import BitFlipOracleGate qc = QuantumCircuit(5) bool_expr = "(x0 & x1 | ~x2) & x4" oracle = BitFlipOracleGate(bool_expr) qc.compose(oracle, inplace=True) qc.draw('mpl') qc.decompose().draw('mpl')
from qiskit import QuantumCircuit from qiskit.circuit.library.phase_oracle import PhaseOracleGate qc = QuantumCircuit(5) bool_expr = "(x0 & x1 | ~x2) & x4" oracle = PhaseOracleGate(bool_expr) qc.compose(oracle, inplace=True) qc.draw('mpl') qc.decompose().draw('mpl')
-
A new control-flow op,
BoxOp
, its associatedQuantumCircuit.box()
method and context manager are now available fromqiskit.circuit
.The normal way to construct a box is to use the
QuantumCircuit.box()
context manager:from qiskit.circuit import QuantumCircuit qc = QuantumCircuit(5) with qc.box(): # This box "uses" qubits 0 and 1. qc.x(0) qc.z(1) # Boxes can be assigned a duration. with qc.box(duration=100, unit="ms"): # This box "uses" qubits 2, 3 and 4. # Qubit 4 undergoes no operations. qc.cx(2, 3) qc.noop(4)
The Qiskit “box” maps nearly directly to the OpenQASM 3 concept of a box.
All qubits “used” by the box are timing synchronized at the start and end of the box. In other words, the box has the same “duration” for every qubit it uses, and the start points are synchronized. Other operations at the same scope as the
BoxOp
itself see the box as atomic; it is valid to commute an operation past an entire box if the operation commutes with the action of the whole box, but it is not generally valid to move an operation into or out of a box.The principal uses of a box are to group a series of instructions for later processing (such as grouping a partial layer of two-qubit gates), and to schedule a compound block together at one scope while using relative scheduling within the block (such as dynamical decoupling several qubits in a group). Qiskit’s compiler does not yet have built-in passes that will group instructions or schedule instructions with a
BoxOp
.The transpiler supports routing and layout in the presence of boxes, and will optimize within the box (up to the
optimization_level
setting), but does not yet perform optimizations around the atomic structure of boxes. The text- and Matplotlib-based circuit drawers support box. Exporting to QPY and to OpenQASM 3 is supported, although OpenQASM 3 currently has no way of designating idling qubits within a box (it is expected that a spec change will add this in the near future: see the relevant feature proposal). -
Added a new
approximation_degree
argument toCommutationChecker.commute()
andCommutationChecker.commute_nodes()
. This argument allows you to set the approximation threshold for when gates are evaluated as commuting. See the docstring ofCommutationChecker
for more information. -
Added a new circuit method,
QuantumCircuit.noop()
, which allows qubits to be explicitly marked as used within a control-flow builder scope without adding a corresponding operation to them. -
The classical realtime-expressions module
qiskit.circuit.classical
can now represent constant expressions. TheExpr
class now has a booleanconst
attribute which indicates the expression’s const-ness. This allows us to enforce that expressions in certain contexts must be possible to evaluate at compile time.All
Var
expressions are considered to be non-const, while allValue
expressions are const.An expression comprised only of other const expressions is also const:
from qiskit.circuit.classical import expr assert expr.bit_and(5, 6).const
An expression that contains any non-const expression is non-const:
from qiskit.circuit.classical import expr, types assert not expr.bit_and(5, expr.Var.new("a", types.Uint(5)).const
-
The classical realtime-expressions module
qiskit.circuit.classical
can now represent durations by using the new typeDuration
.The module
qiskit.circuit
also has a newDuration
class, which can be used as a literal value within classical expressions.The
lift()
function can be used to create a value expression from aDuration
instance:from qiskit.circuit import Duration from qiskit.circuit.classical import expr expr.lift(Duration.dt(1000)) # Value(Duration.dt(1000), Duration())
-
The classical realtime-expressions module
qiskit.circuit.classical
can now represent IEEE-754 double-precision floating point values using the new typeFloat
.The
lift()
function can be used to create a value expression from a Python float:from qiskit.circuit.classical import expr expr.lift(5.0) # >>> Value(5.0, Float())
This type is intended primarily for use in timing-related (
duration
andstretch
) expressions. It is not compatible with bitwise or logical operations, although it can be used with these if they are first explicitly cast to something else. -
Reduced the number of two-qubit gates when decomposing multi-controlled single-qubit unitary gates. For example:
- For multi-controlled
YGate
on 10 qubits, theCXGate
count was reduced by 56%. - For multi-controlled
HGate
on 10 qubits, theCXGate
count was reduced by 56%. - For multi-controlled
SXGate
andSXdgGate
on 10 qubits, theCXGate
count was reduced by 80%. - For multi-controlled
UGate
on 10 qubits, theCXGate
count was reduced by 31%.
- For multi-controlled
-
The classical realtime-expressions module
qiskit.circuit.classical
can now represent arithmetic operationsadd()
,sub()
,mul()
, anddiv()
on numeric and timing operands.For example:
from qiskit.circuit import QuantumCircuit, ClassicalRegister, Duration from qiskit.circuit.classical import expr # Subtract two integers cr = ClassicalRegister(4, "cr") qc = QuantumCircuit(cr) with qc.if_test(expr.equal(expr.sub(cr, 2), 3)): pass # Multiply a Duration by a Float with qc.if_test(expr.less(expr.mul(Duration.dt(200), 2.0), Duration.ns(500))): pass # Divide a Duration by a Duration to get a Float with qc.if_test(expr.greater(expr.div(Duration.dt(200), Duration.dt(400)), 0.5)): pass
For additional examples, see the module-level documentation linked above.
-
The constructor for
UCGate
now has a new optional argument,mux_simp
, which takes a boolean value that enables the search for simplifications of Carvalho et al. This optimization is enabled by default, identifies and removes unnecessary controls from the multiplexer, reducing the number of CX gates and circuit depth, especially in separable state preparation withInitialize
. -
The
PauliEvolutionGate
now natively supportsSparseObservable
s as input. This efficiently allows to handle evolution under projectors, which are implemented as controls of a phase rotation and require less gates than explicitly expanding the projector in terms of Paulis. For example:from qiskit.circuit.library import PauliEvolutionGate from qiskit.quantum_info import SparseObservable obs = SparseObservable("001") evo_proj = PauliEvolutionGate(obs, time=1) print(evo_proj.definition.draw())
-
A new expression node
Stretch
has been added to the classical expression system to representstretch
variables. To create a newstretch
variable, you can useQuantumCircuit.add_stretch()
. The resulting expression is a constant expression of typeDuration
, which can be used as theduration
argument of adelay()
.For example, to ensure a sequence of gates between two barriers will be left-aligned, whatever their actual durations are, you can do the following:
from qiskit import QuantumCircuit from numpy import pi qc = QuantumCircuit(5) qc.barrier() qc.cx(0, 1) qc.u(pi/4, 0, pi/2, 2) qc.cx(3, 4) a = qc.add_stretch("a") b = qc.add_stretch("b") c = qc.add_stretch("c") # Use the stretches as Delay duration. qc.delay(a, [0, 1]) qc.delay(b, 2) qc.delay(c, [3, 4]) qc.barrier()
The
Stretch
expression is most similar to the existingVar
expression used to represent classical variables in a circuit, except it is constant and is always of typeDuration
. It can be used in other expressions (for example, you can multiply it by a numeric constant) andQuantumCircuit
provides full scoping support for it (for example, it can be captured by or declared within a control flow scope).For additional context and examples, refer to the OpenQASM 3 language specification.
-
Added
Gate
versions of the single-register arithmetic gates that allow the transpiler to perform high-level optimizations compared to theirQuantumCircuit
variants. These are:ExactReciprocalGate
(replacingExactReciprocal
)IntegerComparatorGate
(replacingIntegerComparator
)LinearPauliRotationsGate
(replacingLinearPauliRotations
)PiecewiseLinearPauliRotationsGate
(replacingPiecewiseLinearPauliRotations
)PiecewiseChebyshevGate
(replacingPiecewiseChebyshev
)PiecewisePolynomialPauliRotationsGate
(replacingPiecewisePolynomialPauliRotations
)PolynomialPauliRotationsGate
(replacingPolynomialPauliRotations
)LinearAmplitudeFunctionGate
(replacingLinearAmplitudeFunction
)QuadraticFormGate
(replacingQuadraticForm
)WeightedSumGate
(replacingWeightedAdder
)
Primitives Features
- Added a new
to_bool_array()
method to theBitArray
class that returns the bit array as a boolean NumPy array. Theorder
argument can be used to specify the endianness of the output array.
Providers Features
-
Added the ability to set the
dt
property ofGenericBackendV2
in the class initializer with a newdt
argument. Example usage:from qiskit.providers.fake_provider import GenericBackendV2 backend = GenericBackendV2( num_qubits = 5, basis_gates = ["cx", "id", "rz", "sx", "x"], dt = 2.22*e-10, seed = 42 )
Quantum Information Features
-
Added a new
SparseObservable.to_sparse_list()
method to obtain a sparse list representation of aSparseObservable
. For example:from qiskit.quantum_info import SparseObservable obs = SparseObservable.from_list([("+II", 1), ("-II", 1)]) print(obs.to_sparse_list()) # [("+", [2], 1), ("-", [2], 1)]
-
Added a new
SparseObservable.as_paulis()
method to express a sparse observable in terms of Paulis only, by expanding all projectors. For example:from qiskit.quantum_info import SparseObservable obs = SparseObservable("+-") obs_paulis = obs.as_paulis() # 1/4 ( II + XI - IX - XX )
-
Qiskit v2.0.0 supports constructing a
SparsePauliOp
from aSparseObservable
by using the new methodSparsePauliOp.from_sparse_observable()
. It is important to remember thatSparseObservable
objects can efficiently represent projectors, which require an exponential number of terms in theSparsePauliOp
. -
SparseObservable
now supports operator composition using thecompose()
method, similar to otherquantum_info
classes. This is analagous to matrix multiplication, though the method is entirely matrix free. -
SparseObservable.BitTerm
has a new attribute,label
, which contains the single-character Python string used to represent the term in string labels. -
The
StabilizerState.expectation_value()
method can now accept an operator of typeSparsePauliOp
.
Synthesis Features
-
Added a new
TwoQubitControlledUDecomposer
class that decomposes any two-qubit unitary in terms of basis two-qubit fractional gates, such asRZZGate
(or two-qubit gates that are locally equivalent toRZZGate
, up to single qubit gates).For example:
from qiskit.circuit.library import RZZGate from qiskit.synthesis import TwoQubitControlledUDecomposer from qiskit.quantum_info import random_unitary unitary = random_unitary(4, seed=1) decomposer = TwoQubitControlledUDecomposer(RZZGate, euler_basis="ZXZ") circ = decomposer(unitary) circ.draw(output='mpl')
-
The
synth_cnot_depth_line_kms()
pass has been ported into Rust, with preliminary benchmarks pointing at a factor of 20x speedup. -
The
synth_cx_cz_depth_line_my()
pass has been ported into Rust, with preliminary benchmarks pointing at a factor of 70x speedup. -
Added synthesis functions
synth_integer_comparator_2s()
andsynth_integer_comparator_greedy()
to compile gates that implement an integer comparison, such asIntegerComparatorGate
. The corresponding high-level synthesis plugins areIntComparatorSynthesis2s
andIntComparatorSynthesisNoAux
. To let the compiler select the optimal decomposition based on the availably auxiliary qubits, useIntComparatorSynthesisDefault
. -
Added
synth_weighted_sum_carry()
to synthesizeWeightedSumGate
objects. This is currently the only available synthesis method forWeightedSumGate
, with the corresponding high-level synthesis pluginWeightedSumSynthesisDefault
.
Transpiler Features
-
Added support for working with
Target
objects that contain two-qubit basis gates that contain arbitrary angles, such asRZZGate
, to theConsolidateBlocks
transpiler pass. The pass previously would not correctly estimate the number of gates required for a decomposition which would result in blocks not being consolidated whereUnitarySynthesis
could potentially optimize the block. Internally, the gate count estimate is done using theTwoQubitControlledUDecomposer
class.For example:
from qiskit import QuantumCircuit from qiskit.transpiler import generate_preset_pass_manager from qiskit.transpiler.passes import ConsolidateBlocks qc = QuantumCircuit(2) qc.rzz(0.1, 0, 1) qc.rzz(0.2, 0, 1) # basis_gates contains fractional gate (rzz) consolidate_pass = ConsolidateBlocks(basis_gates=["rz", "rzz", "sx", "x", "rx"]) block = consolidate_pass(qc) # consolidate the circuit into a single unitary block block.draw(output='mpl') pm = generate_preset_pass_manager( optimization_level=2, basis_gates=["rz", "rzz", "sx", "x", "rx"] ) tqc = pm.run(qc) # synthesizing the circuit into basis gates tqc.draw(output='mpl')
-
Added support for two-qubit fractional basis gates, such as
RZZGate
, to theUnitarySynthesis
transpiler pass. The decomposition is done using theTwoQubitControlledUDecomposer
, and supports both standard and custom basis gates.For example:
from qiskit import QuantumCircuit from qiskit.quantum_info import random_unitary from qiskit.transpiler.passes import UnitarySynthesis from qiskit.converters import circuit_to_dag, dag_to_circuit unitary = random_unitary(4, seed=1) qc = QuantumCircuit(2) qc.append(unitary, [0, 1]) dag = circuit_to_dag(qc) # basis_gates contains fractional gate (rzz) circ = UnitarySynthesis(basis_gates=['rzz', 'rx', 'rz']).run(dag) dag_to_circuit(circ).draw(output='mpl')
-
Added a new transpiler pass,
LightCone
, that returns the lightcone of a circuit when measuring a subset of qubits or a specific Pauli string.For example, for the following circuit:
running the pass would eliminate the gates that do not affect the outcome:
from qiskit.transpiler.passes.optimization.light_cone import LightCone from qiskit.transpiler.passmanager import PassManager from qiskit.circuit import QuantumCircuit qc = QuantumCircuit(3,1) qc.h(range(3)) qc.cx(0,1) qc.cx(2,1) qc.h(range(3)) qc.measure(0,0) pm = PassManager([LightCone()]) new_circuit = pm.run(qc) new_circuit.draw("mpl")
-
Added a new argument
max_block_width
to theBlockCollector
class and to theCollectLinearFunctions
andCollectCliffords
transpiler passes. This argument allows you to restrict the maximum number of qubits over which a block of nodes is defined.For example:
from qiskit.circuit import QuantumCircuit from qiskit.transpiler.passes import CollectLinearFunctions qc = QuantumCircuit(5) qc.h(0) qc.cx(0, 1) qc.cx(1, 2) qc.cx(2, 3) qc.cx(3, 4) # Collects all CX-gates into a single block qc1 = CollectLinearFunctions()(qc) qc1.draw(output='mpl') # Collects CX-gates into two blocks of width 3 qc2 = CollectLinearFunctions(max_block_width=3)(qc) qc2.draw(output='mpl')
-
Added a new option,
collect_from_back
, to theCollectMultiQBlocks
transpiler pass. When set toTrue
, the blocks are collected in the reverse direction, from the outputs toward the inputs of the circuit. The blocks are still reported following the normal topological order. This leads to an additional flexibility provided by the pass, and additional optimization opportunities when combined with a circuit resynthesis method. -
Added a new
approximation_degree
argument toCommutationAnalysis
. This argument allows you to set the approximation threshold for when gates are evaluated to commute. See the class docstring for more information. -
A new transpiler pass,
ContractIdleWiresInControlFlow
, is available inqiskit.transpiler.passes
. This pass removes qubits from control-flow blocks if the semantics allow it and if the qubit remains idle throughout the control-flow operation. Previously, the routing stage of the preset pass managers could remove idle qubits as an unintended side effect of how the passes operated. Now, this behavior is properly handled as part of an optimization pass. -
A new
"default"
routing plugin stage was added. In Qiskit v2.0.0, this is simply an alias for the previous default"sabre"
. The underlying default algorithm may change over the course of the Qiskit v2.x release series for some or all targets, but you can always set explicitlyrouting_method="sabre"
to maintain the current behavior. -
Added a new
"default"
translation plugin stage. In Qiskit v2.0.0, this is an alias for the previous default"translator"
. The underlying default algorithm may change over the course of the Qiskit 2.x series for some or all targets, but you can always settranslation_method="translator"
explicitly to maintain the current behavior. -
The
HighLevelSynthesis
transpiler pass now synthesizes objects of typeAnnotatedOperation
through the plugin interface. -
PassManager.run()
now accepts aproperty_set
argument, which can be set to aMapping
-like object to provide the initial values of the pipeline’sPropertySet
. This can be used to recommence a partially applied compilation, or to reuse certain analysis from a prior compilation in a new place. -
The scheduling passes
PadDelay
andPadDynamicalDecoupling
now have new arguments on their constructors:target
anddurations
. These are used to specify theTarget
orInstructionDurations
respectively. For access to the instruction durations when the pass is run, one of the arguments is required. -
Added a new
seconds_to_dt()
method to theTarget
class. This is used to translate a duration in seconds to a number of discretized time steps of the system time resolution specified in theTarget.dt
attribute. This is typically useful for converting theInstructionProperties.duration
value to units ofdt
. -
The
Split2QUnitaries
transpiler pass has been upgraded to handle the case where the unitary in consideration can be written as aSwapGate
gate and two single-qubit gates. In this case, it splits the unitary and also applies virtual swapping, similar to what is done inElidePermutations
. This functionality can be controlled with a new argument,split_swap
, in the constructor of :class`.Split2QUnitaries`, which can be used to disable splitting swap equivalent gates.
Misc. Features
-
qiskit.utils
now contains utilities to provide better control and inspection of Qiskit’smultiprocessing
parallelization settings. In particular, one can now useshould_run_in_parallel()
to query whetherparallel_map()
(and pass managers) will launch subprocesses for suitable inputs, and use the context managershould_run_in_parallel.override()
to temporarily override most system and user configuration around this decision.An additional function,
default_num_processes()
, reads the default maximum number of subprocesses that Qiskit will use for process-based parallelism. -
A new environment variable,
QISKIT_IGNORE_USER_SETTINGS
, now controls whether to read the user settings file onimport qiskit
. If set to the stringtrue
, the settings file will not be read. This is useful for isolating certain instances of Qiskit from the system environment, such as for testing.
Upgrade Notes
-
Qiskit v2.0 has dropped support for Linux i686 and 32-bit Windows. Starting in Qiskit v2.0.0, a 64-bit platform is required to run Qiskit. This aligns with the trend in the scientific Python community and allows Qiskit to focus on performance improvements for increasingly complex quantum computing hardware.
Qiskit v1.4 will continue to support 32-bit platforms until end-of-life (September 2025), but starting in this 2.0.0 release, Qiskit will no longer publish pre-compiled binaries for them, and offers no guarantee of successful source builds on 32-bit platforms.
-
The minimum supported Rust version for building Qiskit from source is now v1.79. This has been raised from v1.70, the previous minimum supported Rust version in the Qiskit v1.x release series.
-
Qiskit Pulse has been completely removed in this release, following its deprecation in Qiskit v1.3. This includes all pulse module files, pulse visualization functionality, support for
ScheduleBlock
and pulse-gate serialization and deserialization in QPY, calibrations management inQuantumCircuit
,Target
andDAGCircuit
, and pulse-based fake backends. For more details about the removed components related to pulse, see the corresponding sections below.Note that Pulse migration to Qiskit Dynamics, as was the initial plan following the deprecation of Pulse, has been put on hold due to Qiskit Dynamics development priorities. Users wanting to use Qiskit Pulse as a frontend to supporting backends or in other uses cases can still use it in Qiskit versions prior to v2.0.0, which include pulse functionality.
-
The functions
sequence
andschedule
from thecompiler
module have been removed following their deprecation in Qiskit v1.3. They relied on being able to translate circuits to pulse components using backend definitions, a capability that is no longer present. For this reason they have been removed with no proposed alternative. Note that these removals relate to the Pulse package, which is also being removed in Qiskit 2.0.
Circuits Upgrade Notes
-
Bit
andRegister
as well as their subclassess are no longer guaranteed to be comparable usingis
checks, due to conversions to and from Python which may re-allocate each instance exposed to Python. -
Bit
andRegister
(and their subclasses) can no longer be subclassed. This was never intended to be supported behavior, and doing so would cause unspecified behavior in Qiskit. It is no longer possible to do this as an implementation detail of the classes. -
It is no longer possible to create instances of the base
Bit
andRegister
classes. Directly instantiating these classes was clearly documented as something that was not supported, and being able to do it was was just an implementation artifact of the class hierarchy in previous releases. Starting in Qiskit v2.0.0, it is no longer possible to do this. -
The
qiskit.circuit.classicalfunction
module has been removed following its deprecation in Qiskit v1.4. That includes theClassicalFunction
class, its relatedclassical_function
function, and theBooleanExpression
class. This change was made to remove the dependency on thetweedledum
library, which is no longer compatible with all of Qiskit’s supported platforms and Python versions.ClassicalFunction
was exclusively used inPhaseOracle
, which has been upgraded to only accept expressions instring
format (see following release note).BooleanExpression
has been superseded by the newBitFlipOracleGate
class. -
The
PhaseOracle
class no longer depends on thetweedledum
library, as the dependency is not actively maintained. The interface has been simplified: it no longer accepts asynthesizer
parameter, and theexpression
parameter can only be a string. The previously acceptedClassicalFunction
type, deprecated in Qiskit v1.4, has been removed in Qiskit v2.0.Despite these upgrades, the standard usage of the
PhaseOracle
class remains unchanged:from qiskit.circuit.library.phase_oracle import PhaseOracle bool_expr = "(x0 & x1 | ~x2) & x4" oracle = PhaseOracle(bool_expr) oracle.draw('mpl')
Note that this change may affect synthesis effectiveness, but was required for compatibility with all of Qiskit’s supported platforms and Python versions.
-
Updated the metric used to check commutations in
CommutationChecker
. Two gates are assumed to commute if the average gate fidelity of the commutation is above(1 - 1e-12)
. This value is chosen to account for round-off errors in the fidelity calculation and for consistency withRemoveIdentityEquivalent
andTwoQubitWeylDecomposition
. See the class docstring for more information. -
The method
QuantumCircuit.measure_active()
has changed the name of the classical register it creates, as the previous name conflicted with anOpenQASM
reserved word. Instead ofmeasure
, it is now calledmeas
, aligning with the register name used bymeasure_all()
. -
The
DAGCircuit.control_flow_op_nodes()
method has been updated to always return a list, even if it is empty. Previously, it returnedNone
if it was empty, and never returned an empty list, which required special handling. If you need to explicitly test for emptiness in both Qiskit v1.x and v2.x, you can do:control_flow_nodes = dag.control_flow_op_nodes() if not control_flow_nodes: # There are no control-flow nodes. pass
-
BlueprintCircuit.copy_empty_like()
now returns an emptyQuantumCircuit
with the same number of qubits and clbits, and the same metadata as the original circuit, instead of aBlueprintCircuit
. This change addresses unexpected behavior where dealing with an “empty” copy of a blueprint circuit would cause the circuit data to be rebuilt. Note thatBlueprintCircuit.copy()
still returns aBlueprintCircuit
. WhileBlueprintCircuit
is not a public class as it’s an internal type used for building legacy entries inqiskit.circuit.library
this impacts its subclasses such asNLocal
andZZFeatureMap
. Refer to theqiskit.circuit.library
for a complete list of the classes impacted by this change. Fixed #13535 -
The internal function
qiskit.circuit.add_control.add_control
has been removed. This function was not part of the public API, it had fragile preconditions to uphold and was a common source of bugs. Uses ofadd_control(SomeGate(...), ...)
should change toSomeGate(...).control(...)
usingGate.control()
instead, which is far safer. -
The
ParameterExpression.sympify()
method can now raise aMissingOptionalLibrary
exception ifsympy
is not installed. In the Qiskit v1.x releases,sympy
was always guaranteed to be installed, but starting in v2.0.0, this is no longer a hard requirement and may only be needed if you are using this method. Because this functionality explicitly requiressympy
you need to ensure you havesympy
installed to use the method. -
The deprecated
DAGNode
dag
argument has been removed from theDAGNode
class and its subclasses:DAGOpNode
,DAGOutNode
, andDAGInNode
.The
dag
parameter was an optional argument when constructing these objects, but it has been unused and ignored since the v1.3 release, and deprecated since the v1.4 release. -
The following
QuantumCircuit
methods:cast
cbit_argument_conversion
cls_instances
cls_prefix
qbit_argument_conversion
have been removed, following their deprecation in Qiskit 1.2. These methods were internal helper functions, and never intended to be public API. No replacement is provided.
-
The deprecated attributes for
Instruction
andGate
:duration
andunit
have been removed, so you can no longer set theunit
orduration
arguments for anyqiskit.circuit.Instruction
or subclass. These attributes were deprecated in Qiskit v1.3.0 and were used to attach a custom execution duration and unit for that duration to an individual instruction. However, the source of truth of the duration of a gate is theBackendV2
Target
, which contains the duration for each instruction supported on the backend. The duration of an instruction is not typically user adjustable and is an immutable property of the backend. If you previously used this capability to experiment with different gate durations, you can mutate theInstructionProperties.duration
field in a givenTarget
to set a custom duration for an instruction on a backend. (The unit is always in seconds in theTarget
.) -
The deprecated attribute for
qiskit.circuit.Instruction
andGate
:condition
has been removed. This functionality has been superseded by theIfElseOp
class, which can be used to describe a classical condition in a circuit. This attribute was deprecated in the v1.3.0 release. -
The deprecated methods for
Instruction
andGate
:c_if
andcondition_bits
have been removed. These methods were deprecated in the v1.3.0 release. This functionality has been superseded by theIfElseOp
class, which can be used to describe a classical condition in a circuit. For example, a circuit previously usingInstruction.c_if()
like:from qiskit.circuit import QuantumCircuit qc = QuantumCircuit(2, 2) qc.h(0) qc.x(0).c_if(0, 1) qc.z(1.c_if(1, 0) qc.measure(0, 0) qc.measure(1, 1)
can be rewritten as:
qc = QuantumCircuit(2, 2) qc.h(0) with expected.if_test((expected.clbits[0], True)): qc.x(0) with expected.if_test((expected.clbits[1], False)): qc.z(1) qc.measure(0, 0) qc.measure(1, 1)
-
The deprecated method
InstructionSet.c_if
has been removed. This method was deprecated in the 1.3.0 release. This functionality has been superseded by theIfElseOp
class which can be used to describe a classical condition in a circuit. -
As part of Pulse removal in Qiskit v2.0.0, the
calibrations
property has been removed from theQuantumCircuit
,DAGCircuit
andDAGDependency
classes. In addition to this, the methodhas_calibration_for
has been removed from theQuantumCircuit
andDAGCircuit
classes, andadd_calibration
has been removed fromQuantumCircuit
. -
The
qiskit.circuit.classicalfunction
module has been removed. This module was dependent on thetweedledum
library which is not compatible with newer versions of Python. As an alternative, thePhaseOracleGate
andBitFlipOracleGate
classes can be used to generate circuits from boolean expressions. -
The internal representation of
UnitaryGate
when added to aQuantumCircuit
has changed. The object stored in the circuit will not necessarily share a common reference to the object added to the circuit anymore. This behavior was never guaranteed, and mutating theUnitaryGate
object directly or by reference was always unsound and likely to corrupt the circuit, especially when modifying the matrix. If you need to mutate an element in the circuit (which is not recommended as it’s inefficient and error prone), do something like:from qiskit.circuit import QuantumCircuit from qiskit.quantum_info import random_unitary from qiskit.circuit.library import UnitaryGate import numpy as np qc = QuantumCircuit(2) qc.unitary(np.eye(2, dtype=complex)) new_op = UnitaryGate(random_unitary(2)) qc.data[0] = qc.data[0].replace(operation=new_op)
This also applies to
DAGCircuit
, but you can useDAGCircuit.substitute_node()
instead. -
The
CircuitInstruction.params
attribute for aCircuitInstruction
that contains anUnitaryGate
for itsoperation
will no longer contain the underlying unitary matrix for the gate. This is because the internal representation of the gate no longer treats the matrix object as a parameter. If you need to access the matrix of the gate you can do this either via theCircuitInstruction.matrix
or theUnitaryGate.params
field of theCircuitInstruction.operation
.
Primitives Upgrade Notes
-
As a consequence of the removal of the
BackendV1
model, theBackendSamplerV2
andBackendEstimatorV2
classes no longer accept inputs of typeBackendV1
in theirbackend
input argument. -
Primitive V1 implementations and V1-exclusive non-versioned type aliases, deprecated in Qiskit v1.2, have been removed. These interfaces have been superseded by their V2 counterparts. The removal includes the following classes implementing V1 interfaces:
Estimator
, in favor of the V2 equivalent,StatevectorEstimator
Sampler
, in favor of the V2 equivalent,StatevectorSampler
BackendEstimator
, in favor of the V2 equivalent,BackendEstimatorV2
BackendSampler
, in favor of the V2 equivalent,BackendSamplerV2
As well as the following non-versioned type aliases:
BaseEstimator
, alias forBaseEstimatorV1
BaseSampler
, alias forBaseSamplerV1
This removal does NOT affect the explicitly-versioned
BaseEstimatorV1
andBaseSamplerV1
abstract interface definitions or related result and job classes, which have been kept to maintain backwards compatibility. If you are using a non-versioned V1-type alias such asBaseEstimator
, you can directly replace it with the versioned type (BaseEstimatorV1
).Additionally, the following utility functions have been removed. These functions were only used in Primitive V1 implementations:
init_circuit
: to initialize a circuit from aStatevector
, useQuantumCircuit.initialize()
instead.init_observable
: use the constructor ofSparsePauliOp
instead.final_measurement_mapping
: useQuantumCircuit.layout()
andSparsePauliOp.apply_layout()
to adjust an operator for a layout. Otherwise, usemthree.utils.final_measurement_mapping
. See Mthree Utility functions for details.
Providers Upgrade Notes
-
The
configuration
method ofBasicSimulator
has been removed following its deprecation in Qiskit v1.3. This method returned aBackendConfiguration
instance, a class that was part of the discontinuedBackendV1
workflow and is also removed in Qiskit v2.0.0. The individual configuration elements can now be retrieved directly from the backend or from the containedTarget
instance (backend.target
). -
The
run_experiment
method ofBasicSimulator
has been removed. This method took an instance of theQasmQobjExperiment
class as an input argument, a class that has been deprecated since Qiskit v1.2 and was removed with theQobj
workflow in Qiskit v2.0.0. -
The
BackendV1
model has been removed following its deprecation in Qiskit 1.2.0. This includes theBackendV1
class as well as related modules and utils, as they have been superseded by theBackendV2
model. The list of removed items includes:-
BackendV1
class: the core of the removed model -
All elements in
qiskit/providers/models
, as they were used to represent components of theBackendV1
model:BackendConfiguration
BackendProperties
BackendStatus
QasmBackendConfiguration
PulseBackendConfiguration
UchannelLO
GateConfig
PulseDefaults
PulseQobjDef
Command
GateProperties
Nduv
JobStatus
: This class has been superseded by the more widely usedJobStatus
PulseDefaults
-
BackendV2Converter
class: used to convert fromBackendV1
toBackendV2
-
convert_to_target
function: used to build aTarget
instance from legacyBackendV1
components (such asBackendConfiguration
orBackendProperties
) -
BackendPropertyError
andBackendConfigurationError
: exceptions linked to removed classes
-
-
The
BasicSimulator
backend can no longer simulate classical control flow. It only supported using the.c_if()
/.condition
for modeling control flow, but this construction has now been removed from the Qiskit data model. -
All fake backend classes based on the deprecated
BackendV1
have been removed from theproviders.fake_provider
module. These classes have been deprecated since Qiskit 1.2 and were part of the deprecatedBackendV1
workflow. Their use in tests has been replaced with theGenericBackendV2
class, which allows to create custom instances ofBackendV2
that implement a simulatedBackendV2.run()
. The removal affects:-
Base classes:
FakeBackend
FakePulseBackend
FakeQasmBackend
-
Fake backends for special testing purposes:
Fake1Q
FakeOpenPulse2Q
FakeOpenPulse3Q
-
Legacy fake backends:
Fake5QV1
Fake20QV1
Fake7QPulseV1
Fake27QPulseV1
Fake127QPulseV1
-
-
As part of pulse removal in Qiskit v2.0.0, the following methods have been removed:
qiskit.providers.BackendV2.instruction_schedule_map
qiskit.providers.BackendV2.drive_channel
qiskit.providers.BackendV2.measure_channel
qiskit.providers.BackendV2.acquire_channel
qiskit.providers.BackendV2.control_channel
-
As part of pulse removal in Qiskit v2.0.0, pulse support has been removed from
GenericBackendV2
. This includes the ability to initialize the backend with custom calibrations (calibrate_instructions
argument) and pulse channel attributes (drive_channel
,measure_channel
,acquire_channel
,control_channel
). -
Removed the abstract base classes
Provider
andProviderV1
, which have been deprecated since Qiskit v1.1.0. The abstraction provided by these interface definitions was not offering significant value, only including the attributesname
,backends
, and aget_backend()
method.A rovider, as a concept, will continue existing as a collection of backends. If you’re currently implementing a provider, you can adjust your code by simply removing
ProviderV1
as the parent class of your implementation.As part of this change, you will likely want to add an implementation of
get_backend
for backwards compatibility. For example:def get_backend(self, name=None, **kwargs): backend = self.backends(name, **kwargs) if len(backends) > 1: raise QiskitBackendNotFoundError("More than one backend matches the criteria") if not backends: raise QiskitBackendNotFoundError("No backend matches the criteria") return backends[0]
QPY Upgrade Notes
-
The
qpy.load()
function can now raise aMissingOptionalLibrary
exception if a QPY v10, v11, or v12 payload is passed in that usessymengine
symbolic expressions andsymengine
is not installed. The exception is also raised ifsympy
is not installed for any other QPY payload prior to v13. In the Qiskit v1.x releases,symengine
andsympy
were always guaranteed to be installed. However, starting in v2.x this is no longer a hard requirement and may only be needed if you’re deserializing a QPY file that was generated usingsymengine
. Parsing these QPY payloads requiressymengine
as its usage is part of the format specification for QPY v10, v11, and v12. If the payload requires it, installing a compatible version ofsymengine
(0.11.0
or0.13.0
) is the only option. Similarly,sympy
was was used forParameterExpression
encoding for all QPY versions 1 - 12. -
The minimum QPY compatibility version,
QPY_COMPATIBILITY_VERSION
, has been raised from 10 (the v1.x release requirement) to 13. This version controls the minimum version of QPY that can be emitted by theqpy.dump()
function. This means thatqpy.dump()
can only emit QPY v13 and v14 in this release. QPY v13 is still compatible with Qiskit v1.3.x and v1.4.x, which means that payloads generated in Qiskit v2.x with QPY v13 can still be loaded with the Qiskit v1.x release series.This change was necessary because QPY versions 10 -12 require either the
sympy
orsymengine
libraries to generate a serialization forParameterExpression
objects, but in Qiskit 2.x neither library is required for theParameterExpression
object. -
With the removal of pulse in Qiskit v2.0.0, support for serializing
ScheduleBlock
programs through theqiskit.qpy.dump()
function has been removed. Users can still load payloads containing pulse gates by using theqiskit.qpy.load()
function, however, they will be treated as opaque custom instructions. LoadingScheduleBlock
payloads is not supported anymore and will cause aQpyError
exception.
Synthesis Upgrade Notes
-
The
atomic_evolution
callable argument ofProductFormula
(and its subclassesQDrift
,LieTrotter
, andSuzukiTrotter
) has a new function signature. The old signature would take some Pauli operator and time coefficient and return the evolution circuit:def atomic_evolution(pauli_op: SparsePauliOp, time: float) -> QuantumCircuit: evol_circuit = QuantumCircuit(pauli_op.num_qubits) # append operators to circuit return evol_circuit
The new signature directly takes in an existing circuit and should append the evolution of the provided Pauli and given time to this circuit:
def atomic_evolution(evol_circuit: QuantumCircuit, pauli_op: SparsePauliOp, time: float): # append operators to circuit, in-place modification
This new implementation benefits from significantly better performance.
Transpiler Upgrade Notes
-
Increased the minimum threshold for when gates are assumed to be the identity in
RemoveIdentityEquivalent
from machine epsilon to1e-12
to account for round-off errors in the fidelity calculation and for consistency with the other classes, such asCommutationAnalysis
andTwoQubitWeylDecomposition
. -
The routing plugin stage name
default
is now reserved for the Qiskit built-in plugin of the same name. -
The default routing plugin stage is now
"default"
. In Qiskit v2.0.0, this is simply an alias for the previous default"sabre"
. The underlying default algorithm may change over the course of the Qiskit v2.x release series for some or all targets, but you can always explicitly setrouting_method="sabre"
to maintain the current behavior. -
The translation plugin stage name
default
is now reserved for the Qiskit built-in plugin of the same name. -
The default translation plugin stage is now
"default"
. In Qiskit 2.0, this is simply an alias for the previous default"translator"
. The underlying default algorithm may change over the course of the Qiskit 2.x series for some or all targets, but you can always settranslation_method="translator"
explicitly to maintain the current behavior. -
The legacy scheduling passes
ASAPSchedule
,ALAPSchedule
,DynamicalDecoupling
, andAlignMeasures
have been removed in favor of the updated alternativesALAPScheduleAnalysis
,ASAPScheduleAnalysis
,PadDynamicalDecoupling
, andConstrainedReschedule
respectively. These were deprecated in Qiskit v1.1 after the new scheduling workflow superseded the legacy one. -
In the case that neither a
target
nor a set ofbasis_gates
are specified, theHighLevelSynthesis
transpiler pass synthesizes circuits with annotated operations with fewer layers of wrappings than before (this happens, for instance, for the circuit produced bymultiplier_cumulative_h18()
). -
The keyword argument
property_set
is now reserved inBasePassManager.run()
, and cannot be used as akwarg
that will be forwarded to the subclass’ conversion from the front-end representation to the internal representation. -
The following deprecated uses of the
BackendProperties
object in the transpilation pipeline have been removed in Qiskit 2.0:backend_properties
input argument intranspile()
backend_properties
input argument inPassManagerConfig
backend_properties
input argument ingenerate_preset_pass_manager()
backend_properties
input argument ingenerate_routing_passmanager()
backend_properties
input argument ingenerate_translation_passmanager()
backend_properties
input argumentTarget.from_configuration()
The following passes have also been updated to only accept a
target
instead of:backend_prop
input argument inDenseLayout
properties
input argument inVF2Layout
properties
andcoupling_map
input arguments inVF2PostLayout
backend_props
input argument inUnitarySynthesis
The
BackendProperties
class has been deprecated since Qiskit v1.2, because it was part of theBackendV1
workflow. Specific instruction properties, such as gate errors or durations can be added to aTarget
upon construction through theTarget.add_instruction()
method, and communicated to the relevant transpiler passes through thetarget
input argument. -
As a consequence of the removal of the
BackendV1
model, the accepted input types of the following transpiler objects have been updated:- The
generate_preset_pass_manager()
andtranspile()
functions no longer accept inputs of typeBackendV1
in theirbackend
input argument. - The
Target.from_configuration()
method no longer accepts abackend_properties
argument - The
Target.target_to_backend_properties()
method has been removed
- The
-
The
ResetAfterMeasureSimplification
transpiler pass now uses anIfElseOp
to condition the execution of theXGate
instead of setting acondition
attribute on the gate. This is because thecondition
attribute has been removed from the Qiskit data model. -
The deprecated
ConvertConditionsToIfOps
transpiler pass has been removed. The underlyingcondition
attribute ofInstruction
class has been removed so this transpiler pass no longer had anything to convert from. Instead you should directly useIfElseOp
to classically condition the execution of an operation. -
The
PadDelay
andPadDynamicalDecoupling
transpiler passes now require a new argument when constructed. Eithertarget
ordurations
need to be specified with aTarget
orInstructionDurations
respectively. Without these, the passes cannot determine the duration of instructions in the circuit and will error. Previously these passes determined these values from the now removedduration
attribute ofInstruction
objects. -
The previously deprecated
AlignMeasures
transpiler pass has been removed. This pass was deprecated in Qiskit v1.1.0. Instead, theConstrainedReschedule
pass should be used.ConstrainedReschedule
performs the same function and also supports aligning to additional timing constraints. -
When scheduling by using
generate_preset_pass_manager()
ortranspile()
, if theinstruction_durations
argument is specified, the durations are formatted as alist
, and they are in units ofdt
. You must also set thedt
input argument of the transpilation function. -
Removed the deprecated
DAGNode.sort_key
attribute. This attribute was deprecated in the Qiskit v1.4.0 release. As the lexicographical topological sorting is done internally in Rust and the sort key attribute was unused, this attribute was removed to avoid the overhead from DAG node creation. If you relied on the sort key, you can reproduce it from a given node using something like:def get_sort_key(node: DAGNode): if isinstance(node, (DAGInNode, DAGOutNode)): return str(node.wire) return ",".join( f"{dag.find_bit(q).index:04d}" for q in itertools.chain(node.qargs, node.cargs) )
-
The following
transpile()
andgenerate_preset_pass_manager()
input arguments, deprecated since Qiskit 1.3 , have been removed from the API:instruction_durations
timing_constraints
In addition to this, the specification of custom basis gates through the
basis
gate argument oftranspile()
andgenerate_preset_pass_manager()
, also deprecated in Qiskit 1.3, is no longer allowed, and aValueError
will be raised in these cases.The information formerly provided through these can still be specified via the
backend
ortarget
arguments. You can build a Target instance with defined instruction durations doing:Target.from_configuration(..., instruction_durations=...)
For specific timing constraints:
Target.from_configuration(..., timing_constraints=...)
And for custom basis gates, you can manually add them to the target or use
.from_configuration
with a custom name mapping, for example:from qiskit.circuit.library import XGate from qiskit.transpiler.target import Target basis_gates = ["my_x", "cx"] custom_name_mapping = {"my_x": XGate()} target = Target.from_configuration( basis_gates=basis_gates, num_qubits=2, custom_name_mapping=custom_name_mapping )
-
The
transpile()
andgenerate_preset_pass_manager()
interfaces now raise aUserWarning
when providing acoupling_map
and/orbasis_gates
along with abackend
. In these cases there are multiple sources of truth, the user intentions are not always clear, and there can be conflicts thatgenerate_preset_pass_manager()
may not know how to resolve. The suggested alternative is to define a custom target that combines the chosen constraints.One of these situations is the specification of a gate with 3 or more qubits in
backend
orbasis_gates
together with a customcoupling_map
. The coupling map does not provide the necessary connectivity details to be able to determine the action of the gate. In these cases,transpile()
andgenerate_preset_pass_manager()
now raise aValueError
. -
As part of Pulse removal in Qiskit 2.0, all pulse and calibration related functionality in the transpiler have been removed.
The following passes and functions have been removed:
qiskit.transpiler.passes.PulseGates
passqiskit.transpiler.passes.ValidatePulseGates
passqiskit.transpiler.passes.RXCalibrationBuilder
passqiskit.transpiler.passes.RZXCalibrationBuilder
passqiskit.transpiler.passes.RZXCalibrationBuilderNoEcho
passqiskit.transpiler.passes.EchoRZXWeylDecomposition
passqiskit.transpiler.passes.NoramlizeRXAngle
passqiskit.transpiler.passes.rzx_templates()
function
The
inst_map
argument has been removed from the following elements:- The
generate_preset_pass_manager()
andtranspile()
functions - The
Target.from_configuration()
method - The constructor of the
PassManagerConfig
class
Calibration support has been removed:
calibration
has been removed from theInstructionProperties
constructor and is no longer a property of that class.- The
has_calibration
,get_calibration
,instruction_schedule_map
andupdate_from_instruction_schedule_map
methods have been removed from theTarget
class.
-
The deprecated
StochasticSwap
transpiler pass, and its associated built-in routing stage plugin “stochastic”, have been removed. These were marked as deprecated in the Qiskit v1.3.0 release. The pass has been superseded by theSabreSwap
class, which should be used instead, as it offers better performance and output quality. For example, if the pass was previously invoked through the transpile function, such as:from qiskit import transpile from qiskit.circuit import QuantumCircuit from qiskit.transpiler import CouplingMap from qiskit.providers.fake_provider import GenericBackendV2 qc = QuantumCircuit(4) qc.h(0) qc.cx(0, range(1, 4)) qc.measure_all() cmap = CouplingMap.from_heavy_hex(3) backend = GenericBackendV2(num_qubits=cmap.size(), coupling_map=cmap) tqc = transpile( qc, routing_method="stochastic", layout_method="dense", seed_transpiler=12342, target=backend.target )
this should be replaced with:
tqc = transpile( qc, routing_method="sabre", layout_method="dense", seed_transpiler=12342, target=backend.target )
-
The
qiskit.transpiler.passes.CXCancellation
pass has been removed. It was deprecated in favor of class:.InverseCancellation, which is more generic.CXCancellation()
is fully semantically equivalent toInverseCancellation([CXGate()])
. -
The
SolovayKitaev
transpiler pass no longer raises an exception on circuits that contain single-qubit operations without ato_matrix
method (such as measures, barriers, and control-flow operations) or parameterized single-qubit operations, but will leave them unchanged. -
Plugins for the translation stage of the preset pass managers are now required to respect
Target
gate directionality in their output. Previously,transpile()
andgenerate_preset_pass_manager()
would generate aPassManager
that contained fix-up passes if needed. You must now include these in your own custom stage, if your stage does not guarantee that it respects directionality.You can use the
GateDirection
pass to perform the same fix-ups that Qiskit used to do. For example:from qiskit.transpiler import PassManager from qiskit.transpiler.passes import GateDirection from qiskit.transpiler.preset_passmanagers.plugin import PassManagerStagePlugin class YourTranslationPlugin(PassManagerStagePlugin): def pass_manager(self, pass_manager_config, optimization_level): pm = PassManager([ # ... whatever your current setup is ... ]) # Add the two-qubit directionality-fixing pass. pm.append(GateDirection( pass_manager_config.coupling_map, pass_manager_config.target, )) return pm
-
The preset pass managers no longer populates the implicit
pre_optimization
stage of their outputStagedPassManager
. You can now safely assign your ownPassManager
to this field. You could previously only append to the existingPassManager
. -
The default value for the
generate_routing_passmanager()
argumentseed_transpiler
has changed fromNone
to-1
. This change was made because this flag was only used to configure theVF2PostLayout
transpiler pass, and for that pass, the randomization typically degrades performance and is not desirable. If you relied on the previous default value, you can restore this behavior by explicitly setting the argumentseed_transpiler=None
. If you were explicitly setting a seed value for this parameter, there is no change in behavior.
Visualization Upgrade Notes
-
The
idle_wires
parameter in all circuit drawers has been extended with a new option,"auto"
, which is now the default behavior. If you still want to display wires without instructions, explicitly setidle_wires=True
.When set to
"auto"
, the behavior is as follows:- If the circuit has a defined
.layout
attribute,idle_wires
is automatically set toFalse
(hiding idle wires) - Otherwise,
idle_wires
remainsTrue
(showing all wires, as was the previous default)
The following example shows a circuit without a layout displayed by using
idle_wires="auto"
:qr_0: ──────── ┌───┐┌─┐ qr_1: ┤ H ├┤M├ └───┘└╥┘ cr_0: ══════╬═ ║ cr_1: ══════╩═
Once a layout is applied,
idle_wires="auto"
setsidle_wires
toFalse
, hiding idle wires:┌───┐┌─┐ qr_1 -> 1 ┤ H ├┤M├ └───┘└╥┘ cr_1: ══════╩═
If you want to display all wires in a laid-out circuit, set
idle_wires=True
explicitly:qr_0 -> 0 ──────── ┌───┐┌─┐ qr_1 -> 1 ┤ H ├┤M├ └───┘└╥┘ ancilla_0 -> 2 ──────╫─ ║ cr_0: ══════╬═ ║ cr_1: ══════╩═
As quantum computers scale to more qubits, even small circuits can produce large circuit representations after transpilation. The
"auto"
setting helps improve readability by hiding unnecessary wires when possible. - If the circuit has a defined
-
The
array_to_latex()
function andOperator.draw()
method can now raise aMissingOptionalLibrary
exception if thesympy
library is not installed. In the Qiskit v1.x releases,symengine
andsympy
were always guaranteed to be installed, but starting in v2.0.0, this is no longer a hard requirement. The LaTeX visualization for a matrix relies on thesympy
library, so if you’re using this functionality, ensure that you havesympy
installed. -
As a consequence of the removal of the
BackendV1
model, theplot_gate_map()
,plot_error_map()
andplot_circuit_layout()
functions no longer accept inputs of typeBackendV1
in theirbackend
input argument. -
The timeline drawer now requires that the
target
argument is specified when called. As instructions no longer contain duration attributes, this extra argument is required to specify the durations for all the supported instructions. Without the argument, the timeline drawer does not have access to this information. -
As part of the Pulse removal in Qiskit 2.0, support for pulse drawing via
qiskit.visualization.pulse_drawer
has been removed.
Misc. Upgrade Notes
-
The
deprecate_function
anddeprecate_arguments
decorators, deprecated since Qiskit v0.24 (May 2023), have been removed in Qiskit v2.0.0. The currentdeprecate_func()
replaces@deprecate_function
and the currentdeprecate_arg()
replaces@deprecate_arguments
. -
The
assemble
function and related capabilities (contained in theassembler
module) have been removed from the codebase following their deprecation in Qiskit v1.2.assemble
was used to generate aQobj
in the context of the deprecatedBackendV1
workflow. The conversion is no longer necessary, as the transpilation and primitives pipeline handles quantum circuits directly, rendering theQobj
obsolete.The removal includes the following public API components:
qiskit.compiler.assemble
functionqiskit.assembler.assemble_circuits
functionqiskit.assembler.assemble_schedules
functionqiskit.assembler.disassemble
functionqiskit.assembler.RunConfig
classqiskit.circuit.Instruction.assemble
method
-
The
Qobj
structure and related classes, deprecated in Qiskit v1.2.0, have been removed. They were introduced as part of theBackendV1
workflow and are no longer necessary for interacting withBackendV2
backends. This removal affects the following classes:QobjExperimentHeader
QobjHeader
QasmQobj
QasmQobjInstruction
QasmQobjExperimentConfig
QasmQobjExperiment
QasmQobjConfig
QasmExperimentCalibrations
GateCalibration
PulseQobj
PulseQobjInstruction
PulseQobjExperimentConfig
PulseQobjExperiment
PulseQobjConfig
QobjMeasurementOption
PulseLibraryItem
-
The
MeasLevel
andMeasReturnType
classes, previously defined inqobj/utils.py
, have been migrated toresult/models.py
following the removal of theqobj
module. These classes were not part of the public API. The import path has been updated from:from qiskit.qobj.utils import MeasLevel, MeasReturnType
to:from qiskit.result import MeasLevel, MeasReturnType
. -
The use of positional arguments in the constructor of
Result
has been disabled. Please set all arguments using kwarg syntax, i.e:Result(backend_name="name", ....)
. In addition to this, theqobj_id
argument will no longer be used in the construction of theResult
internals. It is still possible to setqobj_id
as a generic kwarg, which will land in the metadata field with the other generic kwargs. -
As part of pulse removal in Qiskit 2.0.0, the
sequence
andschedule_circuit
functions fromqiskit.scheduler
together with theScheduleConfig
class have been removed. -
The
qiskit.result.mitigation
module has been removed following its deprecation in Qiskit v1.3. The removal includes theLocalReadoutMitigator
andCorrelatedReadoutMitigator
classes as well as the associated utils. There is no alternative path in Qiskit, as their functionality had been superseded by the`mthree
addon. <https://github.com/Qiskit/qiskit-addon-mthree>`__
Circuits Deprecations
-
The deprecated
QuantumCircuit.duration
attribute was not removed in this release as originally planned. It will be removed as part of the Qiskit v3.0.0 release instead. This functionality has been superseded by theQuantumCircuit.estimate_duration()
method, which should be used instead. -
The deprecated tuple-like interface for
CircuitInstruction
was not removed in this release as originally planned. It will be removed in Qiskit v3.0.0 instead. Instead, use theoperation
,qubits
, andclbits
named attributes. -
The Multiple-Control-Multiple-Target circuit class
MCMT
is now deprecated and was replaced byMCMTGate
, which is a properGate
subclass. Using a gate instead of a circuit allows the compiler to reason about the object at a higher level of abstraction and allows multiple synthesis plugins to be applied.
Transpiler Deprecations
-
The deprecated
DAGCircuit.duration
attribute was not removed in this release as originally planned. It will be removed as part of the Qiskit v3.0.0 release instead. This functionality has been superseded by theQuantumCircuit.estimate_duration()
method, which should be used instead. -
The
propagate_condition
argument ofDAGCircuit.substitute_node()
andDAGCircuit.substitute_node_with_dag()
has been deprecated. With the removal ofInstruction.condition
from the Qiskit data model this option no longer serves a purpose. If it is set it no longer has any effect. It is not removed from the signature to maintain compatibility during the migration from Qiskit 1.x -> 2.0. This option will be removed in Qiskit 3.0. -
The function
generate_pre_op_passmanager()
is deprecated. It is no longer used in the Qiskit preset pass managers, and its purpose is defunct; it originally generated a fix-up stage for translation plugins that did not respect ISA directionality. Translation stages are now required to respect directionality, so the functionality is not needed, and most likely, no replacement is required.
Security Issues
- Fixed a security vulnerability in
qpy.load()
when loading payloads that usesympy
to serializeParameterExpression
objects and other symbolic expressions. This potentially includes any QPY payload using QPY version < 10, and optionally 10, 11, and 12 depending on the symbolic encoding used in the serialization step (qpy.dump()
).
Bug Fixes
-
Fixed an inconsistency in the transpilation process when handling close-to-identity gates, where these gates were evaluated to commute with everything by
CommutationAnalysis
, but not removed byRemoveIdentityEquivalent
. The underlying issue was caused byRemoveIdentityEquivalent
andCommutationAnalysis
(and, by extension,CommutativeInverseCancellation
) using different metrics. Both now use the average gate fidelity and the same threshold to assess whether a gate should be treated as identity (such as a rotation gate with very small angle). See the docstrings of these classes for more information. Fixed #13547. -
Fixed a bug in
QuantumCircuit.assign_parameters()
, which occurred when assigning parameters to standard gates whose definition had already been triggered. In this case, the new values were not properly propagated to the gate instances. While the circuit itself was still compiled as expected, inspecting the individual operations would still show the old parameter.For example:
from qiskit.circuit.library import EfficientSU2 circuit = EfficientSU2(2, flatten=True) circuit.assign_parameters([1.25] * circuit.num_parameters, inplace=True) print(circuit.data[0].operation.params) # would print θ[0] instead of 1.25
Fixed #13478.
-
Fixed a bug in
DAGCircuit
that would cause outputVar
nodes to become input nodes duringdeepcopy
and pickling. -
Fixed an oversight in the
Target
class where setting a new value for thedt
attribute and subsequently callingtarget.durations()
would not show the updateddt
value in the returnedInstructionDurations
object. This is now fixed through an invalidation of the internal target instruction durations cache in thedt
setter. -
Fixed a problem in the
BasisTranslator
transpiler pass where the global phase of the DAG was not updated correctly. Fixed #14074. -
Fixed a bug in the
HighLevelSynthesis
transpiler pass, where it would synthesize any instruction for which a synthesis plugin is available, regardless of whether the instruction is already supported by the target or a part of the explicitly passedbasis_gates
. This behavior is now fixed, so that such already supported instructions are no longer synthesized. -
The
InverseCancellation
transpilation pass now runs inside of control-flow blocks. Previously, it ignored pairs of gates that could be cancelled when they were defined within classical blocks. Refer to #13437 for more details. -
Fixed a bug with multi-controlled rotations where the rotation angle was a
ParameterExpression
. Attempting synthesis in this case would lead to an error stating that the gate cannot be synthesized with an unbound parameter. This bug affected multi-controlled rotation circuit methodsQuantumCircuit.mcrx()
, :meth:.QuantumCircuit.mcry, andQuantumCircuit.mcrz()
, as well as when callingRXGate.control()
,RYGate.control()
, orRZGate.control()
when the rotation angle was aParameterExpression
. Now, these multi-controlled rotation circuits can be synthesized without raising an error. -
Fixed a bug in QPY (
qiskit.qpy
) where circuits containing gates of classMCMTGate
would fail to serialize. See #13965. -
Fixed a bug that caused
Statevector.expectation_value()
to yield incorrect results for the identity operator when the statevector was not normalized. Fixed #13029 -
Converting a quantum circuit to a gate with
converters.circuit_to_instruction()
now properly fails when given circuit contains control flow instructions. -
Calling an
AnalysisPass
or aTransformationPass
like a function (as inpass_ = MyPass(); pass_(qc)
) will now respect any requirements that the pass might have. For example, scheduling passes such asALAPScheduleAnalysis
require thatTimeUnitConversion
runs before them. Running the pass by using aPassManager
always respected this requirement, but until now, it was not respected when calling the pass directly. -
When a
TranspilerError
subclass is raised by a pass inside a call toPassManger.run()
, the exception will now be propagated through losslessly, rather than becoming a chained exception with an erased type. -
SabreSwap
will no longer contract idle qubit wires out of control-flow blocks during routing. This was generally a valid optimization, but not an expected side effect of a routing pass. You can now use theContractIdleWiresInControlFlow
pass to perform this contraction. -
Fixed a per-process based non-determinism in
SparsePauliOp.to_matrix
. The exact order of the floating-point operations in the summation would previously vary per process, but will now be identical between different invocations of the same script. See #13413.