Skip to main contentIBM Quantum Documentation

Qiskit 0.39 release notes


0.39.5

Terra 0.22.4

Prelude

Qiskit Terra 0.22.4 is a minor bugfix release, fixing some bugs identified in the 0.22 series.

Bug Fixes

  • Fixed a bug in BackendSampler that raised an error if its run() method was called two times sequentially.

  • Fixed two bugs in the ComposedOp where the ComposedOp.to_matrix() method did not provide the correct results for compositions with StateFn and for compositions with a global coefficient. Fixed #9283(opens in a new tab).

  • Fixed the problem in which primitives, Sampler and Estimator, did not work when passed a circuit with numpy.ndarray as a parameter.

  • Fixed a bug in SamplingVQE where the aggregation argument did not have an effect. Now the aggregation function and, with it, the CVaR expectation value can correctly be specified.

  • Fixed a performance bug where SamplingVQE evaluated the energies of eigenstates in a slow manner.

  • Fixed the autoevaluation of the beta parameters in VQD, added support for SparsePauliOp inputs, and fixed the energy evaluation function to leverage the asynchronous execution of primitives, by only retrieving the job results after both jobs have been submitted.

  • Fixed an issue with the Statevector.probabilities_dict() and DensityMatrix.probabilities_dict() methods where they would return incorrect results for non-qubit systems when the qargs argument was specified. Fixed #9210(opens in a new tab)

  • Fixed handling of some classmethods by wrap_method() in Python 3.11. Previously, in Python 3.11, wrap_method would wrap the unbound function associated with the classmethod and then fail when invoked because the class object usually bound to the classmethod was not passed to the function. Starting in Python 3.11.1, this issue affected QiskitTestCase, preventing it from being imported by other test code. Fixed #9291(opens in a new tab).

Aer 0.11.2

No change

IBM Q Provider 0.19.2

No change


0.39.4

Terra 0.22.3

No change

Aer 0.11.2

New Features

  • Added support for running Qiskit Aer with Python 3.11 support.

Known Issues

  • Fix two bugs in AerStatevector. AerStatevector uses mc* instructions, which are not enabled in matrix_product_state method. This commit changes AerStatevector not to use MC* and use H, X, Y, Z, U and CX. AerStatevector also failed if an instruction is decomposed to empty QuantumCircuit. This commit allows such instruction.

Bug Fixes

  • Fixed support in the AerSimulator.from_backend() method for instantiating an AerSimulator instance from an a BackendV2 object. Previously, attempting to use AerSimulator.from_backend() with a BackendV2 object would have raised an AerError saying this wasn’t supported.

  • Fixes a bug where NoiseModel.from_backend() with a BackendV2 object may generate a noise model with excessive QuantumError s on non-Gate instructions while, for example, only ReadoutError s should be sufficient for measures. This commit updates NoiseModel.from_backend() with a BackendV2 object so that it returns the same noise model as that called with the corresponding BackendV1 object. That is, the resulting noise model does not contain any QuantumError s on measures and it may contain only thermal relaxation errors on other non-gate instructions such as resets. Note that it still contains ReadoutError s on measures.

  • Fixed a bug in NoiseModel.from_backend() where using the temperature kwarg with a non-default value would incorrectly compute the excited state population for the specified temperature. Previously, there was an additional factor of 2 in the Boltzman distribution calculation leading to an incorrect smaller value for the excited state population.

  • Fixed incorrect logic in the control-flow compiler that could allow unrelated instructions to appear “inside” control-flow bodies during execution, causing incorrect results. For example, previously:

    from qiskit import QuantumCircuit
    from qiskit_aer import AerSimulator
     
    backend = AerSimulator(method="statevector")
     
    circuit = QuantumCircuit(3, 3)
    circuit.measure(0, 0)
    circuit.measure(1, 1)
     
    with circuit.if_test((0, True)):
        with circuit.if_test((1, False)):
            circuit.x(2)
     
    with circuit.if_test((0, False)):
        with circuit.if_test((1, True)):
            circuit.x(2)
     
    circuit.measure(range(3), range(3))
    print(backend.run(circuit, method=method, shots=100).result())

    would print {'010': 100} as the nested control-flow operations would accidentally jump over the first X gate on qubit 2, which should have been executed.

  • Fixes a bug where NoiseModel.from_backend() prints verbose warnings when supplying a backend that reports un-physical device parameters such as T2 > 2 * T1 due to statistical errors in their estimation. This commit removes such warnings because they are not actionable for users in the sense that there are no means other than truncating them to the theoretical bounds as done within noise.device module. See Issue 1631(opens in a new tab) for details of the fixed bug.

  • This is fix for GPU statevector simulator. Chunk distribution tried to allocate all free memory on GPU, but this causes memory allocation error. So this fix allocates 80 percent of free memory. Also this fixes size of matrix buffer when noise sampling is applied.

  • This is a fix of AerState running with cache blocking. AerState wrongly configured transpiler of Aer for cache blocking, and then its algorithm to swap qubits worked wrongly. This fix corrects AerState to use this transpiler. More specifically, After the transpilation, a swapped qubit map is recoverd to the original map when using AerState. This fix is necessary for AerStatevector to use multiple-GPUs.

  • This is fix for AerStatevector. It was not possible to create an AerStatevector instance directly from terra’s Statevector. This fix allows a Statevector as AerStatevector’s input.

  • SamplerResult.quasi_dists contain the data about the number of qubits. QuasiDistribution.binary_probabilities() returns bitstrings with correct length.

  • Previously seed is not initialized in AerStatevector and then sampled results are always same. With this commit, a seed is initialized for each sampling and sampled results can be vary.

IBM Q Provider 0.19.2

No change


0.39.3

Terra 0.22.3

Prelude

Qiskit Terra 0.22.3 is a minor bugfix release, fixing some further bugs in the 0.22 series.

Bug Fixes

  • AdaptVQE now correctly indicates that it supports auxiliary operators.

  • The circuit drawers (QuantumCircuit.draw() and circuit_drawer()) will no longer emit a warning about the cregbundle parameter when using the default arguments, if the content of the circuit requires all bits to be drawn individually. This was most likely to appear when trying to draw circuits with new-style control-flow operations.

  • Fixed a bug causing QNSPSA to fail when max_evals_grouped was set to a value larger than 1.

  • Fixed an issue with the SabreSwap pass which would cause the output of multiple runs of the pass without the seed argument specified to reuse the same random number generator seed between runs instead of using different seeds. This previously caused identical results to be returned between runs even when no seed was specified.

  • Fixed an issue with the primitive classes, BackendSampler and BackendEstimator, where instances were not able to be serialized with pickle. In general these classes are not guaranteed to be serializable as BackendV2 and BackendV1 instances are not required to be serializable (and often are not), but the class definitions of BackendSampler and BackendEstimator no longer prevent the use of pickle.

  • The pulse.Instruction.draw() method will now succeed, as before. This method is deprecated with no replacement planned, but it should still work for the period of deprecation.

Aer 0.11.1

No change

IBM Q Provider 0.19.2

No change


0.39.2

Terra 0.22.2

Prelude

Qiskit Terra 0.22.2 is a minor bugfix release, and marks the first official support for Python 3.11.

Bug Fixes

  • Fixed an issue with the backend primitive classes BackendSampler and BackendEstimator which prevented running with a BackendV1 instance that does not have a max_experiments field set in its BackendConfiguration.

  • Fixed a bug in the VF2PostLayout pass when transpiling for backends with a defined Target, where the interaction graph would be built incorrectly. This could result in excessive runtimes due to the graph being far more complex than necessary.

  • The Pulse expression parser should no longer periodically hang when called from Jupyter notebooks. This is achieved by avoiding an internal deepycopy of a recursive object that seemed to be particularly difficult for the memoization to evaluate.

Aer 0.11.1

No change

IBM Q Provider 0.19.2

No change


0.39.1

Terra 0.22.1

Prelude

Qiskit Terra 0.22.1 is a bugfix release, addressing some minor issues identified since the 0.22.0 release.

Deprecation Notes

  • The pauli_list kwarg of pauli_basis() has been deprecated as pauli_basis() now always returns a PauliList. This argument was removed prematurely from Qiskit Terra 0.22.0 which broke compatibility for users that were leveraging the pauli_list``argument. Now, the argument has been restored but will emit a ``DeprecationWarning when used. If used it has no effect because since Qiskit Terra 0.22.0 a PauliList is always returned.

