Skip to main contentIBM Quantum Documentation

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 for Delay instructions, which enable expressing relationships between timing-aware instructions. The new Stretch 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 as RZXGate or RZZGate, 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 given Target. 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 and PhaseOracleGate. BitFlipOracleGate was introduced as an alternative to directly synthesizing BooleanExpression, which has been removed in Qiskit v2.0. PhaseOracleGate was added as an alternative to PhaseOracle, as the latter will be deprecated throughout the v2.x releases. Both classes share the interface of PhaseOracle, except for the evaluate_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')
    _images/release_notes-1_00.png _images/release_notes-1_01.png
    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')
    _images/release_notes-2_00.png _images/release_notes-2_01.png
  • A new control-flow op, BoxOp, its associated QuantumCircuit.box() method and context manager are now available from qiskit.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 to CommutationChecker.commute() and CommutationChecker.commute_nodes(). This argument allows you to set the approximation threshold for when gates are evaluated as commuting. See the docstring of CommutationChecker 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. The Expr class now has a boolean const 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 all Value 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 type Duration.

    The module qiskit.circuit also has a new Duration class, which can be used as a literal value within classical expressions.

    The lift() function can be used to create a value expression from a Duration 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 type Float.

    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 and stretch) 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, the CXGate count was reduced by 56%.
    • For multi-controlled HGate on 10 qubits, the CXGate count was reduced by 56%.
    • For multi-controlled SXGate and SXdgGate on 10 qubits, the CXGate count was reduced by 80%.
    • For multi-controlled UGate on 10 qubits, the CXGate count was reduced by 31%.
  • The classical realtime-expressions module qiskit.circuit.classical can now represent arithmetic operations add(), sub(), mul(), and div() 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 with Initialize.

  • The PauliEvolutionGate now natively supports SparseObservables 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 represent stretch variables. To create a new stretch variable, you can use QuantumCircuit.add_stretch(). The resulting expression is a constant expression of type Duration, which can be used as the duration argument of a delay().

    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 existing Var expression used to represent classical variables in a circuit, except it is constant and is always of type Duration. It can be used in other expressions (for example, you can multiply it by a numeric constant) and QuantumCircuit 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 their QuantumCircuit variants. These are:

Primitives Features

  • Added a new to_bool_array() method to the BitArray class that returns the bit array as a boolean NumPy array. The order argument can be used to specify the endianness of the output array.

Providers Features

  • Added the ability to set the dt property of GenericBackendV2 in the class initializer with a new dt 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

Synthesis Features

