Skip to main contentIBM Quantum Documentation

Qiskit 0.37 release notes


This release officially marks the end of support for the Qiskit Ignis project from Qiskit. It was originally deprecated in the 0.33.0 release and as was documented in that release the qiskit-ignis package has been removed from the Qiskit metapackage, which means in that future release pip install qiskit will no longer include qiskit-ignis. However, note because of limitations in python packaging we cannot automatically remove a pre-existing install of qiskit-ignis. If you are upgrading from a previous version it’s recommended that you manually uninstall Qiskit Ignis with pip uninstall qiskit-ignis or install the metapackage in a fresh python environment.

Qiskit Ignis has been supersceded by the Qiskit Experiments (opens in a new tab) project. You can refer to the migration guide (opens in a new tab) for details on how to switch from Qiskit Ignis to Qiskit Experiments.

Terra 0.21.0


The Qiskit 0.21.0 release highlights are:

  • Support for serialization of a pulse ScheduleBlock via qiskit.qpy. The QPY Format has been updated to version 5 which includes a definition for including the pulse schedules. To support this, a new SymbolicPulse class was introduced to enable defining parametric pulse waveforms via symbolic expressions.
  • Improvements to working with preset pass managers. A new function generate_preset_pass_manager() enables easily generating a pass manager equivalent to what transpile() will use internally. Additionally, preset pass managers are now instances of StagedPassManager which makes it easier to modify sections.
  • A refactor of the internal data structure of the attribute. It previously was a list of tuples in the form (instruction, qubits, clbits) and now is a list of CircuitInstruction objects. The CircuitInstruction objects is backwards compatible with the previous tuple based access, however with runtime overhead cost.

Additionally, the transpiler has been improved to enable better quality outputs. This includes the introduction of new passes such as VF2PostLayout and ToqmSwap.