Bug Fixes

  • Fixed the BarrierBeforeFinalMeasurements transpiler pass when there are conditions on loose Clbits immediately before the final measurement layer. Previously, this would fail claiming that the bit was not present in an internal temporary circuit. Fixed #8923(opens in a new tab)

  • The equality checkers for QuantumCircuit and DAGCircuit (with objects of the same type) will now correctly handle conditions on single bits. Previously, these would produce false negatives for equality, as the bits would use “exact” equality checks instead of the “semantic” checks the rest of the properties of circuit instructions get.

  • Fixed handling of classical bits in StochasticSwap with control flow. Previously, control-flow operations would be expanded to contain all the classical bits in the outer circuit and not contracted again, leading to a mismatch between the numbers of clbits the instruction reported needing and the actual number supplied to it. Fixed #8903(opens in a new tab)

  • Fixed handling of globally defined instructions for the Target class. Previously, two methods, operations_for_qargs() and operation_names_for_qargs() would ignore/incorrectly handle any globally defined ideal operations present in the target. For example:

    from qiskit.transpiler import Target
    from qiskit.circuit.library import CXGate
     
    target = Target(num_qubits=5)
    target.add_instruction(CXGate())
    names = target.operation_names_for_qargs((1, 2))
    ops = target.operations_for_qargs((1, 2))

    will now return {"cx"} for names and [CXGate()] for ops instead of raising a KeyError or an empty return.

  • Fixed an issue in the Target.add_instruction() method where it would previously have accepted an argument with an invalid number of qubits as part of the properties argument. For example:

    from qiskit.transpiler import Target
    from qiskit.circuit.library import CXGate
     
    target = Target()
    target.add_instruction(CXGate(), {(0, 1, 2): None})

    This will now correctly raise a TranspilerError instead of causing runtime issues when interacting with the target. Fixed #8914(opens in a new tab)

  • Fixed an issue with the plot_state_hinton() visualization function which would result in a misplaced axis that was offset from the actual plot. Fixed #8446 <https://github.com/Qiskit/qiskit-terra/issues/8446(opens in a new tab)>

  • Fixed the output of the plot_state_hinton() function so that the state labels are ordered ordered correctly, and the image matches up with the natural matrix ordering. Fixed #8324(opens in a new tab)

  • Fixed an issue with the primitive classes, BackendSampler and BackendEstimator when running on backends that have a limited number of circuits in each job. Not all backends support an unlimited batch size (most hardware backends do not) and previously the backend primitive classes would have potentially incorrectly sent more circuits than the backend supported. This has been corrected so that BackendSampler and BackendEstimator will chunk the circuits into multiple jobs if the backend has a limited number of circuits per job.

  • Fixed an issue with the BackendEstimator class where previously setting a run option named monitor to a value that evaluated as True would have incorrectly triggered a job monitor that only worked on backends from the qiskit-ibmq-provider package. This has been removed so that you can use a monitor run option if needed without causing any issues.

  • Fixed an issue with the Target.build_coupling_map() method where it would incorrectly return None for a Target object with a mix of ideal globally available instructions and instructions that have qubit constraints. Now in such cases the Target.build_coupling_map() will return a coupling map for the constrained instruction (unless it’s a 2 qubit operation which will return None because globally there is no connectivity constraint). Fixed #8971(opens in a new tab)

  • Fixed an issue with the Target.qargs attribute where it would incorrectly return None for a Target object that contained any globally available ideal instruction.

  • Fixed the premature removal of the pauli_list keyword argument of the pauli_basis() function which broke existing code using the pauli_list=True future compatibility path on upgrade to Qiskit Terra 0.22.0. This keyword argument has been added back to the function and is now deprecated and will be removed in a future release.

  • Fixed an issue in QPY serialization (dump()) when a custom ControlledGate subclass that overloaded the _define() method to provide a custom definition for the operation. Previously, this case of operation was not serialized correctly because it wasn’t accounting for using the potentially _define() method to provide a definition. Fixes #8794(opens in a new tab)

  • QPY deserialisation will no longer add extra Clbit instances to the circuit if there are both loose Clbits in the circuit and more Qubits than Clbits.

  • QPY deserialisation will no longer add registers named q and c if the input circuit contained only loose bits.

  • Fixed the SparsePauliOp.dot() method when run on two operators with real coefficients. To fix this, the dtype that SparsePauliOp can take is restricted to np.complex128 and object. Fixed #8992(opens in a new tab)

  • Fixed an issue in the circuit_drawer() function and QuantumCircuit.draw() method where the only built-in style for the mpl output that was usable was default. If another built-in style, such as iqx, were used then a warning about the style not being found would be emitted and the drawer would fall back to use the default style. Fixed #8991(opens in a new tab)

  • Fixed an issue with the transpile() where it would previously fail with a TypeError if a custom Target object was passed in via the target argument and a list of multiple circuits were specified for the circuits argument.

  • Fixed an issue with transpile() when targeting a Target (either directly via the target argument or via a BackendV2 instance from the backend argument) that contained an ideal Measure instruction (one that does not have any properties defined). Previously this would raise an exception trying to parse the target. Fixed #8969(opens in a new tab)

  • Fixed an issue with the VF2Layout pass where it would error when running with a Target that had instructions that were missing error rates. This has been corrected so in such cases the lack of an error rate will be treated as an ideal implementation and if no error rates are present it will just select the first matching layout. Fixed #8970(opens in a new tab)

  • Fixed an issue with the VF2PostLayout pass where it would error when running with a Target that had instructions that were missing. In such cases the lack of an error rate will be treated as an ideal implementation of the operation.

  • Fixed an issue with the VQD class if more than k=2 eigenvalues were computed. Previously this would fail due to an internal type mismatch, but now runs as expected. Fixed #8982(opens in a new tab)

  • Fixed a performance bug where the new primitive-based variational algorithms minimum_eigensolvers.VQE, eigensolvers.VQD and SamplingVQE did not batch energy evaluations per default, which resulted in a significant slowdown if a hardware backend was used.

  • Zero-operand gates and instructions will now work with circuit_to_gate(), QuantumCircuit.to_gate(), Gate.control(), and the construction of an Operator from a QuantumCircuit containing zero-operand instructions. This edge case is occasionally useful in creating global-phase gates as part of larger compound instructions, though for many uses, QuantumCircuit.global_phase may be more appropriate.

  • Fixes issue where Statevector.evolve() and DensityMatrix.evolve() would raise an exeception for nested subsystem evolution for non-qubit subsystems. Fixes issue #8897(opens in a new tab)

  • Fixes bug in Statevector.evolve() where subsystem evolution will return the incorrect value in certain cases where there are 2 or more than non-evolved subsystems with different subsystem dimensions. Fixes issue #8899(opens in a new tab)

Aer 0.11.1

Bug Fixes

  • Fixed a potential build error when trying to use CMake 3.18 or newer and building qiskit-aer with GPU support enabled. Since CMake 3.18 or later when building with CUDA the CMAKE_CUDA_ARCHITECTURES was required to be set with the architecture value for the target GPU. This has been corrected so that setting AER_CUDA_ARCH will be used if this was not set.

  • Fixes a bug in the handling of instructions with clbits in LocalNoisePass. Previously, it was accidentally erasing clbits of instructions (e.g. measures) to which the noise is applied in the case of method="append".

  • Fixed the performance overhead of the Sampler class when running with identical circuits on multiple executions. This was accomplished by skipping/caching the transpilation of these identical circuits on subsequent executions.

  • Fixed compatibility of the Sampler(opens in a new tab) and Estimator primitive classes with qiskit-terra 0.22.0 release. In qiskit-terra 0.22.0 breaking API changes were made to the abstract interface which broke compatibility with these classes, this has been addressed so that Sampler(opens in a new tab) and Estimator can now be used with qiskit-terra >= 0.22.0.

IBM Q Provider 0.19.2

No change


0.39.0

This release also officially deprecates the Qiskit Aer project as part of the Qiskit metapackage. This means that in a future release pip install qiskit will no longer include qiskit-aer. If you’re currently installing or listing qiskit as a dependency to get Aer you should upgrade this to explicitly list qiskit-aer as well.

The qiskit-aer project is still active and maintained moving forward but for the Qiskit metapackage (i.e. what gets installed via pip install qiskit) the project is moving towards a model where the Qiskit package only contains the common core functionality for building and compiling quantum circuits, programs, and applications and packages that build on it or link Qiskit to hardware or simulators are separate packages.

Terra 0.22.0

Prelude

The Qiskit Terra 0.22.0 release is a major feature release that includes a myriad of new feature and bugfixes. The highlights for this release are:

New Features

  • Add support for representing an operation that has a variable width to the Target class. Previously, a Target object needed to have an instance of Operation defined for each operation supported in the target. This was used for both validation of arguments and parameters of the operation. However, for operations that have a variable width this wasn’t possible because each instance of an Operation class can only have a fixed number of qubits. For cases where a backend supports variable width operations the instruction can be added with the class of the operation instead of an instance. In such cases the operation will be treated as globally supported on all qubits. For example, if building a target like:

    from qiskit.circuit import Parameter, Measure, IfElseOp, ForLoopOp, WhileLoopOp
    from qiskit.circuit.library import IGate, RZGate, SXGate, XGate, CXGate
    from qiskit.transpiler import Target, InstructionProperties
     
    theta = Parameter("theta")
     
    ibm_target = Target()
    i_props = {
        (0,): InstructionProperties(duration=35.5e-9, error=0.000413),
        (1,): InstructionProperties(duration=35.5e-9, error=0.000502),
        (2,): InstructionProperties(duration=35.5e-9, error=0.0004003),
        (3,): InstructionProperties(duration=35.5e-9, error=0.000614),
        (4,): InstructionProperties(duration=35.5e-9, error=0.006149),
    }
    ibm_target.add_instruction(IGate(), i_props)
    rz_props = {
        (0,): InstructionProperties(duration=0, error=0),
        (1,): InstructionProperties(duration=0, error=0),
        (2,): InstructionProperties(duration=0, error=0),
        (3,): InstructionProperties(duration=0, error=0),
        (4,): InstructionProperties(duration=0, error=0),
    }
    ibm_target.add_instruction(RZGate(theta), rz_props)
    sx_props = {
        (0,): InstructionProperties(duration=35.5e-9, error=0.000413),
        (1,): InstructionProperties(duration=35.5e-9, error=0.000502),
        (2,): InstructionProperties(duration=35.5e-9, error=0.0004003),
        (3,): InstructionProperties(duration=35.5e-9, error=0.000614),
        (4,): InstructionProperties(duration=35.5e-9, error=0.006149),
    }
    ibm_target.add_instruction(SXGate(), sx_props)
    x_props = {
        (0,): InstructionProperties(duration=35.5e-9, error=0.000413),
        (1,): InstructionProperties(duration=35.5e-9, error=0.000502),
        (2,): InstructionProperties(duration=35.5e-9, error=0.0004003),
        (3,): InstructionProperties(duration=35.5e-9, error=0.000614),
        (4,): InstructionProperties(duration=35.5e-9, error=0.006149),
    }
    ibm_target.add_instruction(XGate(), x_props)
    cx_props = {
        (3, 4): InstructionProperties(duration=270.22e-9, error=0.00713),
        (4, 3): InstructionProperties(duration=305.77e-9, error=0.00713),
        (3, 1): InstructionProperties(duration=462.22e-9, error=0.00929),
        (1, 3): InstructionProperties(duration=497.77e-9, error=0.00929),
        (1, 2): InstructionProperties(duration=227.55e-9, error=0.00659),
        (2, 1): InstructionProperties(duration=263.11e-9, error=0.00659),
        (0, 1): InstructionProperties(duration=519.11e-9, error=0.01201),
        (1, 0): InstructionProperties(duration=554.66e-9, error=0.01201),
    }
    ibm_target.add_instruction(CXGate(), cx_props)
    measure_props = {
        (0,): InstructionProperties(duration=5.813e-6, error=0.0751),
        (1,): InstructionProperties(duration=5.813e-6, error=0.0225),
        (2,): InstructionProperties(duration=5.813e-6, error=0.0146),
        (3,): InstructionProperties(duration=5.813e-6, error=0.0215),
        (4,): InstructionProperties(duration=5.813e-6, error=0.0333),
    }
    ibm_target.add_instruction(Measure(), measure_props)
    ibm_target.add_instruction(IfElseOp, name="if_else")
    ibm_target.add_instruction(ForLoopOp, name="for_loop")
    ibm_target.add_instruction(WhileLoopOp, name="while_loop")

    The IfElseOp, ForLoopOp, and WhileLoopOp operations are globally supported for any number of qubits. This is then reflected by other calls in the Target API such as instruction_supported():

    ibm_target.instruction_supported(operation_class=WhileLoopOp, qargs=(0, 2, 3, 4))
    ibm_target.instruction_supported('if_else', qargs=(0, 1))

    both return True.

  • Added new primitive implementations, BackendSampler and BackendEstimator, to qiskit.primitives. Thes new primitive class implementation wrap a BackendV1 or BackendV2 instance as a BaseSampler or BaseEstimator respectively. The intended use case for these primitive implementations is to bridge the gap between providers that do not have native primitive implementations and use that provider’s backend with APIs that work with primitives. For example, the SamplingVQE class takes a BaseSampler instance to function. If you’d like to run that class with a backend from a provider without a native primitive implementation you can construct a BackendSampler to do this:

    from qiskit.algorithms.minimum_eigensolvers import SamplingVQE
    from qiskit.algorithms.optimizers import SLSQP
    from qiskit.circuit.library import TwoLocal
    from qiskit.primitives import BackendSampler
    from qiskit.providers.fake_provider import FakeHanoi
    from qiskit.opflow import PauliSumOp
    from qiskit.quantum_info import SparsePauliOp
     
    backend = FakeHanoi()
    sampler = BackendSampler(backend=backend)
     
    operator = PauliSumOp(SparsePauliOp(["ZZ", "IZ", "II"], coeffs=[1, -0.5, 0.12]))
    ansatz = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz")
    optimizer = SLSQP()
    sampling_vqe = SamplingVQE(sampler, ansatz, optimizer)
    result = sampling_vqe.compute_minimum_eigenvalue(operator)
    eigenvalue = result.eigenvalue

    If you’re using a provider that has native primitive implementations (such as qiskit-ibm-runtime or qiskit-aer) it is always a better choice to use that native primitive implementation instead of BackendEstimator or BackendSampler as the native implementations will be much more efficient and/or do additional pre and post processing. BackendEstimator and BackendSampler are designed to be generic that can work with any backend that returns Counts in their Results which precludes additional optimization.

  • Added a new algorithm class, AdaptVQE to qiskit.algorithms This algorithm uses a qiskit.algorithms.minimum_eigensolvers.VQE in combination with a pool of operators from which to build out an qiskit.circuit.library.EvolvedOperatorAnsatz adaptively. For example:

    from qiskit.algorithms.minimum_eigensolvers import AdaptVQE, VQE
    from qiskit.algorithms.optimizers import SLSQP
    from qiskit.primitives import Estimator
    from qiskit.circuit.library import EvolvedOperatorAnsatz
     
    # get your Hamiltonian
    hamiltonian = ...
     
    # construct your ansatz
    ansatz = EvolvedOperatorAnsatz(...)
     
    vqe = VQE(Estimator(), ansatz, SLSQP())
     
    adapt_vqe = AdaptVQE(vqe)
     
    result = adapt_vqe.compute_minimum_eigenvalue(hamiltonian)
  • The BackendV2 class now has support for two new optional hook points enabling backends to inject custom compilation steps as part of transpile() and generate_preset_pass_manager(). If a BackendV2 implementation includes the methods get_scheduling_stage_plugin() or get_translation_stage_plugin() the transpiler will use the returned string as the default value for the scheduling_method and translation_method arguments. This enables backends to run additional custom transpiler passes when targetting that backend by leveraging the transpiler stage plugin interface. For more details on how to use this see: Custom Transpiler Passes.

  • Added a new keyword argument, ignore_backend_supplied_default_methods, to the transpile() function which can be used to disable a backend’s custom selection of a default method if the target backend has get_scheduling_stage_plugin() or get_translation_stage_plugin() defined.

  • Added a label parameter to the Barrier class’s constructor and the barrier() method which allows a user to assign a label to an instance of the Barrier directive. For visualizations generated with circuit_drawer() or QuantumCircuit.draw() this label will be printed at the top of the barrier.

    from qiskit import QuantumCircuit
     
    circuit = QuantumCircuit(2)
    circuit.h(0)
    circuit.h(1)
    circuit.barrier(label="After H")
    circuit.draw('mpl')
  • Add new gates CCZGate, CSGate, and CSdgGate to the standard gates in the Circuit Library (qiskit.circuit.library).

  • Added qiskit.algorithms.eigensolvers package to include interfaces for primitive-enabled algorithms. This new module will eventually replace the previous qiskit.algorithms.eigen_solvers. This new module contains an alternative implementation of the VQD which instead of taking a backend or QuantumInstance instead takes an instance of BaseEstimator, including Estimator, BackendEstimator, or any provider implementations such as those as those present in qiskit-ibm-runtime and qiskit-aer.

    For example, to use the new implementation with an instance of Estimator class:

    from qiskit.algorithms.eigensolvers import VQD
    from qiskit.algorithms.optimizers import SLSQP
    from qiskit.circuit.library import TwoLocal
    from qiskit.primitives import Sampler, Estimator
    from qiskit.algorithms.state_fidelities import ComputeUncompute
    from qiskit.opflow import PauliSumOp
    from qiskit.quantum_info import SparsePauliOp
     
    h2_op = PauliSumOp(SparsePauliOp(
        ["II", "IZ", "ZI", "ZZ", "XX"],
        coeffs=[
            -1.052373245772859,
            0.39793742484318045,
            -0.39793742484318045,
            -0.01128010425623538,
            0.18093119978423156,
        ],
    ))
     
    estimator = Estimator()
    ansatz = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz")
    optimizer = SLSQP()
    fidelity = ComputeUncompute(Sampler())
     
    vqd = VQD(estimator, fidelity, ansatz, optimizer, k=2)
    result = vqd.compute_eigenvalues(h2_op)
    eigenvalues = result.eigenvalues

    Note that the evaluated auxillary operators are now obtained via the aux_operators_evaluated field on the results. This will consist of a list or dict of tuples containing the expectation values for these operators, as we well as the metadata from primitive run. aux_operator_eigenvalues is no longer a valid field.

  • Added new algorithms to calculate state fidelities/overlaps for pairs of quantum circuits (that can be parametrized). Apart from the base class (BaseStateFidelity) which defines the interface, there is an implementation of the compute-uncompute method that leverages instances of the BaseSampler primitive: qiskit.algorithms.state_fidelities.ComputeUncompute.

    For example:

    import numpy as np
    from qiskit.primitives import Sampler
    from qiskit.algorithms.state_fidelities import ComputeUncompute
    from qiskit.circuit.library import RealAmplitudes
     
    sampler = Sampler(...)
    fidelity = ComputeUncompute(sampler)
    circuit = RealAmplitudes(2)
    values = np.random.random(circuit.num_parameters)
    shift = np.ones_like(values) * 0.01
     
    job = fidelity.run([circuit], [circuit], [values], [values+shift])
    fidelities = job.result().fidelities
  • Added a new module qiskit.algorithms.gradients that contains classes which are used to compute gradients using the primitive interfaces defined in qiskit.primitives. There are 4 types of gradient classes: Finite Difference, Parameter Shift, Linear Combination of Unitary, and SPSA with implementations that either use an instance of the BaseEstimator interface:

    or an instance of the BaseSampler interface:

    The estimator-based gradients compute the gradient of expectation values, while the sampler-based gradients return gradients of the measurement outcomes (also referred to as “probability gradients”).

    For example:

    estimator = Estimator(...)
    gradient = ParamShiftEstimatorGradient(estimator)
    job = gradient.run(circuits, observables, parameters)
    gradients = job.result().gradients
  • The Grover class has a new keyword argument, sampler which is used to run the algorithm using an instance of the BaseSampler interface to calculate the results. This new argument supersedes the the quantum_instance argument and accordingly, quantum_instance is pending deprecation and will be deprecated and subsequently removed in future releases.

    Example:

    from qiskit import QuantumCircuit
    from qiskit.primitives import Sampler
    from qiskit.algorithms import Grover, AmplificationProblem
     
    sampler = Sampler()
    oracle = QuantumCircuit(2)
    oracle.cz(0, 1)
    problem = AmplificationProblem(oracle, is_good_state=["11"])
    grover = Grover(sampler=sampler)
    result = grover.amplify(problem)
  • A new option, "formatter.control.fill_waveform" has been added to the pulse drawer (pulse_v2.draw() and Schedule.draw()) style sheets. This option can be used to remove the face color of pulses in the output visualization which allows for drawing pulses only with lines.

    For example:

    from qiskit.visualization.pulse_v2 import IQXStandard
     
    my_style = IQXStandard(
        **{"formatter.control.fill_waveform": False, "formatter.line_width.fill_waveform": 2}
    )
     
    my_sched.draw(style=my_style)
  • Added a new transpiler pass, ResetAfterMeasureSimplification, which is used to replace a Reset operation after a Measure with a conditional XGate. This pass can be used on backends where a Reset operation is performed by doing a measurement and then a conditional X gate so that this will remove the duplicate implicit Measure from the Reset operation. For example:

    from qiskit import QuantumCircuit
    from qiskit.transpiler.passes import ResetAfterMeasureSimplification
     
    qc = QuantumCircuit(1)
    qc.measure_all()
    qc.reset(0)
    qc.draw('mpl')
    result = ResetAfterMeasureSimplification()(qc)
    result.draw('mpl')
  • Added a new supported value, "reverse_linear" for the entanglement keyword argument to the constructor for the NLocal circuit class. For TwoLocal circuits (which are subclassess of NLocal), if entanglement_blocks="cx" then using entanglement="reverse_linear" provides an equivalent n-qubit circuit as entanglement="full" but with only n1n-1 CXGate gates, instead of n(n1)2\frac{n(n-1)}{2}.

  • ScheduleBlock has been updated so that it can manage unassigned subroutine, in other words, to allow lazy calling of other programs. For example, this enables the following workflow:

    from qiskit import pulse
     
    with pulse.build() as prog:
      pulse.reference("x", "q0")
     
    with pulse.build() as xq0:
      pulse.play(Gaussian(160, 0.1, 40), pulse.DriveChannel(0))
     
    prog.assign_references({("x", "q0"): xq0})

    Now a user can create prog without knowing actual implementation of the reference ("x", "q0"), and assign it at a later time for execution. This improves modularity of pulse programs, and thus one can easily write a template pulse program relying on other calibrations.

    To realize this feature, the new pulse instruction (compiler directive) Reference has been added. This instruction is injected into the current builder scope when the reference() command is used. All references defined in the current pulse program can be listed with the references property.

    In addition, every reference is managed with a scope to ease parameter management. scoped_parameters() and search_parameters() have been added to ScheduleBlock. See API documentation for more details.

  • Added a new method SparsePauliOp.argsort(), which returns the composition of permutations in the order of sorting by coefficient and sorting by Pauli. By using the weight keyword argument for the method the output can additionally be sorted by the number of non-identity terms in the Pauli, where the set of all Paulis of a given weight are still ordered lexicographically.

  • Added a new method SparsePauliOp.sort(), which will first sort the coefficients using numpy’s argsort() and then sort by Pauli, where the Pauli sort takes precedence. If the Pauli sort is the same, it will then be sorted by coefficient. By using the weight keyword argument the output can additionally be sorted by the number of non-identity terms in the Pauli, where the set of all Paulis of a given weight are still ordered lexicographically.

  • Added a new keyword argument, wire_order, to the circuit_drawer() function and QuantumCircuit.draw() method which allows arbitrarily reordering both the quantum and classical bits in the output visualization. For example:

    from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
     
    qr = QuantumRegister(4, "q")
    cr = ClassicalRegister(4, "c")
    cr2 = ClassicalRegister(2, "ca")
    circuit = QuantumCircuit(qr, cr, cr2)
    circuit.h(0)
    circuit.h(3)
    circuit.x(1)
    circuit.x(3).c_if(cr, 10)
    circuit.draw('mpl', cregbundle=False, wire_order=[2, 1, 3, 0, 6, 8, 9, 5, 4, 7])
  • Added support for the CSGate, CSdgGate and CCZGate classes to the constructor for the operator class CNOTDihedral. The input circuits when creating a CNOTDihedral operator will now support circuits using these gates. For example:

    from qiskit import QuantumCircuit
    from qiskit.quantum_info import CNOTDihedral
     
    qc = QuantumCircuit(2)
    qc.t(0)
    qc.cs(0, 1)
    qc.tdg(0)
    operator = CNOTDihedral(qc)
  • The amplitude estimation algorithm classes:

    Now have a new keyword argument, sampler on their constructor that takes an instance of an object that implements the BaseSampler interface including BackendSampler, Sampler, or any provider implementations such as those as those present in qiskit-ibm-runtime and qiskit-aer. This provides an alternative to using the quantum_instance argument to set the target Backend or QuantumInstance to run the algorithm on. Using a QuantumInstance is pending deprecation and will be deprecated in a future release.

  • Added a new class, BackendV2Converter, which is used to wrap a BackendV1 instance in a BackendV2 interface. It enables you to have a BackendV2 instance from any BackendV1. This enables standardizing access patterns on the newer BackendV2 interface even if you still support BackendV1.

  • Added a new function convert_to_target() which is used to take a BackendConfiguration, and optionally a BackendProperties and PulseDefaults and create a Target object equivalent to the contents of those objects.

  • qiskit.quantum_info.BaseOperator subclasses (such as ScalarOp, SparsePauliOp and PauliList) can now be used with the built-in Python sum() function.

  • A new transpiler pass, ConvertConditionsToIfOps was added, which can be used to convert old-style Instruction.c_if()-conditioned instructions into IfElseOp objects. This is to help ease the transition from the old type to the new type for backends. For most users, there is no need to add this to your pass managers, and it is not included in any preset pass managers.

  • Refactored gate commutativity analysis into a class CommutationChecker. This class allows you to check (based on matrix multiplication) whether two gates commute or do not commute, and to cache the results (so that a similar check in the future will no longer require matrix multiplication).

    For example we can now do:

    from qiskit.circuit import QuantumRegister, CommutationChecker
     
    comm_checker = CommutationChecker()
    qr = QuantumRegister(4)
     
    res = comm_checker.commute(CXGate(), [qr[1], qr[0]], [], CXGate(), [qr[1], qr[2]], [])

    As the two CX gates commute (the first CX gate is over qubits qr[1] and qr[0], and the second CX gate is over qubits qr[1] and qr[2]), we will have that res is True.

    This commutativity checking is over-conservative for conditional and parameterized gates, and may return False even when such gates commute.

  • Added a new transpiler pass CommutativeInverseCancellation that cancels pairs of inverse gates exploiting commutation relations between gates. This pass is a generalization of the transpiler pass InverseCancellation as it detects a larger set of inverse gates, and as it takes commutativity into account. The pass also avoids some problems associated with the transpiler pass CommutativeCancellation.

    For example:

    from qiskit.circuit import QuantumCircuit
    from qiskit.transpiler import PassManager
    from qiskit.transpiler.passes import CommutativeInverseCancellation
     
    circuit = QuantumCircuit(2)
    circuit.z(0)
    circuit.x(1)
    circuit.cx(0, 1)
    circuit.z(0)
    circuit.x(1)
     
    passmanager = PassManager(CommutativeInverseCancellation())
    new_circuit = passmanager.run(circuit)

    cancels the pair of self-inverse Z-gates, and the pair of self-inverse X-gates (as the relevant gates commute with the CX-gate), producing a circuit consisting of a single CX-gate.

    The inverse checking is over-conservative for conditional and parameterized gates, and may not cancel some of such gates.

  • QuantumCircuit.compose() will now accept an operand with classical bits if the base circuit has none itself. The pattern of composing a circuit with measurements onto a quantum-only circuit is now valid. For example:

    from qiskit import QuantumCircuit
     
    base = QuantumCircuit(3)
    terminus = QuantumCircuit(3, 3)
    terminus.measure_all()
     
    # This will now succeed, though it was previously a CircuitError.
    base.compose(terminus)
  • The DAGCircuit methods depth() and size() have a new recurse keyword argument for use with circuits that contain control-flow operations (such as IfElseOp, WhileLoopOp, and ForLoopOp). By default this is False and will raise an error if control-flow operations are present, to avoid poorly defined results. If set to True, a proxy value that attempts to fairly weigh each control-flow block relative to its condition is returned, even though the depth or size of a concrete run is generally unknowable. See each method’s documentation for how each control-flow operation affects the output.

  • DAGCircuit.count_ops() gained a recurse keyword argument for recursing into control-flow blocks. By default this is True, and all operations in all blocks will be returned, as well as the control-flow operations themselves.

  • Added an argument create_preds_and_succs to the functions circuit_to_dagdependency() and dag_to_dagdependency() that convert from QuantumCircuit and DAGCircuit, respectively, to DAGDependency. When the value of create_preds_and_succs is False, the transitive predecessors and successors for nodes in DAGDependency are not constructed, making the conversions faster and significantly less memory-intensive. The direct predecessors and successors for nodes in DAGDependency are constructed as usual.

    For example:

    from qiskit.converters import circuit_to_dagdependency
    from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
     
    circuit_in = QuantumCircuit(2)
    circuit_in.h(qr[0])
    circuit_in.h(qr[1])
     
    dag_dependency = circuit_to_dagdependency(circuit_in, create_preds_and_succs=False)
  • Added new attributes Clifford.symplectic_matrix, Clifford.tableau, Clifford.z, Clifford.x, Clifford.phase, Clifford.stab, Clifford.stab_z, Clifford.stab_x, Clifford.stab_phase, Clifford.destab, Clifford.destab_z, Clifford.destab_x, Clifford.destab_phase to the Clifford class. These can be used instead of Clifford.table, that will be deprecated in the future. StabilizerTable and PauliTable are pending deprecation and will be deprecated in the future release and subsequently removed after that.

  • The Commuting2qGateRouter constructor now has a new keyword argument, edge_coloring. This argument is used to provide an edge coloring of the coupling map to determine the order in which the commuting gates are applied.

  • Added a new algorithms interface for creating time evolution algorithms using the primitives BaseSampler and BaseEstimator. This new interface consists of:

    This new interface is an alternative to the previously existing time evolution algorithms interface available defined with EvolutionProblem, EvolutionResult, RealEvolver, and ImaginaryEvolver which worked with a QuantumInstance object instead of primitives. This new interface supersedes the previous interface which will eventually be deprecated and subsequently removed in future releases.

  • Added new backend classes to qiskit.providers.fake_provider:

    These new classes implement the BackendV2 interface and are created using stored snapshots of the backend information from the IBM Quantum systems ibm_auckland, ibm_oslo, ibm_geneva, and ibm_perth systems respectively.

  • The Z2Symmetries class has two new methods, convert_clifford() and taper_clifford(). These two methods are the two operations necessary for taperng an operator based on the Z2 symmetries in the object and were previously performed internally via the taper() method. However, these methods are now public methods of the class which can be called individually if needed.

  • The runtime performance for conjugation of a long PauliList object by a Clifford using the PauliList.evolve() has significantly improved. It will now run significantly faster than before.

  • Added a new abstract class ClassicalIOChannel to the qiskit.pulse.channels module. This class is used to represent classical I/O channels and differentiate these channels from other subclasses of Channel. This new class is the base class for the MemorySlot, RegisterSlot, and SnapshotChannel classes. Accordingly, the pad() canonicalization pulse transform in qiskit.pulse.transforms will not introduce delays to any instances of ClassicalIOChannel

  • The SabreSwap transpiler pass has a new keyword argument on its constructor, trials. The trials argument is used to specify the number of random seed trials to attempt. The output from the SABRE algorithm(opens in a new tab) can differ greatly based on the seed used for the random number. SabreSwap will now run the algorithm with trials number of random seeds and pick the best (with the fewest swaps inserted). If trials is not specified the pass will default to use the number of physical CPUs on the local system.

  • The SabreLayout transpiler pass has a new keyword argument on its constructor, swap_trials. The swap_trials argument is used to specify how many random seed trials to run on the SabreSwap pass internally. It corresponds to the trials arugment on the SabreSwap pass. When set, each iteration of SabreSwap will be run internally swap_trials times. If swap_trials is not specified the will default to use the number of physical CPUs on the local system.

  • Added a new function, estimate_observables() which uses an implementation of the BaseEstimator interface (e.g. Estimator, BackendEstimator, or any provider implementations such as those as those present in qiskit-ibm-runtime and qiskit-aer) to calculate the expectation values, their means and standard deviations from a list or dictionary of observables. This serves a similar purpose to the pre-existing function eval_observables() which performed the calculation using a QuantumInstance object and has been superseded (and will be deprecated and subsequently removed in future releases) by this new function.

  • Added a new Operation base class which provides a lightweight abstract interface for objects that can be put on QuantumCircuit. This allows to store “higher-level” objects directly on a circuit (for instance, Clifford objects), to directly combine such objects (for instance, to compose several consecutive Clifford objects over the same qubits), and to synthesize such objects at run time (for instance, to synthesize Clifford in a way that optimizes depth and/or exploits device connectivity). Previously, only subclasses of qiskit.circuit.Instruction could be put on QuantumCircuit, but this interface has become unwieldy and includes too many methods and attributes for general-purpose objects.

    The new Operation interface includes name, num_qubits and num_clbits (in the future this may be slightly adjusted), but importantly does not include definition (and thus does not tie synthesis to the object), does not include condition (this should be part of separate classical control flow), and does not include duration and unit (as these are properties of the output of the transpiler).

    As of now, Operation includes Gate, Reset, Barrier, Measure, and “higher-level” objects such as Clifford. This list of “higher-level” objects will grow in the future.

  • A Clifford is now added to a quantum circuit as an Operation, without first synthesizing a subcircuit implementing this Clifford. The actual synthesis is postponed to a later HighLevelSynthesis transpilation pass.

    For example, the following code:

    from qiskit import QuantumCircuit
    from qiskit.quantum_info import random_clifford
     
    qc = QuantumCircuit(3)
    cliff = random_clifford(2)
    qc.append(cliff, [0, 1])

    no longer converts cliff to qiskit.circuit.Instruction, which includes synthesizing the clifford into a circuit, when it is appended to qc.

  • Added a new transpiler pass OptimizeCliffords that collects blocks of consecutive Clifford objects in a circuit, and replaces each block with a single Clifford.

    For example, the following code:

    from qiskit import QuantumCircuit
    from qiskit.quantum_info import random_clifford
    from qiskit.transpiler.passes import OptimizeCliffords
    from qiskit.transpiler import PassManager
     
    qc = QuantumCircuit(3)
    cliff1 = random_clifford(2)
    cliff2 = random_clifford(2)
    qc.append(cliff1, [2, 1])
    qc.append(cliff2, [2, 1])
    qc_optimized = PassManager(OptimizeCliffords()).run(qc)

    first stores the two Cliffords cliff1 and cliff2 on qc as “higher-level” objects, and then the transpiler pass OptimizeCliffords optimizes the circuit by composing these two Cliffords into a single Clifford. Note that the resulting Clifford is still stored on qc as a higher-level object. This pass is not yet included in any of preset pass managers.

  • Added a new transpiler pass HighLevelSynthesis that synthesizes higher-level objects (for instance, Clifford objects).

    For example, the following code:

    from qiskit import QuantumCircuit
    from qiskit.quantum_info import random_clifford
    from qiskit.transpiler import PassManager
    from qiskit.transpiler.passes import HighLevelSynthesis
     
    qc = QuantumCircuit(3)
    qc.h(0)
    cliff = random_clifford(2)
    qc.append(cliff, [0, 1])
     
    qc_synthesized = PassManager(HighLevelSynthesis()).run(qc)

    will synthesize the higher-level Clifford stored in qc using the default decompose_clifford() function.

    This new transpiler pass HighLevelSynthesis is integrated into the preset pass managers, running right after UnitarySynthesis pass. Thus, transpile() will synthesize all higher-level Cliffords present in the circuit.

    It is important to note that the work done to store Clifford objects as “higher-level” objects and to transpile these objects using HighLevelSynthesis pass should be completely transparent, and no code changes are required.

  • SparsePauliOps can now be constructed with coefficient arrays that are general Python objects. This is intended for use with ParameterExpression objects; other objects may work, but do not have first-class support. Some SparsePauliOp methods (such as conversion to other class representations) may not work when using object arrays, if the desired target cannot represent these general arrays.

    For example, a ParameterExpression SparsePauliOp could be constructed by:

    import numpy as np
    from qiskit.circuit import Parameter
    from qiskit.quantum_info import SparsePauliOp
     
    print(SparsePauliOp(["II", "XZ"], np.array([Parameter("a"), Parameter("b")])))

    which gives

    SparsePauliOp(['II', 'XZ'],
          coeffs=[ParameterExpression(1.0*a), ParameterExpression(1.0*b)])
  • Added a new function plot_distribution() for plotting distributions over quasi-probabilities. This is suitable for Counts, QuasiDistribution and ProbDistribution. Raw dict can be passed as well. For example:

    from qiskit.visualization import plot_distribution
     
    quasi_dist = {'0': .98, '1': -.01}
    plot_distribution(quasi_dist)
  • Introduced a new high level synthesis plugin interface which is used to enable using alternative synthesis techniques included in external packages seamlessly with the HighLevelSynthesis transpiler pass. These alternative synthesis techniques can be specified for any “higher-level” objects of type Operation, as for example for Clifford and LinearFunction objects. This plugin interface is similar to the one for unitary synthesis. In the latter case, the details on writing a new plugin appear in the qiskit.transpiler.passes.synthesis.plugin module documentation.

  • Introduced a new class HLSConfig which can be used to specify alternative synthesis algorithms for “higher-level” objects of type Operation. For each higher-level object of interest, an object HLSConfig specifies a list of synthesis methods and their arguments. This object can be passed to HighLevelSynthesis transpiler pass or specified as a parameter hls_config in transpile().

    As an example, let us assume that op_a and op_b are names of two higher-level objects, that op_a-objects have two synthesis methods default which does require any additional parameters and other with two optional integer parameters option_1 and option_2, that op_b-objects have a single synthesis method default, and qc is a quantum circuit containing op_a and op_b objects. The following code snippet:

    hls_config = HLSConfig(op_b=[("other", {"option_1": 7, "option_2": 4})])
    pm = PassManager([HighLevelSynthesis(hls_config=hls_config)])
    transpiled_qc = pm.run(qc)

    shows how to run the alternative synthesis method other for op_b-objects, while using the default methods for all other high-level objects, including op_a-objects.

  • Added new methods for executing primitives: BaseSampler.run() and BaseEstimator.run(). These methods execute asynchronously and return JobV1 objects which provide a handle to the exections. These new run methods can be passed QuantumCircuit objects (and observables for BaseEstimator) that are not registered in the constructor. For example:

    estimator = Estimator()
    result = estimator.run(circuits, observables, parameter_values).result()

    This provides an alternative to the previous execution model (which is now deprecated) for the BaseSampler and BaseEstimator primitives which would take all the inputs via the constructor and calling the primitive object with the combination of those input parameters to use in the execution.

  • Added shots option for reference implementations of primitives. Random numbers can be fixed by giving seed_primitive. For example:

    from qiskit.primitives import Sampler
    from qiskit import QuantumCircuit
     
    bell = QuantumCircuit(2)
    bell.h(0)
    bell.cx(0, 1)
    bell.measure_all()
     
    with Sampler(circuits=[bell]) as sampler:
        result = sampler(circuits=[0], shots=1024, seed_primitive=15)
        print([q.binary_probabilities() for q in result.quasi_dists])
  • The constructors for the BaseSampler and BaseEstimator primitive classes have a new optional keyword argument, options which is used to set the default values for the options exposed via the options attribute.

  • Added the PVQD class to the time evolution framework in qiskit.algorithms. This class implements the projected Variational Quantum Dynamics (p-VQD) algorithm Barison et al.(opens in a new tab).

    In each timestep this algorithm computes the next state with a Trotter formula and projects it onto a variational form. The projection is determined by maximizing the fidelity of the Trotter-evolved state and the ansatz, using a classical optimization routine.

    import numpy as np
     
    from qiskit.algorithms.state_fidelities import ComputeUncompute
    from qiskit.algorithms.evolvers import EvolutionProblem
    from qiskit.algorithms.time_evolvers.pvqd import PVQD
    from qiskit.primitives import Estimator, Sampler
    from qiskit import BasicAer
    from qiskit.circuit.library import EfficientSU2
    from qiskit.quantum_info import Pauli, SparsePauliOp
    from qiskit.algorithms.optimizers import L_BFGS_B
     
    sampler = Sampler()
    fidelity = ComputeUncompute(sampler)
    estimator = Estimator()
    hamiltonian = 0.1 * SparsePauliOp([Pauli("ZZ"), Pauli("IX"), Pauli("XI")])
    observable = Pauli("ZZ")
    ansatz = EfficientSU2(2, reps=1)
    initial_parameters = np.zeros(ansatz.num_parameters)
     
    time = 1
    optimizer = L_BFGS_B()
     
    # setup the algorithm
    pvqd = PVQD(
        fidelity,
        ansatz,
        initial_parameters,
        estimator,
        num_timesteps=100,
        optimizer=optimizer,
    )
     
    # specify the evolution problem
    problem = EvolutionProblem(
        hamiltonian, time, aux_operators=[hamiltonian, observable]
    )
     
    # and evolve!
    result = pvqd.evolve(problem)
  • The QNSPSA.get_fidelity() static method now supports an optional sampler argument which is used to provide an implementation of the BaseSampler interface (such as Sampler, BackendSampler, or any provider implementations such as those present in qiskit-ibm-runtime and qiskit-aer) to compute the fidelity of a QuantumCircuit. For example:

    from qiskit.primitives import Sampler
    from qiskit.algorithms.optimizers import QNSPSA
     
    fidelity = QNSPSA.get_fidelity(my_circuit, Sampler())
  • Added a new keyword argument sampler to the constructors of the phase estimation classes:

    This argument is used to provide an implementation of the BaseSampler interface such as Sampler, BackendSampler, or any provider implementations such as those as those present in qiskit-ibm-runtime and qiskit-aer.

    For example:

    from qiskit.primitives import Sampler
    from qiskit.algorithms.phase_estimators import HamiltonianPhaseEstimation
    from qiskit.synthesis import MatrixExponential
    from qiskit.quantum_info import SparsePauliOp
    from qiskit.opflow import PauliSumOp
     
     
    sampler = Sampler()
    num_evaluation_qubits = 6
    phase_est = HamiltonianPhaseEstimation(
        num_evaluation_qubits=num_evaluation_qubits, sampler=sampler
    )
     
    hamiltonian = PauliSumOp(SparsePauliOp.from_list([("X", 0.5), ("Y", 0.6), ("I", 0.7)]))
    result = phase_est.estimate(
        hamiltonian=hamiltonian,
        state_preparation=None,
        evolution=MatrixExponential(),
        bound=1.05,
    )
  • The SabreSwap transpiler pass has significantly improved runtime performance due to a rewrite of the algorithm in Rust.

  • Symbolic pulse subclasses Gaussian, GaussianSquare, Drag and Constant have been upgraded to instantiate SymbolicPulse rather than the subclass itself. All parametric pulse objects in pulse programs must be symbolic pulse instances, because subclassing is no longer neccesary. Note that SymbolicPulse can uniquely identify a particular envelope with the symbolic expression object defined in SymbolicPulse.envelope.

  • Added a new function, sampled_expectation_value(), that allows for computing expectation values for diagonal operators from distributions such as Counts and QuasiDistribution. Valid operators for use with this function are: str, Pauli, PauliOp, PauliSumOp, and SparsePauliOp.

  • A SamplingVQE class is introduced, which is optimized for diagonal hamiltonians and leverages a sampler primitive. A QAOA class is also added that subclasses SamplingVQE.

    To use the new SamplingVQE with a reference primitive, one can do, for example:

    from qiskit.algorithms.minimum_eigensolvers import SamplingVQE
    from qiskit.algorithms.optimizers import SLSQP
    from qiskit.circuit.library import TwoLocal
    from qiskit.primitives import Sampler
    from qiskit.opflow import PauliSumOp
    from qiskit.quantum_info import SparsePauliOp
     
    operator = PauliSumOp(SparsePauliOp(["ZZ", "IZ", "II"], coeffs=[1, -0.5, 0.12]))
     
    sampler = Sampler()
    ansatz = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz")
    optimizer = SLSQP()
     
    sampling_vqe = SamplingVQE(sampler, ansatz, optimizer)
    result = sampling_vqe.compute_minimum_eigenvalue(operator)
    eigenvalue = result.eigenvalue

    Note that the evaluated auxillary operators are now obtained via the aux_operators_evaluated field on the results. This will consist of a list or dict of tuples containing the expectation values for these operators, as we well as the metadata from primitive run. aux_operator_eigenvalues is no longer a valid field.

  • Added a new atol keyword argument to the SparsePauliOp.equiv() method to adjust to tolerance of the equivalence check,

  • Introduced a new plugin interface for transpiler stages which is used to enable alternative PassManager objects from an external package in a particular stage as part of transpile() or the StagedPassManager output from generate_preset_pass_manager(), level_0_pass_manager(), level_1_pass_manager(), level_2_pass_manager(), and level_3_pass_manager(). Users can select a plugin to use for a transpiler stage with the init_method, layout_method, routing_method, translation_method, optimization_method, and scheduling_method keyword arguments on transpile() and generate_preset_pass_manager(). A full list of plugin names currently installed can be found with the list_stage_plugins() function. For creating plugins refer to the qiskit.transpiler.preset_passmanagers.plugin module documentation which includes a guide for writing stage plugins.

  • The transpile() has two new keyword arguments, init_method and optimization_method which are used to specify alternative plugins to use for the init stage and optimization stages respectively.

  • The PassManagerConfig class has 2 new attributes, init_method and optimization_method along with matching keyword arguments on the constructor methods. These represent the user specified init and optimization plugins to use for compilation.

  • The SteppableOptimizer class is added. It allows one to perfore classical optimizations step-by-step using the step() method. These optimizers implement the “ask and tell” interface which (optionally) allows to manually compute the required function or gradient evaluations and plug them back into the optimizer. For more information about this interface see: ask and tell interface(opens in a new tab). A very simple use case when the user might want to do the optimization step by step is for readout:

    import random
    import numpy as np
    from qiskit.algorithms.optimizers import GradientDescent
     
    def objective(x):
          return (np.linalg.norm(x) - 1) ** 2
     
    def grad(x):
          return 2 * (np.linalg.norm(x) - 1) * x / np.linalg.norm(x)
     
     
    initial_point = np.random.normal(0, 1, size=(100,))
     
    optimizer = GradientDescent(maxiter=20)
    optimizer.start(x0=initial_point, fun=objective, jac=grad)
     
    for _ in range(maxiter):
        state = optimizer.state
        # Here you can manually read out anything from the optimizer state.
        optimizer.step()
     
    result = optimizer.create_result()

    A more complex case would be error handling. Imagine that the function you are evaluating has a random chance of failing. In this case you can catch the error and run the function again until it yields the desired result before continuing the optimization process. In this case one would use the ask and tell interface.

    import random
    import numpy as np
    from qiskit.algorithms.optimizers import GradientDescent
     
    def objective(x):
        if random.choice([True, False]):
            return None
        else:
            return (np.linalg.norm(x) - 1) ** 2
     
    def grad(x):
        if random.choice([True, False]):
            return None
        else:
            return 2 * (np.linalg.norm(x) - 1) * x / np.linalg.norm(x)
     
     
    initial_point = np.random.normal(0, 1, size=(100,))
     
    optimizer = GradientDescent(maxiter=20)
    optimizer.start(x0=initial_point, fun=objective, jac=grad)
     
    while optimizer.continue_condition():
        ask_data = optimizer.ask()
        evaluated_gradient = None
     
        while evaluated_gradient is None:
            evaluated_gradient = grad(ask_data.x_center)
            optimizer.state.njev += 1
     
        optmizer.state.nit += 1
     
        cf  = TellData(eval_jac=evaluated_gradient)
        optimizer.tell(ask_data=ask_data, tell_data=tell_data)
     
    result = optimizer.create_result()

    Transitioned GradientDescent to be a subclass of SteppableOptimizer.

  • The subset_fitter method is added to the TensoredMeasFitter class. The implementation is restricted to mitigation patterns in which each qubit is mitigated individually, e.g. [[0], [1], [2]]. This is, however, the most widely used case. It allows the TensoredMeasFitter to be used in cases where the numberical order of the physical qubits does not match the index of the classical bit.

  • Control-flow operations are now supported through the transpiler at optimization levels 0 and 1 (e.g. calling transpile() or generate_preset_pass_manager() with keyword argument optimization_level=1). One can now construct a circuit such as

    from qiskit import QuantumCircuit
     
    qc = QuantumCircuit(2, 1)
    qc.h(0)
    qc.measure(0, 0)
    with qc.if_test((0, True)) as else_:
      qc.x(1)
    with else_:
      qc.y(1)

    and successfully transpile this, such as by:

    from qiskit import transpile
    from qiskit_aer import AerSimulator
     
    backend = AerSimulator(method="statevector")
    transpiled = transpile(qc, backend)

    The available values for the keyword argument layout_method are “trivial” and “dense”. For routing_method, “stochastic” and “none” are available. Translation (translation_method) can be done using “translator” or “unroller”. Optimization levels 2 and 3 are not yet supported with control flow, nor is circuit scheduling (i.e. providing a value to scheduling_method), though we intend to expand support for these, and the other layout, routing and translation methods in subsequent releases of Qiskit Terra.

    In order for transpilation with control-flow operations to succeed with a backend, the backend must have the requisite control-flow operations in its stated basis. Qiskit Aer, for example, does this. If you simply want to try out such transpilations, consider overriding the basis_gates argument to transpile().

  • The following transpiler passes have all been taught to understand control-flow constructs in the form of ControlFlowOp instructions in a circuit:





    These passes are most commonly used via the preset pass managers (those used internally by transpile() and generate_preset_pass_manager()), but are also available for other uses. These passes will now recurse into control-flow operations where appropriate, updating or analysing the internal blocks.

  • Added a new TrotterQRTE class that implements the RealTimeEvolver interface that uses an qiskit.primitives.BaseEstimator to perform the calculation. This new class supersedes the previously available qiskit.algorithms.TrotterQRTE class (which will be deprecated and subsequenty removed in future releases) that used a Backend or QuantumInstance to perform the calculation.

  • DAGCircuit.substitute_node_with_dag() now takes propagate_condition as a keyword argument. This defaults to True, which was the previous behavior, and copies any condition on the node to be replaced onto every operation node in the replacement. If set to False, the condition will not be copied, which allows replacement of a conditional node with a sub-DAG that already faithfully implements the condition.

  • DAGCircuit.substitute_node_with_dag() can now take a mapping for its wires parameter as well as a sequence. The mapping should map bits in the replacement DAG to the bits in the DAG it is being inserted into. This permits an easier style of construction for callers when the input node has both classical bits and a condition, and the replacement DAG may use these out-of-order.

  • Added the qiskit.algorithms.minimum_eigensolvers package to include interfaces for primitive-enabled algorithms. VQE has been refactored in this implementation to leverage primitives.

    To use the new implementation with a reference primitive, one can do, for example:

    from qiskit.algorithms.minimum_eigensolvers import VQE
    from qiskit.algorithms.optimizers import SLSQP
    from qiskit.circuit.library import TwoLocal
    from qiskit.primitives import Estimator
    from qiskit.quantum_info import SparsePauliOp
     
    h2_op = SparsePauliOp(
        ["II", "IZ", "ZI", "ZZ", "XX"],
        coeffs=[
            -1.052373245772859,
            0.39793742484318045,
            -0.39793742484318045,
            -0.01128010425623538,
            0.18093119978423156,
        ],
    )
     
    estimator = Estimator()
    ansatz = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz")
    optimizer = SLSQP()
     
    vqe = VQE(estimator, ansatz, optimizer)
    result = vqe.compute_minimum_eigenvalue(h2_op)
    eigenvalue = result.eigenvalue

    Note that the evaluated auxillary operators are now obtained via the aux_operators_evaluated field on the results. This will consist of a list or dict of tuples containing the expectation values for these operators, as we well as the metadata from primitive run. aux_operator_eigenvalues is no longer a valid field.