Transpiler Features

  • Added support for working with Target objects that contain two-qubit basis gates that contain arbitrary angles, such as RZZGate, to the ConsolidateBlocks 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 where UnitarySynthesis could potentially optimize the block. Internally, the gate count estimate is done using the TwoQubitControlledUDecomposer 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 the UnitarySynthesis transpiler pass. The decomposition is done using the TwoQubitControlledUDecomposer, 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:

    _images/release_notes-3.png

    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")
    _images/release_notes-4.png
  • Added a new argument max_block_width to the BlockCollector class and to the CollectLinearFunctions and CollectCliffords 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 the CollectMultiQBlocks transpiler pass. When set to True, 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 to CommutationAnalysis. 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 in qiskit.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 explicitly routing_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 set translation_method="translator" explicitly to maintain the current behavior.

  • The HighLevelSynthesis transpiler pass now synthesizes objects of type AnnotatedOperation through the plugin interface.

  • PassManager.run() now accepts a property_set argument, which can be set to a Mapping-like object to provide the initial values of the pipeline’s PropertySet. 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 and PadDynamicalDecoupling now have new arguments on their constructors: target and durations. These are used to specify the Target or InstructionDurations 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 the Target class. This is used to translate a duration in seconds to a number of discretized time steps of the system time resolution specified in the Target.dt attribute. This is typically useful for converting the InstructionProperties.duration value to units of dt.

  • The Split2QUnitaries transpiler pass has been upgraded to handle the case where the unitary in consideration can be written as a SwapGate gate and two single-qubit gates. In this case, it splits the unitary and also applies virtual swapping, similar to what is done in ElidePermutations. 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’s multiprocessing parallelization settings. In particular, one can now use should_run_in_parallel() to query whether parallel_map() (and pass managers) will launch subprocesses for suitable inputs, and use the context manager should_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 on import qiskit. If set to the string true, 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 in QuantumCircuit, Target and DAGCircuit, 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 and schedule from the compiler 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 and Register as well as their subclassess are no longer guaranteed to be comparable using is checks, due to conversions to and from Python which may re-allocate each instance exposed to Python.

  • Bit and Register (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 and Register 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 the ClassicalFunction class, its related classical_function function, and the BooleanExpression class. This change was made to remove the dependency on the tweedledum library, which is no longer compatible with all of Qiskit’s supported platforms and Python versions. ClassicalFunction was exclusively used in PhaseOracle, which has been upgraded to only accept expressions in string format (see following release note). BooleanExpression has been superseded by the new BitFlipOracleGate class.

  • The PhaseOracle class no longer depends on the tweedledum library, as the dependency is not actively maintained. The interface has been simplified: it no longer accepts a synthesizer parameter, and the expression parameter can only be a string. The previously accepted ClassicalFunction 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')
    _images/release_notes-5.png

    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 with RemoveIdentityEquivalent and TwoQubitWeylDecomposition. 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 an OpenQASM reserved word. Instead of measure, it is now called meas, aligning with the register name used by measure_all().

  • The DAGCircuit.control_flow_op_nodes() method has been updated to always return a list, even if it is empty. Previously, it returned None 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 empty QuantumCircuit with the same number of qubits and clbits, and the same metadata as the original circuit, instead of a BlueprintCircuit. This change addresses unexpected behavior where dealing with an “empty” copy of a blueprint circuit would cause the circuit data to be rebuilt. Note that BlueprintCircuit.copy() still returns a BlueprintCircuit. While BlueprintCircuit is not a public class as it’s an internal type used for building legacy entries in qiskit.circuit.library this impacts its subclasses such as NLocal and ZZFeatureMap. Refer to the qiskit.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 of add_control(SomeGate(...), ...) should change to SomeGate(...).control(...) using Gate.control() instead, which is far safer.

  • The ParameterExpression.sympify() method can now raise a MissingOptionalLibrary exception if sympy 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 requires sympy you need to ensure you have sympy installed to use the method.

  • The deprecated DAGNode dag argument has been removed from the DAGNode class and its subclasses: DAGOpNode, DAGOutNode, and DAGInNode.

    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 and Gate: duration and unit have been removed, so you can no longer set the unit or duration arguments for any qiskit.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 the BackendV2 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 the InstructionProperties.duration field in a given Target to set a custom duration for an instruction on a backend. (The unit is always in seconds in the Target.)

  • The deprecated attribute for qiskit.circuit.Instruction and Gate: condition has been removed. This functionality has been superseded by the IfElseOp 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 and Gate: c_if and condition_bits have been removed. These methods were deprecated in the v1.3.0 release. This functionality has been superseded by the IfElseOp class, which can be used to describe a classical condition in a circuit. For example, a circuit previously using Instruction.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 the IfElseOp 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 the QuantumCircuit, DAGCircuit and DAGDependency classes. In addition to this, the method has_calibration_for has been removed from the QuantumCircuit and DAGCircuit classes, and add_calibration has been removed from QuantumCircuit.

  • The qiskit.circuit.classicalfunction module has been removed. This module was dependent on the tweedledum library which is not compatible with newer versions of Python. As an alternative, the PhaseOracleGate and BitFlipOracleGate classes can be used to generate circuits from boolean expressions.

  • The internal representation of UnitaryGate when added to a QuantumCircuit 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 the UnitaryGate 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 use DAGCircuit.substitute_node() instead.

  • The CircuitInstruction.params attribute for a CircuitInstruction that contains an UnitaryGate for its operation 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 the CircuitInstruction.matrix or the UnitaryGate.params field of the CircuitInstruction.operation.

Primitives Upgrade Notes

  • As a consequence of the removal of the BackendV1 model, the BackendSamplerV2 and BackendEstimatorV2 classes no longer accept inputs of type BackendV1 in their backend 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:

    As well as the following non-versioned type aliases:

    This removal does NOT affect the explicitly-versioned BaseEstimatorV1 and BaseSamplerV1 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 as BaseEstimator, 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:

Providers Upgrade Notes

  • The configuration method of BasicSimulator has been removed following its deprecation in Qiskit v1.3. This method returned a BackendConfiguration instance, a class that was part of the discontinued BackendV1 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 contained Target instance (backend.target).

  • The run_experiment method of BasicSimulator has been removed. This method took an instance of the QasmQobjExperiment class as an input argument, a class that has been deprecated since Qiskit v1.2 and was removed with the Qobj workflow in Qiskit v2.0.0.

  • The BackendV1 model has been removed following its deprecation in Qiskit 1.2.0. This includes the BackendV1 class as well as related modules and utils, as they have been superseded by the BackendV2 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 the BackendV1 model:

      • BackendConfiguration
      • BackendProperties
      • BackendStatus
      • QasmBackendConfiguration
      • PulseBackendConfiguration
      • UchannelLO
      • GateConfig
      • PulseDefaults
      • PulseQobjDef
      • Command
      • GateProperties
      • Nduv
      • JobStatus: This class has been superseded by the more widely used JobStatus
      • PulseDefaults
    • BackendV2Converter class: used to convert from BackendV1 to BackendV2

    • convert_to_target function: used to build a Target instance from legacy BackendV1 components (such as BackendConfiguration or BackendProperties)

    • BackendPropertyError and BackendConfigurationError: 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 the providers.fake_provider module. These classes have been deprecated since Qiskit 1.2 and were part of the deprecated BackendV1 workflow. Their use in tests has been replaced with the GenericBackendV2 class, which allows to create custom instances of BackendV2 that implement a simulated BackendV2.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 and ProviderV1, which have been deprecated since Qiskit v1.1.0. The abstraction provided by these interface definitions was not offering significant value, only including the attributes name, backends, and a get_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 a MissingOptionalLibrary exception if a QPY v10, v11, or v12 payload is passed in that uses symengine symbolic expressions and symengine is not installed. The exception is also raised if sympy is not installed for any other QPY payload prior to v13. In the Qiskit v1.x releases, symengine and sympy 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 using symengine. Parsing these QPY payloads requires symengine as its usage is part of the format specification for QPY v10, v11, and v12. If the payload requires it, installing a compatible version of symengine (0.11.0 or 0.13.0) is the only option. Similarly, sympy was was used for ParameterExpression 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 the qpy.dump() function. This means that qpy.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 or symengine libraries to generate a serialization for ParameterExpression objects, but in Qiskit 2.x neither library is required for the ParameterExpression object.

  • With the removal of pulse in Qiskit v2.0.0, support for serializing ScheduleBlock programs through the qiskit.qpy.dump() function has been removed. Users can still load payloads containing pulse gates by using the qiskit.qpy.load() function, however, they will be treated as opaque custom instructions. Loading ScheduleBlock payloads is not supported anymore and will cause a QpyError exception.

Synthesis Upgrade Notes

  • The atomic_evolution callable argument of ProductFormula (and its subclasses QDrift, LieTrotter, and SuzukiTrotter ) 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 to 1e-12 to account for round-off errors in the fidelity calculation and for consistency with the other classes, such as CommutationAnalysis and TwoQubitWeylDecomposition.

  • 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 set routing_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 set translation_method="translator" explicitly to maintain the current behavior.

  • The legacy scheduling passes ASAPSchedule, ALAPSchedule, DynamicalDecoupling, and AlignMeasures have been removed in favor of the updated alternatives ALAPScheduleAnalysis, ASAPScheduleAnalysis, PadDynamicalDecoupling, and ConstrainedReschedule 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 of basis_gates are specified, the HighLevelSynthesis transpiler pass synthesizes circuits with annotated operations with fewer layers of wrappings than before (this happens, for instance, for the circuit produced by multiplier_cumulative_h18()).

  • The keyword argument property_set is now reserved in BasePassManager.run(), and cannot be used as a kwarg 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:

    The following passes have also been updated to only accept a target instead of:

    The BackendProperties class has been deprecated since Qiskit v1.2, because it was part of the BackendV1 workflow. Specific instruction properties, such as gate errors or durations can be added to a Target upon construction through the Target.add_instruction() method, and communicated to the relevant transpiler passes through the target 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 ResetAfterMeasureSimplification transpiler pass now uses an IfElseOp to condition the execution of the XGate instead of setting a condition attribute on the gate. This is because the condition attribute has been removed from the Qiskit data model.

  • The deprecated ConvertConditionsToIfOps transpiler pass has been removed. The underlying condition attribute of Instruction class has been removed so this transpiler pass no longer had anything to convert from. Instead you should directly use IfElseOp to classically condition the execution of an operation.

  • The PadDelay and PadDynamicalDecoupling transpiler passes now require a new argument when constructed. Either target or durations need to be specified with a Target or InstructionDurations 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 removed duration attribute of Instruction objects.

  • The previously deprecated AlignMeasures transpiler pass has been removed. This pass was deprecated in Qiskit v1.1.0. Instead, the ConstrainedReschedule 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() or transpile(), if the instruction_durations argument is specified, the durations are formatted as a list, and they are in units of dt. You must also set the dt 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() and generate_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 of transpile() and generate_preset_pass_manager(), also deprecated in Qiskit 1.3, is no longer allowed, and a ValueError will be raised in these cases.

    The information formerly provided through these can still be specified via the backend or target 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() and generate_preset_pass_manager() interfaces now raise a UserWarning when providing a coupling_map and/or basis_gates along with a backend. In these cases there are multiple sources of truth, the user intentions are not always clear, and there can be conflicts that generate_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 or basis_gates together with a custom coupling_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() and generate_preset_pass_manager() now raise a ValueError.

  • 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 pass
    • qiskit.transpiler.passes.ValidatePulseGates pass
    • qiskit.transpiler.passes.RXCalibrationBuilder pass
    • qiskit.transpiler.passes.RZXCalibrationBuilder pass
    • qiskit.transpiler.passes.RZXCalibrationBuilderNoEcho pass
    • qiskit.transpiler.passes.EchoRZXWeylDecomposition pass
    • qiskit.transpiler.passes.NoramlizeRXAngle pass
    • qiskit.transpiler.passes.rzx_templates() function

    The inst_map argument has been removed from the following elements:

    Calibration support has been removed:

    • calibration has been removed from the InstructionProperties constructor and is no longer a property of that class.
    • The has_calibration, get_calibration, instruction_schedule_map and update_from_instruction_schedule_map methods have been removed from the Target 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 the SabreSwap 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 to InverseCancellation([CXGate()]).

  • The SolovayKitaev transpiler pass no longer raises an exception on circuits that contain single-qubit operations without a to_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() and generate_preset_pass_manager() would generate a PassManager 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 output StagedPassManager. You can now safely assign your own PassManager to this field. You could previously only append to the existing PassManager.

  • The default value for the generate_routing_passmanager() argument seed_transpiler has changed from None to -1. This change was made because this flag was only used to configure the VF2PostLayout 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 argument seed_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 set idle_wires=True.

    When set to "auto", the behavior is as follows:

    • If the circuit has a defined .layout attribute, idle_wires is automatically set to False (hiding idle wires)
    • Otherwise, idle_wires remains True (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" sets idle_wires to False, 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.

  • The array_to_latex() function and Operator.draw() method can now raise a MissingOptionalLibrary exception if the sympy library is not installed. In the Qiskit v1.x releases, symengine and sympy 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 the sympy library, so if you’re using this functionality, ensure that you have sympy installed.

  • As a consequence of the removal of the BackendV1 model, the plot_gate_map(), plot_error_map() and plot_circuit_layout() functions no longer accept inputs of type BackendV1 in their backend 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 and deprecate_arguments decorators, deprecated since Qiskit v0.24 (May 2023), have been removed in Qiskit v2.0.0. The current deprecate_func() replaces @deprecate_function and the current deprecate_arg() replaces @deprecate_arguments.

  • The assemble function and related capabilities (contained in the assembler module) have been removed from the codebase following their deprecation in Qiskit v1.2. assemble was used to generate a Qobj in the context of the deprecated BackendV1 workflow. The conversion is no longer necessary, as the transpilation and primitives pipeline handles quantum circuits directly, rendering the Qobj obsolete.

    The removal includes the following public API components:

    • qiskit.compiler.assemble function
    • qiskit.assembler.assemble_circuits function
    • qiskit.assembler.assemble_schedules function
    • qiskit.assembler.disassemble function
    • qiskit.assembler.RunConfig class
    • qiskit.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 the BackendV1 workflow and are no longer necessary for interacting with BackendV2 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 and MeasReturnType classes, previously defined in qobj/utils.py, have been migrated to result/models.py following the removal of the qobj 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, the qobj_id argument will no longer be used in the construction of the Result internals. It is still possible to set qobj_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 and schedule_circuit functions from qiskit.scheduler together with the ScheduleConfig class have been removed.

  • The qiskit.result.mitigation module has been removed following its deprecation in Qiskit v1.3. The removal includes the LocalReadoutMitigator and CorrelatedReadoutMitigator 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 the QuantumCircuit.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 the operation, qubits, and clbits named attributes.

  • The Multiple-Control-Multiple-Target circuit class MCMT is now deprecated and was replaced by MCMTGate, which is a proper Gate 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 the QuantumCircuit.estimate_duration() method, which should be used instead.

  • The propagate_condition argument of DAGCircuit.substitute_node() and DAGCircuit.substitute_node_with_dag() has been deprecated. With the removal of Instruction.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 use sympy to serialize ParameterExpression 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 by RemoveIdentityEquivalent. The underlying issue was caused by RemoveIdentityEquivalent and CommutationAnalysis (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 output Var nodes to become input nodes during deepcopy and pickling.

  • Fixed an oversight in the Target class where setting a new value for the dt attribute and subsequently calling target.durations() would not show the updated dt value in the returned InstructionDurations object. This is now fixed through an invalidation of the internal target instruction durations cache in the dt 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 passed basis_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 methods QuantumCircuit.mcrx(), :meth:.QuantumCircuit.mcry, and QuantumCircuit.mcrz(), as well as when calling RXGate.control(), RYGate.control(), or RZGate.control() when the rotation angle was a ParameterExpression. 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 class MCMTGate 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 a TransformationPass like a function (as in pass_ = MyPass(); pass_(qc)) will now respect any requirements that the pass might have. For example, scheduling passes such as ALAPScheduleAnalysis require that TimeUnitConversion runs before them. Running the pass by using a PassManager 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 to PassManger.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 the ContractIdleWiresInControlFlow 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.

Was this page helpful?
Report a bug or request content on GitHub.