New Features

  • Added a new class, qiskit.transpiler.StagedPassManager, which is a PassManager subclass that has a pipeline with defined phases to perform circuit compilation. Each phase is a PassManager object that will get executed in a fixed order. For example:

    from qiskit.transpiler.passes import *
    from qiskit.transpiler import PassManager, StagedPassManager
    basis_gates = ['rx', 'ry', 'rxx']
    init = PassManager([UnitarySynthesis(basis_gates, min_qubits=3), Unroll3qOrMore()])
    translate = PassManager([Collect2qBlocks(),
    staged_pm = StagedPassManager(stages=['init', 'translation'], init=init, translation=translate)
  • Added the methods PauliList.group_commuting() and SparsePauliOp.group_commuting(), which partition these operators into sublists where each element commutes with all the others. For example:

    from qiskit.quantum_info import PauliList, SparsePauliOp
    groups = PauliList(["XX", "YY", "IZ", "ZZ"]).group_commuting()
    # 'groups' is [PauliList(['IZ', 'ZZ']), PauliList(['XX', 'YY'])]
    op = SparsePauliOp.from_list([("XX", 2), ("YY", 1), ("IZ", 2j), ("ZZ", 1j)])
    groups = op.group_commuting()
    # 'groups' is [
    #     SparsePauliOp(['IZ', 'ZZ'], coeffs=[0.+2.j, 0.+1.j]),
    #     SparsePauliOp(['XX', 'YY'], coeffs=[2.+0.j, 1.+0.j]),
    # ]
  • Added a new function, marginal_distribution(), which is used to marginalize an input dictionary of bitstrings to an integer (such as Counts). This is similar in functionality to the existing marginal_counts() function with three key differences. The first is that marginal_counts() works with either a counts dictionary or a Results object while marginal_distribution() only works with a dictionary. The second is that marginal_counts() does not respect the order of indices in its indices argument while marginal_distribution() does and will permute the output bits based on the indices order. The third difference is that marginal_distribution() should be faster as its implementation is written in Rust and streamlined for just marginalizing a dictionary input.

  • Added the @ (__matmul__) binary operator to BaseOperator subclasses in the qiskit.quantum_info module. This is shorthand to call the classes’ dot method (A @ B ==

  • Added a new optional argument, reps, to QuantumCircuit.decompose(), which allows repeated decomposition of the circuit. For example:

    from qiskit import QuantumCircuit
    circuit = QuantumCircuit(1)
    circuit.ry(0.5, 0)
    # Equivalent to circuit.decompose().decompose()
    # decompose 2 times, but only RY gate 2 times and R gate 1 times
    circuit.decompose(gates_to_decompose=['ry','r'], reps=2)
  • Added a new pulse base class SymbolicPulse. This is a replacement of the conventional ParametricPulse, which will be deprecated. In the new base class, pulse-envelope and parameter-validation functions are represented by symbolic-expression objects. The new class provides self-contained and portable pulse data since these symbolic equations can be easily serialized through symbolic computation libraries.

  • Added support for non-Hermitian operators in AerPauliExpectation. This allows the use of Aer’s fast snapshot expectation computations in algorithms such as QEOM.

  • Added a new circuit drawing style, textbook, which uses the color scheme of the Qiskit Textbook.

  • A new attribute QuantumCircuit.op_start_times is populated when one of scheduling analysis passes is run on the circuit. It can be used to obtain circuit instruction with instruction time, for example:

    from qiskit import QuantumCircuit, transpile
    from qiskit.providers.fake_provider import FakeMontreal
    backend = FakeMontreal()
    qc = QuantumCircuit(2)
    qc.h(0), 1)
    qct = transpile(
        qc, backend, initial_layout=[0, 1], coupling_map=[[0, 1]], scheduling_method="alap"
    scheduled_insts = list(zip(qct.op_start_times,
  • Added a new method QuantumCircuit.clear() which is used to remove all instructions from a QuantumCircuit.

  • Added a new method QuantumCircuit.copy_empty_like() which is used to get a cleared copy of a QuantumCircuit instance. This is logically equivalent to qc.copy().clear(), but significantly faster and more memory-efficient. This is useful when one needs a new empty circuit with all the same resources (qubits, classical bits, metadata, and so on) already added.

  • The Target.instruction_supported() method now supports two new keyword arguments, operation_class and parameters. Using these arguments the instruction_supported() method can now be used for checking that a specific operation with parameter values are supported by a Target object. For example, if you want to check if a Target named target supports running a RXGate with θ=π2\theta = \frac{\pi}{2} you would do something like:

    from math import pi
    from qiskit.circuit.library import RXGate
    target.instruction_supported(operation_class=RXGate, parameters=[pi/2])

    which will return True if target supports running RXGate with θ=π2\theta = \frac{\pi}{2} and False if it does not.

  • Added a Trotterization-based quantum real-time evolution algorithm qiskit.algorithms.TrotterQRTE. It is compliant with the new quantum time evolution framework and makes use of the ProductFormula and PauliEvolutionGate implementations.

    from qiskit.algorithms import EvolutionProblem
    from qiskit.algorithms.evolvers.trotterization import TrotterQRTE
    from qiskit.opflow import X, Z, StateFn, SummedOp
    operator = SummedOp([X, Z])
    initial_state = StateFn([1, 0])
    time = 1
    evolution_problem = EvolutionProblem(operator, time, initial_state)
    trotter_qrte = TrotterQRTE()
    evolution_result = trotter_qrte.evolve(evolution_problem)
    evolved_state_circuit = evolution_result.evolved_state
  • Added a new function generate_preset_pass_manager() which can be used to quickly generate a preset PassManager object that mirrors the PassManager used internally by the transpile() function. For example:

    from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
    from qiskit.providers.fake_provider import FakeWashingtonV2
    # Generate an optimization level 3 pass manager targeting FakeWashingtonV2
    pass_manager = generate_preset_pass_manager(3, FakeWashingtonV2())
  • Added a new function marginal_memory() which is used to marginalize shot memory arrays. Provided with the shot memory array and the indices of interest, the function will return a maginized shot memory array. This function differs from the memory support in the marginal_counts() method which only works on the memory field in a Results object.

  • The primitives interface has been extended to accept objects in addition to indices as arguments to the __call__ method. The parameter_values argument can now be optional.

  • The OpenQASM 3 exporter (qiskit.qasm3) now supports exporting circuits with explicit delays, such as from QuantumCircuit.delay().

  • Added a new layout and routing method to transpile() based on the paper “Time-optimal qubit mapping” (opens in a new tab). To use it, the optional package Qiskit TOQM (opens in a new tab) must be installed. The routing_method kwarg of transpile() supports an additional value, 'toqm' which is used to enable layout and routing via TOQM.

    To install qiskit-toqm along with Terra, run:

    pip install qiskit-terra[toqm]
  • Added a new module qiskit.quantum_info.synthesis.qsd to apply Quantum Shannon Decomposition of arbitrary unitaries. This functionality replaces the previous isometry-based approach in the default unitary synthesis transpiler pass as well as when adding unitaries to a circuit using a UnitaryGate.

    The Quantum Shannon Decomposition uses about half the cnot gates as the isometry implementation when decomposing unitary matrices of greater than two qubits.

  • Classes in the quantum_info module that support scalar multiplication can now be multiplied by a scalar from either the left or the right. Previously, they would only accept scalar multipliers from the left.

  • The transpiler pass LookaheadSwap (used by transpile() when routing_method="lookahead") has seen some performance improvements and will now be approximately three times as fast. This is purely being more efficient in its calculations, and does not change the complexity of the algorithm. In most cases, a more modern routing algorithm like SabreSwap (routing_method="sabre") will be vastly more performant.

  • New transpiler passes have been added. The transpiler pass Commuting2qGateRouter uses swap strategies to route a block of commuting gates to the coupling map. Indeed, routing is a hard problem but is significantly easier when the gates commute as in CZ networks. Blocks of commuting gates are also typically found in QAOA. Such cases can be dealt with using swap strategies that apply a predefined set of layers of SWAP gates. Furthermore, the new transpiler pass FindCommutingPauliEvolutions identifies blocks of Pauli evolutions made of commuting two-qubit terms. Here, a swap strategy is specified by the class SwapStrategy. Swap strategies need to be tailored to the coupling map and, ideally, the circuit for the best results.

  • Introduced a new optimizer to Qiskit library, which adds support to the optimization of parameters of variational quantum algorithms. This is the Univariate Marginal Distribution Algorithm (UMDA), which is a specific type of the Estimation of Distribution Algorithms. For example:

    from qiskit.opflow import X, Z, I
    from qiskit import Aer
    from qiskit.algorithms.optimizers import UMDA
    from qiskit.algorithms import QAOA
    from qiskit.utils import QuantumInstance
    H2_op = (-1.052373245772859 * I ^ I) + \
            (0.39793742484318045 * I ^ Z) + \
            (-0.39793742484318045 * Z ^ I) + \
            (-0.01128010425623538 * Z ^ Z) + \
            (0.18093119978423156 * X ^ X)
    p = 2  # Toy example: 2 layers with 2 parameters in each layer: 4 variables
    opt = UMDA(maxiter=100, size_gen=20)
    backend = Aer.get_backend('statevector_simulator')
    vqe = QAOA(opt,
    result = vqe.compute_minimum_eigenvalue(operator=H2_op)
  • The constructor for the Unroll3qOrMore transpiler pass has two new optional keyword arguments, target and basis_gates. These options enable you to specify the Target or supported basis gates respectively to describe the target backend. If any of the operations in the circuit are in the target or basis_gates those will not be unrolled by the pass as the target device has native support for the operation.

  • QPY serialization has been upgraded to support ScheduleBlock. Now you can save pulse program in binary and load it at later time:

    from qiskit import pulse, qpy
    with as schedule:, 0.1, 40), pulse.DriveChannel(0))
    with open('schedule.qpy', 'wb') as fd:
        qpy.dump(schedule, fd)
    with open('schedule.qpy', 'rb') as fd:
        new_schedule = qpy.load(fd)[0]

    This uses the QPY interface common to QuantumCircuit. See SCHEDULE_BLOCK for details of data structure.

  • Added a new transpiler pass, VF2PostLayout. This pass is of a new type to perform a new phase/function in the compilation pipeline, post-layout or post optimization qubit selection. The idea behind this pass is after we finish the optimization loop in transpiler we know what the final gate counts will be on each qubit in the circuit so we can potentially find a better-performing subset of qubits on a backend to execute the circuit. The pass will search for an isomorphic subgraph in the connectivity graph of the target backend and look at the full error rate of the complete circuit on any subgraph found and return the layout found with the lowest error rate for the circuit.

    This pass is similar to the VF2Layout pass and both internally use the same VF2 implementation from retworkx (opens in a new tab). However, VF2PostLayout is deisgned to run after initial layout, routing, basis translation, and any optimization passes run and will only work if a layout has already been applied, the circuit has been routed, and all gates are in the target basis. This is required so that when a new layout is applied the circuit can still be run on the target device. VF2Layout on the other hand is designed to find a perfect initial layout and can work with any circuit.

  • The ApplyLayout transpiler pass now has support for updating a layout on a circuit after a layout has been applied once before. If the post_layout field is present (in addition to the required layout field) the property_set when the ApplyLayout pass is run the pass will update the layout to apply the new layout. This will return a DAGCircuit with the qubits in the new physical order and the layout property set will be updated so that it maps the virtual qubits from the original layout to the physical qubits in the new post_layout field.

  • The preset pass managers generated by level_1_pass_manager(), level_2_pass_manager(), and level_3_pass_manager() which correspond to optimization_level 1, 2, and 3 respectively on the transpile() function now run the VF2PostLayout pass after running the routing pass. This enables the transpiler to potentially find a different set of physical qubits on the target backend to run the circuit on which have lower error rates. The VF2PostLayout pass will not be run if you manually specify a layout_method, routing_method, or initial_layout arguments to transpile(). If the pass can find a better performing subset of qubits on backend to run the physical circuit it will adjust the layout of the circuit to use the alternative qubits instead.

  • The algorithm iteratively computes each eigenstate by starting from the ground state (which is computed as in VQE) and then optimising a modified cost function that tries to compute eigen states that are orthogonal to the states computed in the previous iterations and have the lowest energy when computed over the ansatz. The interface implemented is very similar to that of VQE and is of the form:

    from qiskit.algorithms import VQD
    from qiskit.utils import QuantumInstance
    from qiskit.circuit.library import TwoLocal
    from qiskit.algorithms.optimizers import COBYLA
    from qiskit import BasicAer
    from qiskit.opflow import I,Z,X
    h2_op = (
        -1.052373245772859 * (I ^ I)
        + 0.39793742484318045 * (I ^ Z)
        - 0.39793742484318045 * (Z ^ I)
        - 0.01128010425623538 * (Z ^ Z)
        + 0.18093119978423156 * (X ^ X)
    vqd = VQD(k =2, ansatz = TwoLocal(rotation_blocks="ry", entanglement_blocks="cz"),optimizer = COBYLA(maxiter = 0), quantum_instance = QuantumInstance(
                BasicAer.get_backend("qasm_simulator"), shots = 2048)
    vqd_res = vqd.compute_eigenvalues(op)

    This particular code snippet generates 2 eigenvalues (ground and 1st excited state) Tests have also been implemented.

Upgrade Notes

  • The pulse classes in qiskit.pulse.library are now subclasses of SymbolicPulse rather than ParametricPulse. The available classes remain unchanged as Gaussian, GaussianSquare, Drag, and Constant. SymbolicPulse has full backward compatibility, and there should be no loss of functionality.

  • The data type of each element in has changed. It used to be a simple 3-tuple of an Instruction, a list of Qubits, and a list of Clbits, whereas it is now an instance of CircuitInstruction.

    The attributes of this new class are operation, qubits and clbits, corresponding to the elements of the previous tuple. However, qubits and clbits are now tuple instances, not lists.

    This new class will behave exactly like the old 3-tuple if one attempts to access its index its elements, or iterate through it. This includes casting the qubits and clbits elements to lists. This is to assist backwards compatibility. Starting from Qiskit Terra 0.21, this is no longer the preferred way to access these elements. Instead, you should use the attribute-access form described above.

    This has been done to allow further developments of the QuantumCircuit data structure in Terra, without constantly breaking backwards compatibility. Planned developments include dynamic parameterized circuits, and an overall reduction in memory usage of deep circuits.

  • The python-constraint dependency, which is used solely by the CSPLayout transpiler pass, is no longer in the requirements list for the Qiskit Terra package. This is because the CSPLayout pass is no longer used by default in any of the preset pass managers for transpile(). While the pass is still available, if you’re using it you will need to manually install python-contraint or when you install qiskit-terra you can use the csp-layout extra, for example:

    pip install "qiskit-terra[csp-layout]"
  • The QPY version format version emitted by qpy.dump() has been increased to version 5. This new format version is incompatible with the previous versions and will result in an error when trying to load it with a deserializer that isn’t able to handle QPY version 5. This change was necessary to fix support for representing controlled gates properly and representing non-default control states.

  • Qiskit Terra’s compiled Rust extensions now have a minimum supported Rust version (MSRV) of 1.56.1. This means when building Qiskit Terra from source the oldest version of the Rust compiler supported is 1.56.1. If you are using an older version of the Rust compiler you will need to update to a newer version to continue to build Qiskit from source. This change was necessary as a number of upstream dependencies have updated their minimum supported versions too.

  • Circuit scheduling now executes in parallel when more than one circuit is provided to schedule(). Refer to #2695 (opens in a new tab) for more details.

  • The previously deprecated BaseBackend, BaseJob, and BaseProvider classes have all been removed. They were originally deprecated in the 0.18.0 release. Instead of these classes you should be using the versioned providers interface classes, the latest being BackendV2, JobV1, and ProviderV1.

  • The previously deprecated backend argument for the constructor of the RZXCalibrationBuilder transpiler pass has been removed. It was originally deprecated in the 0.19.0 release. Instead you should query the Backend object for the instruction_schedule_map and qubit_channel_mapping and pass that directly to the constructor. For example, with a BackendV1 backend:

    from qiskit.transpiler.passes import RZXCalibrationBuilder
    from qiskit.providers.fake_provider import FakeMumbai
    backend = FakeMumbai()
    inst_map = backend.defaults().instruction_schedule_map
    channel_map = backend.configuration().qubit_channel_mapping
    cal_pass = RZXCalibrationBuilder(

    or with a BackendV2 backend:

    from qiskit.transpiler.passes import RZXCalibrationBuilder
    from qiskit.providers.fake_provider import FakeMumbaiV2
    backend = FakeMumbaiV2()
    inst_map = backend.instruction_schedule_map
    channel_map = {bit: backend.drive_channel(bit) for bit in range(backend.num_qubits)}
    cal_pass = RZXCalibrationBuilder(
  • The measurement shot limit for the BasicAer backend has been removed.

  • For the DAGNode, the previously deprecated type, op, qargs, cargs, and wire kwargs and attributes have been removed. These were originally deprecated in the 0.19.0 release. The op, qargs, and cargs kwargs and attributes can be accessed only on instances of DAGOpNode, and the wire kwarg and attribute are only on instances of DAGInNode or DAGOutNode.

  • The deprecated function pauli_group() has been removed. It was originally deprecated in Qiskit Terra 0.17.

  • Several deprecated methods on Pauli have been removed, which were originally deprecated in Qiskit Terra 0.17. These were:


    Use Pauli.compose() or instead.


    Use Pauli.to_matrix() with argument sparse=True instead.


    Use Pauli.expand(), but beware that this returns a new object, rather than mutating the existing one.

    update_z and update_x

    Set the z and x attributes of the object directly.


    Use Pauli.insert().


    Use Pauli.expand().


    Use Pauli.delete().


    Construct the label manually and pass directly to the initializer, such as:

    Pauli("I" * index + pauli_label + "I" * (num_qubits - index - len(pauli_label)))


    Use quantum_info.random_pauli() instead.

  • Removed the optimize method from the Optimizer classes, which is superseded by the minimize() method as direct replacement. The one exception is SPSA, where the deprecation warning was not triggered so the method there is still kept.

  • Result was modified so that it always contains date, status, and header attributes (set to None if not specified).

  • For Python 3.7 shared-memory38 (opens in a new tab) is now a dependency. This was added as a dependency for Python 3.7 to enable leveraging the shared memory constructs in the standard library of newer versions of Python. If you’re running on Python >= 3.8 there is no extra dependency required.

  • Instruction labels are now type-checked on instruction creation.

  • QPY serialization has been upgraded to serialize QuantumCircuit with QuantumCircuit.calibrations. As of QPY Version 5, only calibration entries of ScheduleBlock type can be serialized.

  • The definition of XXPlusYYGate has been changed. See #7969 (opens in a new tab) for details.

  • The preset pass managers generated by level_1_pass_manager(), level_2_pass_manager(), and level_3_pass_manager() and used by the transpile() function’s optimization_level argument at 1, 2, and 3 respectively no longer set a hard time limit on the VF2Layout transpiler pass. This means that the pass will no longer stop trying to find a better alternative perfect layout up until a fixed time limit (100ms for level 1, 10 sec for level 2, and 60 sec for level 3) as doing this limited the reproducibility of compilation when a perfect layout was available. This means that the output when using the pass might be different than before, although in all cases it would only change if a lower noise set of qubits can be found over the previous output. If you wish to retain the previous behavior you can create a custom PassManager that sets the time_limit argument on the constructor for the VF2Layout pass.

Deprecation Notes

  • Calling timeline_drawer() with an unscheduled circuit has been deprecated. All circuits, even one consisting only of delay instructions, must be transpiled with the scheduling_method keyword argument of transpile() set, to generate schedule information being stored in QuantumCircuit.op_start_times.

  • The NetworkX (opens in a new tab) converter functions for the DAGCircuit.to_networkx() and from_networkx(), along with the DAGDependency.to_networkx() method have been deprecated and will be removed in a future release. Qiskit has been using retworkx (opens in a new tab) as its graph library since the qiskit-terra 0.12.0 release, and since then the networkx converter functions have been lossy. They were originally added so that users could leverage functionality in NetworkX’s algorithms library not present in retworkx. Since that time, retworkx has matured and offers more functionality, and the DAGCircuit is tightly coupled to retworkx for its operation. Having these converter methods provides limited value moving forward and are therefore going to be removed in a future release.

  • Accessing several old toggles (HAS_MATPLOTLIB, HAS_PDFTOCAIRO, HAS_PYLATEX and HAS_PIL) from the qiskit.visualization module is now deprecated, and these import paths will be removed in a future version of Qiskit Terra. The same objects should instead be accessed through qiskit.utils.optionals, which contains testers for almost all of Terra’s optional dependencies.

  • The qiskit.test.mock module is now deprecated. The fake backend and fake provider classes which were previously available in qiskit.test.mock have been accessible in qiskit.providers.fake_provider since Terra 0.20.0. This change represents a proper commitment to support the fake backend classes as part of Qiskit, whereas previously they were just part of the internal testing suite, and were exposed to users as a side effect.

  • The arguments’ names when calling an Estimator or Sampler object as a function are renamed from circuit_indices and observable_indices to circuits and observables.

  • The qobj_id and qobj_header keyword arguments for the execute() function have been deprecated and will be removed in a future release. Since the removal of the BaseBackend class these arguments don’t have any effect as no backend supports execution with a Qobj object directly and instead only work with QuantumCircuit objects directly.

  • The arguments x, z and label to the initializer of Pauli were documented as deprecated in Qiskit Terra 0.17, but a bug prevented the expected warning from being shown at runtime. The warning will now correctly show, and the arguments will be removed in Qiskit Terra 0.23 or later. A pair of x and z should be passed positionally as a single tuple (Pauli((z, x))). A string label should be passed positionally in the first argument (Pauli("XYZ")).

  • The SPSA.optimize() method is deprecated in favor of SPSA.minimize(), which can be used as direct replacement. Note that this method returns a complete result object with more information than before available.

  • The circuits argument of qpy.dump() has been deprecated and replaced with programs since now QPY supports multiple data types other than circuits.

  • AlignmentKind.to_dict() method has been deprecated and will be removed.

Bug Fixes

  • Extra validation was added to DiagonalGate to check the argument has modulus one.

  • Duplicate qubit indices given to SparsePauliOp.from_sparse_list() will now correctly raise an error, instead of silently overwriting previous values. The old behavior can be accessed by passing the new keyword argument do_checks=False.

  • The timeline_drawer() visualization will no longer misalign classical register slots.

  • Parameter validation for GaussianSquare is now consistent before and after construction. Refer to #7882 (opens in a new tab) for more details.

  • The BackendV2-based fake backends in the qiskit.providers.fake_provider module, such as FakeMontrealV2, now support the Delay operation in their target attributes. Previously, QuantumCircuit objects that contained delays could not be compiled to these backends.

  • Fixed a bug in TridiagonalToeplitz.eigs_bounds(), which caused incorrect eigenvalue bounds to be returned in some cases with negative eigenvalues. Refer to #7939 (opens in a new tab) for more details.

  • Fixed a bug in which the LaTeX statevector drawer ignored the max_size parameter.

  • Fixed support in the PassManagerConfig.from_backend() constructor method for building a PassManagerConfig object from a BackendV2 instance. Previously this wasn’t handled correctly and would fail when running with a BackendV2 object.

  • Fixed support for QPY serialization (qpy.dump()) and deserialization (qpy.load()) of a QuantumCircuit object containing custom ControlledGate objects. Previously, an exception would be raised by qpy.load() when trying to reconstruct the custom ControlledGate. Fixed #7999 (opens in a new tab).

  • Fixed support for QPY serialization (qpy.dump()) and deserialization (qpy.load()) of a QuantumCircuit object containing custom MCPhaseGate objects. Previously, an exception would be raised by qpy.load() when trying to reconstruct the MCPhaseGate.

  • Fixed support for QPY serialization (qpy.dump()) and deserialization (qpy.load()) of a QuantumCircuit object containing controlled gates with an open control state. Previously, the open control state would be lost by the serialization process and the reconstructed circuit.

  • Fixed QuantumCircuit.reverse_bits() with circuits containing registerless Qubit and Clbit. For example, the following will now work:

    from qiskit.circuit import QuantumCircuit, Qubit, Clbit
    qc = QuantumCircuit([Qubit(), Clbit()])
    qc.h(0).c_if(qc.clbits[0], 0)
  • Fixed the ConfigurableFakeBackend.t2 attribute, which was previously incorrectly set based on the provided t1 value.

  • Fixed an issue with BackendV2-based fake backend classes from the qiskit.providers.fake_provider module such as FakeMontrealV2 where the value for the dt attribute (and the Target.dt attribute) were not properly being converted to seconds. This would cause issues when using these fake backends with scheduling.

  • Fixed a bug in plot_histogram() when the number_to_keep argument was smaller that the number of keys. The following code will no longer throw errors and will be properly aligned:

    from qiskit.visualization import plot_histogram
    data = {'00': 3, '01': 5, '11': 8, '10': 11}
    plot_histogram(data, number_to_keep=2)
  • Improved the performance of building and working with parameterized QuantumCircuit instances with many gates that share a relatively small number of parameters.

  • The OpenQASM 3 exporter (qiskit.qasm3) will no longer attempt to produce definitions for non-standard gates in the basis_gates option.

  • Fixed the getter of OptimizerResult.nit, which previously returned the number of Jacobian evaluations instead of the number of iterations.

  • Fixed a bug in the string representation of Result objects that caused the attributes to be specified incorrectly.

  • Fixed an issue with transpile() where in some cases providing a list of basis gate strings with the basis_gates keyword argument or implicitly via a Target input via the target keyword argument would not be interpreted correctly and result in a subset of the listed gates being used for each circuit.

  • Fixed an issue in the UnitarySynthesis transpiler pass which would result in an error when a Target that didn’t have any qubit restrictions on the operations (e.g. in the case of an ideal simulator target) was specified with the target keyword argument for the constructor.

  • The method qiskit.result.marginal_counts(), when passed a Result from a pulse backend, would fail, because it contains an array of ExperimentResult objects, each of which have an QobjExperimentHeader, and those ExperimentHeaders lack creg_sizes instance-variables. If the Result came from a simulator backend (e.g. Aer), that instance-variable would be there. We fix marginal_counts so that it skips logic that needs creg_sizes if the field is not present, or non-None.

  • The OpenQASM 2 exporter (QuantumCircuit.qasm()) will now correctly define the qubit parameters for UnitaryGate operations that do not affect all the qubits they are defined over. Fixed #8224 (opens in a new tab).

  • Fixed an issue with reproducibility of the transpile() function when running with optimization_level 1, 2, and 3. Previously, under some conditions when there were multiple perfect layouts (a layout that doesn’t require any SWAP gates) available the selected layout and output circuit could vary regardless of whether the seed_transpiler argument was set.

Aer 0.10.4

No change

IBM Q Provider 0.19.2

Bug Fixes

  • In the upcoming terra release there will be a release candidate tagged prior to the final release. However changing the version string for the package is blocked on the qiskit-ibmq-provider right now because it is trying to parse the version and is assuming there will be no prelease suffix on the version string (see #8200 (opens in a new tab) for the details). PR #1135 (opens in a new tab) fixes this version parsing to use the regex from the pypa/packaging project which handles all the PEP440 package versioning include pre-release suffixes. This will enable terra to release an 0.21.0rc1 tag without breaking the qiskit-ibmq-provider.
  • threading.currentThread and notifyAll were deprecated in Python 3.10 (October 2021) and will be removed in Python 3.12 (October 2023). PR #1133 (opens in a new tab) replaces them with threading.current_thread, notify_all added in Python 2.6 (October 2008).


Terra 0.21.1

Bug Fixes

  • Fixed an issue in QuantumCircuit.decompose() method when passing in a list of Gate classes for the gates_to_decompose argument. If any gates in the circuit had a label set this argument wouldn’t be handled correctly and caused the output decomposition to incorrectly skip gates explicitly in the gates_to_decompose list.

  • Fix to_instruction() which previously tried to create a UnitaryGate without exponentiating the operator to evolve. Since this operator is generally not unitary, this raised an error (and if the operator would have been unitary by chance, it would not have been the expected result).

    Now calling to_instruction() correctly produces a gate that implements the time evolution of the operator it holds:

    >>> from qiskit.opflow import EvolvedOp, X
    >>> op = EvolvedOp(0.5 * X)
    >>> op.to_instruction()
        name='unitary', num_qubits=1, num_clbits=0,
        params=[array([[0.87758256+0.j, 0.-0.47942554j], [0.-0.47942554j, 0.87758256+0.j]])]
  • Fixed an issue with the marginal_distribution() function: when a numpy array was passed in for the indices argument the function would raise an error. Fixed #8283 (opens in a new tab)

  • Previously it was not possible to adjoint a CircuitStateFn that has been constructed from a VectorStateFn. That’s because the statevector has been converted to a circuit with the Initialize instruction, which is not unitary. This problem is now fixed by instead using the StatePreparation instruction, which can be used since the state is assumed to start out in the all 0 state.

    For example we can now do:

    from qiskit import QuantumCircuit
    from qiskit.opflow import StateFn
    left = StateFn([0, 1])
    left_circuit = left.to_circuit_op().primitive
    right_circuit = QuantumCircuit(1)
    overlap = left_circuit.inverse().compose(right_circuit)  # this line raised an error before!
  • Fix a bug in the Optimizer classes where re-constructing a new optimizer instance from a previously exisiting settings reset both the new and previous optimizer settings to the defaults. This notably led to a bug if Optimizer objects were send as input to Qiskit Runtime programs.

    Now optimizer objects are correctly reconstructed:

    >>> from qiskit.algorithms.optimizers import COBYLA
    >>> original = COBYLA(maxiter=1)
    >>> reconstructed = COBYLA(**original.settings)
    >>> reconstructed._options["maxiter"]
    1  # used to be 1000!
  • Fixed an issue where the limit_amplitude argument on an individual SymbolicPulse or Waveform instance was not properly reflected by parameter validation. In addition, QPY schedule dump() has been fixed to correctly store the limit_amplitude value tied to the instance, rather than saving the global class variable.

  • Fix the pairwise entanglement structure for NLocal circuits. This led to a bug in the ZZFeatureMap, where using entanglement="pairwise" raised an error. Now it correctly produces the desired feature map:

    from qiskit.circuit.library import ZZFeatureMap
    encoding = ZZFeatureMap(4, entanglement="pairwise", reps=1)

    The above prints:

    q_0: ┤ H ├┤ P(2.0*x[0]) ├──■────────────────────────────────────■────────────────────────────────────────────
    q_1: ┤ H ├┤ P(2.0*x[1]) ├┤ X ├┤ P(2.0*- x[0])*- x[1])) ├┤ X ├──■────────────────────────────────────■──
    q_2: ┤ H ├┤ P(2.0*x[2]) ├──■────────────────────────────────────■──┤ X ├┤ P(2.0*- x[1])*- x[2])) ├┤ X ├
    q_3: ┤ H ├┤ P(2.0*x[3]) ├┤ X ├┤ P(2.0*- x[2])*- x[3])) ├┤ X ├──────────────────────────────────────────
  • Fixed an issue in handling the global phase of the UCGate class.

Aer 0.10.4

No change

IBM Q Provider 0.19.2

No change


Terra 0.21.2


Qiskit Terra 0.21.2 is a primarily a bugfix release, and also comes with several improved documentation pages.

Bug Fixes

  • aer_simulator_statevector_gpu will now be recognized correctly as statevector method in some function when using Qiskit Aer’s GPU simulators in QuantumInstance and other algorithm runners.

  • Fixed the UCGate.inverse() method which previously did not invert the global phase.

  • QuantumCircuit.compose() will now function correctly when used with the inplace=True argument within control-flow builder contexts. Previously the instructions would be added outside the control-flow scope. Fixed #8433 (opens in a new tab).

  • Fixed a bug where a bound ParameterExpression was not identified as real if symengine was installed and the bound expression was not a plain 1j. For example:

    from qiskit.circuit import Parameter
    x = Parameter("x")
    expr = 1j * x
    bound = expr.bind({x: 2})
    print(bound.is_real())  # used to be True, but is now False
  • Fixed QPY serialisation and deserialisation of ControlledGate with open controls (i.e. those whose ctrl_state is not all ones). Fixed #8549 (opens in a new tab).

  • All fake backends in qiskit.providers.fake_provider.backends have been updated to return the corresponding pulse channel objects with the method call of drive_channel(), measure_channel(), acquire_channel(), control_channel().

  • Fixed support for running Z2Symmetries.taper() on larger problems. Previously, the method would require a large amount of memory which would typically cause failures for larger problem. As a side effect of this fix the performance has significantly improved.

Aer 0.10.4

No change

IBM Q Provider 0.19.2

No change

Was this page helpful?