Upgrade Notes

  • For Target objects that only contain globally defined 2 qubit operations without any connectivity constaints the return from the Target.build_coupling_map() method will now return None instead of a CouplingMap object that contains num_qubits nodes and no edges. This change was made to better reflect the actual connectivity constraints of the Target because in this case there are no connectivity constraints on the backend being modeled by the Target, not a lack of connecitvity. If you desire the previous behavior for any reason you can reproduce it by checking for a None return and manually building a coupling map, for example:

    from qiskit.transpiler import Target, CouplingMap
    from qiskit.circuit.library import CXGate
     
    target = Target(num_qubits=3)
    target.add_instruction(CXGate())
    cmap = target.build_coupling_map()
    if cmap is None:
        cmap = CouplingMap()
        for i in range(target.num_qubits):
            cmap.add_physical_qubit(i)
  • The default value for the entanglement keyword argument on the constructor for the RealAmplitudes and EfficientSU2 classes has changed from "full" to "reverse_linear". This change was made because the output circuit is equivalent but uses only n1n-1 instead of n(n1)2\frac{n(n-1)}{2} CXGate gates. If you desire the previous default you can explicity set entanglement="full" when calling either constructor.

  • Added a validation check to BaseSampler.run(). It raises an error if there is no classical bit.

  • Behavior of the call() pulse builder function has been upgraded. When a ScheduleBlock instance is called by this method, it internally creates a Reference in the current context, and immediately assigns the called program to the reference. Thus, the Call instruction is no longer generated. Along with this change, it is prohibited to call different blocks with the same name argument. Such operation will result in an error.

  • For most architectures starting in the following release of Qiskit Terra, 0.23, the tweedledum package will become an optional dependency, instead of a requirement. This is currently used by some classical phase-oracle functions. If your application or library needs this functionality, you may want to prepare by adding tweedledum to your package’s dependencies immediately.

    tweedledum is no longer a requirement on macOS arm64 (M1) with immediate effect in Qiskit Terra 0.22. This is because the provided wheels for this platform are broken, and building from the sdist is not reliable for most people. If you manually install a working version of tweedledum, all the dependent functionality will continue to work.

  • The ._layout attribute of the QuantumCircuit object has been changed from storing a Layout object to storing a data class with 2 attributes, initial_layout which contains a Layout object for the initial layout set during compilation and input_qubit_mapping which contains a dictionary mapping qubits to position indices in the original circuit. This change was necessary to provide all the information for a post-transpiled circuit to be able to fully reverse the permutation caused by initial layout in all situations. While this attribute is private and shouldn’t be used externally, it is the only way to track the initial layout through transpile() so the change is being documented in case you’re relying on it. If you have a use case for the _layout attribute that is not being addressed by the Qiskit API please open an issue so we can address this feature gap.

  • The constructors for the SetPhase, ShiftPhase, SetFrequency, and ShiftFrequency classes will now raise a PulseError if the value passed in via the channel argument is not an instance of PulseChannel. This change was made to validate the input to the constructors are valid as the instructions are only valid for pulse channels and not other types of channels.

  • The plot_histogram() function has been modified to return an actual histogram of discrete binned values. The previous behavior for the function was despite the name to actually generate a visualization of the distribution of the input. Due to this disparity between the name of the function and the behavior the function behavior was changed so it’s actually generating a proper histogram of discrete data now. If you wish to preserve the previous behavior of plotting a probability distribution of the counts data you can leverage the plot_distribution() to generate an equivalent graph. For example, the previous behavior of plot_histogram({'00': 512, '11': 500}) can be re-created with:

    from qiskit.visualization import plot_distribution
    import matplotlib.pyplot as plt
     
    ax = plt.subplot()
    plot_distribution({'00': 512, '11': 500}, ax=ax)
    ax.set_ylabel('Probabilities')
  • The qiskit.pulse.builder contexts inline and pad have been removed. These were first deprecated in Terra 0.18.0 (July 2021). There is no replacement for inline; one can simply write the pulses in the containing scope. The pad context manager has had no effect since it was deprecated.

  • The output from the SabreSwap transpiler pass (including when optimization_level=3 or routing_method or layout_method are set to 'sabre' when calling transpile()) with a fixed seed value may change from previous releases. This is caused by a new random number generator being used as part of the rewrite of the SabreSwap pass in Rust which significantly improved the performance. If you rely on having consistent output you can run the pass in an earlier version of Qiskit and leverage qiskit.qpy to save the circuit and then load it using the current version.

  • The Layout.add() behavior when not specifying a physical_bit has changed from previous releases. In previous releases, a new physical bit would be added based on the length of the Layout object. For example if you had a Layout with the physical bits 1 and 3 successive calls to add() would add physical bits 2, 4, 5, 6, etc. While if the physical bits were 2 and 3 then successive calls would add 4, 5, 6, 7, etc. This has changed so that instead Layout.add() will first add any missing physical bits between 0 and the max physical bit contained in the Layout. So for the 1 and 3 example it now adds 0, 2, 4, 5 and for the 2 and 3 example it adds 0, 1, 4, 5 to the Layout. This change was made for both increased predictability of the outcome, and also to fix a class of bugs caused by the unexpected behavior. As physical bits on a backend always are contiguous sequences from 0 to nn adding new bits when there are still unused physical bits could potentially cause the layout to use more bits than available on the backend. If you desire the previous behavior, you can specify the desired physical bit manually when calling Layout.add().

  • The deprecated method SparsePauliOp.table attribute has been removed. It was originally deprecated in Qiskit Terra 0.19. Instead the paulis() method should be used.

  • Support for returning a PauliTable from the pauli_basis() function has been removed. Similarly, the pauli_list argument on the pauli_basis() function which was used to switch to a PauliList (now the only return type) has been removed. This functionality was deprecated in the Qiskit Terra 0.19 release.

  • The fake backend objects FakeJohannesburg, FakeJohannesburgV2, FakeAlmaden, FakeAlmadenV2, FakeSingapore, and FakeSingaporeV2 no longer contain the pulse defaults payloads. This means for the BackendV1 based classes the BackendV1.defaults() method and pulse simulation via BackendV1.run() is no longer available. For BackendV2 based classes the calibration property for instructions in the Target is no longer populated. This change was done because these systems had exceedingly large pulse defaults payloads (in total ~50MB) due to using sampled waveforms instead of parameteric pulse definitions. These three payload files took > 50% of the disk space required to install qiskit-terra. When weighed against the potential value of being able to compile with pulse awareness or pulse simulate these retired devices the file size is not worth the cost. If you require to leverage these properties you can leverage an older version of Qiskit and leverage qpy to transfer circuits from older versions of qiskit into the current release.

  • isinstance check with pulse classes Gaussian, GaussianSquare, Drag and Constant will be invalidated because these pulse subclasses are no longer instantiated. They will still work in Terra 0.22, but you should begin transitioning immediately. Instead of using type information, SymbolicPulse.pulse_type should be used. This is assumed to be a unique string identifer for pulse envelopes, and we can use string equality to investigate the pulse types. For example,

    from qiskit.pulse.library import Gaussian
     
    pulse = Gaussian(160, 0.1, 40)
     
    if isinstance(pulse, Gaussian):
      print("This is Gaussian pulse.")

    This code should be upgraded to

    from qiskit.pulse.library import Gaussian
     
    pulse = Gaussian(160, 0.1, 40)
     
    if pulse.pulse_type == "Gaussian":
      print("This is Gaussian pulse.")

    With the same reason, the class attributes such as pulse.__class__.__name__ should not be accessed to get pulse type information.

  • The exception qiskit.exceptions.QiskitIndexError has been removed and no longer exists as per the deprecation notice from qiskit-terra 0.18.0 (released on Jul 12, 2021).

  • The deprecated arguments epsilon and factr for the constructor of the L_BFGS_B optimizer class have been removed. These arguments were originally deprecated as part of the 0.18.0 release (released on July 12, 2021). Instead the ftol argument should be used, you can refer to the scipy docs(opens in a new tab) on the optimizer for more detail on the relationship between these arguments.

  • The preset pass managers for levels 1 and 2, which will be used when optimization_level=1 or optimization_level=2 with transpile() or generate_preset_pass_manager() and output from level_1_pass_manager() and level_2_pass_manager(), will now use SabreLayout and SabreSwap by default instead of the previous defaults DenseLayout and StochasticSwap. This change was made to improve the output quality of the transpiler, the SabreLayout and SabreSwap combination typically results in fewer SwapGate objects being inserted into the output circuit. If you would like to use the previous default passes you can set layout_method='dense' and routing_method='stochastic' on transpile() or generate_preset_pass_manager() to leverage DenseLayout and StochasticSwap respectively.

  • The implicit use of approximation_degree!=1.0 by default in in the transpile() function when optimization_level=3 is set has been disabled. The transpiler should, by default, preserve unitarity of the input up to known transformations such as one-sided permutations and similarity transformations. This was broken by the previous use of approximation_degree=None leading to incorrect results in cases such as Trotterized evolution with many time steps where unitaries were being overly approximated leading to incorrect results. It was decided that transformations that break unitary equivalence should be explicitly activated by the user. If you desire the previous default behavior where synthesized UnitaryGate instructions are approximated up to the error rates of the target backend’s native instructions you can explicitly set approximation_degree=None when calling transpile() with optimization_level=3, for example:

    transpile(circuit, backend, approximation_degree=None, optimization_level=3)
  • Change the default of maximum number of allowed function evaluations (maxfun) in L_BFGS_B from 1000 to 15000 to match the SciPy default. This number also matches the default number of iterations (maxiter).

  • Updated ProbDistribution and QuasiDistribution to store the information of the number of bits if bitstrings without prefix “0b” are given. ProbDistribution.binary_probabilities() and QuasiDistribution.binary_probabilities() use the stored number of bits as the default value of the number of bits.

  • RZXCalibrationBuilder and RZXCalibrationBuilderNoEcho have been upgraded to skip stretching CX gates implemented by non-echoed cross resonance (ECR) sequence to avoid termination of the pass with unexpected errors. These passes take new argument verbose that controls whether the passes warn when this occurs. If verbose=True is set, pass raises user warning when it enconters non-ECR sequence.

  • The visualization module qiskit.visualization has seen some internal reorganisation. This should not have affected the public interface, but if you were accessing any internals of the circuit drawers, they may now be in different places. The only parts of the visualization module that are considered public are the components that are documented in this online documentation.

Deprecation Notes

  • Importing the names Int1, Int2, classical_function and BooleanExpression directly from qiskit.circuit is deprecated. This is part of the move to make tweedledum an optional dependency rather than a full requirement. Instead, you should import these names from qiskit.circuit.classicalfunction.

  • Modules qiskit.algorithms.factorizers and qiskit.algorithms.linear_solvers are deprecated and will be removed in a future release. They are replaced by tutorials in the Qiskit Textbook: Shor(opens in a new tab) HHL(opens in a new tab)

  • The random_stabilizer_table() has been deprecated and will be removed in a future release. Instead the random_pauli_list() function should be used.

  • The pulse-module function qiskit.pulse.utils.deprecated_functionality is deprecated and will be removed in a future release. This was a primarily internal-only function. The same functionality is supplied by qiskit.utils.deprecate_function, which should be used instead.

  • The method of executing primitives has been changed. The BaseSampler.__call__() and BaseEstimator.__call__() methods were deprecated. For example:

    estimator = Estimator(...)
    result = estimator(circuits, observables, parameters)
     
    sampler = Sampler(...)
    result = sampler(circuits, observables, parameters)

    should be rewritten as

    estimator = Estimator()
    result = estimator.run(circuits, observables, parameter_values).result()
     
    sampler = Sampler()
    result = sampler.run(circuits, parameter_values).result()

    Using primitives as context managers is deprecated. Not all primitives have a context manager available. When available (e.g. in qiskit-ibm-runtime), the session’s context manager provides equivalent functionality.

    circuits, observables, and parameters in the constructor was deprecated. circuits and observables can be passed from run methods. run methods do not support parameters. Users need to resort parameter values by themselves.

  • The unused argument qubit_channel_mapping in the RZXCalibrationBuilder and RZXCalibrationBuilderNoEcho transpiler passes have been deprecated and will be removed in a future release. This argument is no longer used and has no effect on the operation of the passes.

Bug Fixes

  • Fixed an issue where Pauli.evolve() and PauliList.evolve() would raise a dtype error when evolving by certain Clifford gates which modified the Pauli’s phase. Fixed #8438(opens in a new tab)

  • Fixed a bug in QuantumCircuit.initialize() and QuantumCircuit.prepare_state() that caused them to not accept a single Qubit as argument to initialize.

  • The method QuantumCircuit.while_loop() will now resolve classical bit references in its condition in the same way that QuantumCircuit.if_test() and InstructionSet.c_if() do.

  • The DAGCircuit methods depth(), size() and DAGCircuit.count_ops() would previously silently return results that had little-to-no meaning if control-flow was present in the circuit. The depth() and size() methods will now correctly throw an error in these cases, but have a new recurse keyword argument to allow the calculation of a proxy value, while count_ops() will by default recurse into the blocks and count the operations within them.

  • Fixed an issue in the DenseLayout transpiler pass where any loose Qubit objects (i.e. not part of a QuantumRegister) that were part of a QuantumCircuit would not be included in the output Layout that was generated by the pass.

  • The Operator.from_circuit() constructor method has been updated so that it can handle the layout output from transpile() and correctly reverse the qubit permutation caused by layout in all cases. Previously, if your transpiled circuit used loose Qubit objects, multiple QuantumRegister objects, or a single QuantumRegister with a name other than "q" the constructor would have failed to create an Operator from the circuit. Fixed #8800(opens in a new tab).

  • Fixed a bug where decomposing an instruction with one qubit and one classical bit containing a single quantum gate failed. Now the following decomposes as expected:

    block = QuantumCircuit(1, 1)
    block.h(0)
     
    circuit = QuantumCircuit(1, 1)
    circuit.append(block, [0], [0])
     
    decomposed = circuit.decompose()
  • Fixed initialization of empty symplectic matrix in from_symplectic() in PauliList class For example:

    from qiskit.quantum_info.operators import PauliList
     
    x = np.array([], dtype=bool).reshape((1,0))
    z = np.array([], dtype=bool).reshape((1,0))
    pauli_list = PauliList.from_symplectic(x, z)
  • Fix a problem in the GateDirection transpiler pass for the CZGate. The CZ gate is symmetric, so flipping the qubit arguments is allowed to match the directed coupling map.

  • Fixed issues with the DerivativeBase.gradient_wrapper() method when reusing a circuit sampler between the calls and binding nested parameters.

  • Fixed an issue in the mpl and latex circuit drawers, when setting the idle_wires option to False when there was a barrier in the circuit would cause the drawers to fail, has been fixed. Fixed #8313(opens in a new tab)

  • Fixed an issue in circuit_drawer() and QuantumCircuit.draw() with the latex method where an OSError would be raised on systems whose temporary directories (e.g /tmp) are on a different filesystem than the working directory. Fixes #8542(opens in a new tab)

  • Nesting a FlowController inside another in a PassManager could previously cause some transpiler passes to become “forgotten” during transpilation, if the passes returned a new DAGCircuit rather than mutating their input. Nested FlowControllers will now affect the transpilation correctly.

  • Comparing QuantumCircuit and DAGCircuits for equality was previously non-deterministic if the circuits contained more than one register of the same type (e.g. two or more QuantumRegisters), sometimes returning False even if the registers were identical. It will now correctly compare circuits with multiple registers.

  • 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).

  • There were two bugs in the text circuit drawer that were fixed. These appeared when vertical_compression was set to medium, which is the default. The first would sometimes cause text to overwrite other text or gates, and the second would sometimes cause the connections between a gate and its controls to break. See #8588(opens in a new tab).

  • Fixed an issue with the UnitarySynthesis pass where a circuit with 1 qubit gates and a Target input would sometimes fail instead of processing the circuit as expected.

  • The GateDirection transpiler pass will now respect the available values for gate parameters when handling parametrised gates with a Target.

  • Fixed an issue in the SNOBFIT optimizer class when an internal error would be raised during the execution of the minimize() method if no input bounds where specified. This is now checked at call time to quickly raise a ValueError if required bounds are missing from the minimize() call. Fixes #8580(opens in a new tab)

  • Fixed an issue in the output callable from the get_energy_evaluation() method of the VQD class will now correctly call the specified callback when run. Previously the callback would incorrectly not be used in this case. Fixed #8575(opens in a new tab)

  • Fixed an issue when circuit_drawer() was used with reverse_bits=True on a circuit without classical bits that would cause a potentially confusing warning about cregbundle to be emitted. Fixed #8690(opens in a new tab)

  • The OpenQASM 3 exporter (qiskit.qasm3) will now correctly handle OpenQASM built-ins (such as reset and measure) that have a classical condition applied by c_if(). Previously the condition would have been ignored.

  • Fixed an issue with the SPSA class where internally it was trying to batch jobs into even sized batches which would raise an exception if creating even batches was not possible. This has been fixed so it will always batch jobs successfully even if they’re not evenly sized.

  • Fixed the behavior of Layout.add() which was potentially causing the output of transpile() to be invalid and contain more Qubits than what was available on the target backend. Fixed: #8667(opens in a new tab)

  • Fixed an issue with the state_to_latex() function: passing a latex string to the optional prefix argument of the function would raise an error. Fixed #8460(opens in a new tab)

  • The function state_to_latex() produced not valid LaTeX in presence of close-to-zero values, resulting in errors when state_drawer() is called. Fixed #8169(opens in a new tab).

  • GradientDescent will now correctly count the number of iterations, function evaluations and gradient evaluations. Also the documentation now correctly states that the gradient is approximated by a forward finite difference method.

  • Fix deprecation warnings in NaturalGradient, which now uses the StandardScaler to scale the data before fitting the model if the normalize parameter is set to True.

Aer 0.11.0

No change

IBM Q Provider 0.19.2

No change

Was this page helpful?