# Release Notes¶

## Version History¶

This table tracks the meta-package versions and the version of each Qiskit element installed:

Table 16 Version History

Qiskit Metapackage Version

qiskit-terra

qiskit-aer

qiskit-ignis

qiskit-ibmq-provider

qiskit-aqua

Release Date

0.42.0

0.23.2

0.12.0

0.20.2

2023-03-10

0.41.1

0.23.2

0.11.2

0.20.1

2023-02-23

0.41.0

0.23.1

0.11.2

0.20.0

2023-01-31

0.40.0

0.23.0

0.11.2

0.19.2

2023-01-26

0.39.5

0.22.4

0.11.2

0.19.2

2023-01-17

0.39.4

0.22.3

0.11.2

0.19.2

2022-12-08

0.39.3

0.22.3

0.11.1

0.19.2

2022-11-25

0.39.2

0.22.2

0.11.1

0.19.2

2022-11-03

0.39.1

0.22.1

0.11.1

0.19.2

2022-11-02

0.39.0

0.22.0

0.11.0

0.19.2

2022-10-13

0.38.0

0.21.2

0.11.0

0.19.2

2022-09-14

0.37.2

0.21.2

0.10.4

0.19.2

2022-08-23

0.37.1

0.21.1

0.10.4

0.19.2

2022-07-28

0.37.0

0.21.0

0.10.4

0.19.2

2022-06-30

0.36.2

0.20.2

0.10.4

0.7.1

0.19.1

2022-05-18

0.36.1

0.20.1

0.10.4

0.7.0

0.19.1

2022-04-21

0.36.0

0.20.0

0.10.4

0.7.0

0.19.0

2022-04-06

0.35.0

0.20.0

0.10.3

0.7.0

0.18.3

2022-03-31

0.34.2

0.19.2

0.10.3

0.7.0

0.18.3

2022-02-09

0.34.1

0.19.1

0.10.2

0.7.0

0.18.3

2022-01-05

0.34.0

0.19.1

0.10.1

0.7.0

0.18.3

2021-12-20

0.33.1

0.19.1

0.9.1

0.7.0

0.18.2

2021-12-10

0.33.0

0.19.0

0.9.1

0.7.0

0.18.1

2021-12-06

0.32.1

0.18.3

0.9.1

0.6.0

0.18.1

0.9.5

2021-11-22

0.32.0

0.18.3

0.9.1

0.6.0

0.18.0

0.9.5

2021-11-10

0.31.0

0.18.3

0.9.1

0.6.0

0.17.0

0.9.5

2021-10-12

0.30.1

0.18.3

0.9.0

0.6.0

0.16.0

0.9.5

2021-09-29

0.30.0

0.18.2

0.9.0

0.6.0

0.16.0

0.9.5

2021-09-16

0.29.1

0.18.2

0.8.2

0.6.0

0.16.0

0.9.5

2021-09-10

0.29.0

0.18.1

0.8.2

0.6.0

0.16.0

0.9.4

2021-08-02

0.28.0

0.18.0

0.8.2

0.6.0

0.15.0

0.9.4

2021-07-13

0.27.0

0.17.4

0.8.2

0.6.0

0.14.0

0.9.2

2021-06-15

0.26.2

0.17.4

0.8.2

0.6.0

0.13.1

0.9.1

2021-05-19

0.26.1

0.17.4

0.8.2

0.6.0

0.13.1

0.9.1

2021-05-18

0.26.0

0.17.3

0.8.2

0.6.0

0.13.1

0.9.1

2021-05-11

0.25.4

0.17.2

0.8.2

0.6.0

0.12.3

0.9.1

2021-05-05

0.25.3

0.17.1

0.8.2

0.6.0

0.12.3

0.9.1

2021-04-29

0.25.2

0.17.1

0.8.1

0.6.0

0.12.3

0.9.1

2021-04-21

0.25.1

0.17.1

0.8.1

0.6.0

0.12.2

0.9.1

2021-04-15

0.25.0

0.17.0

0.8.0

0.6.0

0.12.2

0.9.0

2021-04-02

0.24.1

0.16.4

0.7.6

0.5.2

0.12.2

0.8.2

2021-03-24

0.24.0

0.16.4

0.7.6

0.5.2

0.12.1

0.8.2

2021-03-04

0.23.6

0.16.4

0.7.5

0.5.2

0.11.1

0.8.2

2021-02-18

0.23.5

0.16.4

0.7.4

0.5.2

0.11.1

0.8.2

2021-02-08

0.23.4

0.16.3

0.7.3

0.5.1

0.11.1

0.8.1

2021-01-28

0.23.3

0.16.2

0.7.3

0.5.1

0.11.1

0.8.1

2021-01-26

0.23.2

0.16.1

0.7.2

0.5.1

0.11.1

0.8.1

2020-12-15

0.23.1

0.16.1

0.7.1

0.5.1

0.11.1

0.8.1

2020-11-12

0.23.0

0.16.0

0.7.0

0.5.0

0.11.0

0.8.0

2020-10-16

0.22.0

0.15.2

0.6.1

0.4.0

0.10.0

0.7.5

2020-10-05

0.21.0

0.15.2

0.6.1

0.4.0

0.9.0

0.7.5

2020-09-16

0.20.1

0.15.2

0.6.1

0.4.0

0.8.0

0.7.5

2020-09-08

0.20.0

0.15.1

0.6.1

0.4.0

0.8.0

0.7.5

2020-08-10

0.19.6

0.14.2

0.5.2

0.3.3

0.7.2

0.7.3

2020-06-25

0.19.5

0.14.2

0.5.2

0.3.2

0.7.2

0.7.3

2020-06-19

0.19.4

0.14.2

0.5.2

0.3.0

0.7.2

0.7.2

2020-06-16

0.19.3

0.14.1

0.5.2

0.3.0

0.7.2

0.7.1

2020-06-02

0.19.2

0.14.1

0.5.1

0.3.0

0.7.1

0.7.1

2020-05-14

0.19.1

0.14.1

0.5.1

0.3.0

0.7.0

0.7.0

2020-05-01

0.19.0

0.14.0

0.5.1

0.3.0

0.7.0

0.7.0

2020-04-30

0.18.3

0.13.0

0.5.1

0.3.0

0.6.1

0.6.6

2020-04-24

0.18.2

0.13.0

0.5.0

0.3.0

0.6.1

0.6.6

2020-04-23

0.18.1

0.13.0

0.5.0

0.3.0

0.6.0

0.6.6

2020-04-20

0.18.0

0.13.0

0.5.0

0.3.0

0.6.0

0.6.5

2020-04-09

0.17.0

0.12.0

0.4.1

0.2.0

0.6.0

0.6.5

2020-04-01

0.16.2

0.12.0

0.4.1

0.2.0

0.5.0

0.6.5

2020-03-20

0.16.1

0.12.0

0.4.1

0.2.0

0.5.0

0.6.4

2020-03-05

0.16.0

0.12.0

0.4.0

0.2.0

0.5.0

0.6.4

2020-02-27

0.15.0

0.12.0

0.4.0

0.2.0

0.4.6

0.6.4

2020-02-06

0.14.1

0.11.1

0.3.4

0.2.0

0.4.5

0.6.2

2020-01-07

0.14.0

0.11.0

0.3.4

0.2.0

0.4.4

0.6.1

2019-12-10

0.13.0

0.10.0

0.3.2

0.2.0

0.3.3

0.6.1

2019-10-17

0.12.2

0.9.1

0.3.0

0.2.0

0.3.3

0.6.0

2019-10-11

0.12.1

0.9.0

0.3.0

0.2.0

0.3.3

0.6.0

2019-09-30

0.12.0

0.9.0

0.3.0

0.2.0

0.3.2

0.6.0

2019-08-22

0.11.2

0.8.2

0.2.3

0.1.1

0.3.2

0.5.5

2019-08-20

0.11.1

0.8.2

0.2.3

0.1.1

0.3.1

0.5.3

2019-07-24

0.11.0

0.8.2

0.2.3

0.1.1

0.3.0

0.5.2

2019-07-15

0.10.5

0.8.2

0.2.1

0.1.1

0.2.2

0.5.2

2019-06-27

0.10.4

0.8.2

0.2.1

0.1.1

0.2.2

0.5.1

2019-06-17

0.10.3

0.8.1

0.2.1

0.1.1

0.2.2

0.5.1

2019-05-29

0.10.2

0.8.0

0.2.1

0.1.1

0.2.2

0.5.1

2019-05-24

0.10.1

0.8.0

0.2.0

0.1.1

0.2.2

0.5.0

2019-05-07

0.10.0

0.8.0

0.2.0

0.1.1

0.2.1

0.5.0

2019-05-06

0.9.0

0.8.0

0.2.0

0.1.1

0.1.1

0.5.0

2019-05-02

0.8.1

0.7.2

0.1.1

0.1.0

2019-05-01

0.8.0

0.7.1

0.1.1

0.1.0

2019-03-05

0.7.3

>=0.7,<0.8

>=0.1,<0.2

2019-02-19

0.7.2

>=0.7,<0.8

>=0.1,<0.2

2019-01-22

0.7.1

>=0.7,<0.8

>=0.1,<0.2

2019-01-17

0.7.0

>=0.7,<0.8

>=0.1,<0.2

2018-12-14

নোট

For the 0.7.0, 0.7.1, and 0.7.2 meta-package releases the Qiskit Versioning policy was not formalized yet.

## Notable Changes¶

### Qiskit 0.42.0¶

No change

#### Aer 0.12.0¶

##### Prelude¶

The Qiskit Aer 0.12.0 release highlights are:

##### New Features¶
• Added a new keyword argument, abelian_grouping, to the Estimator. This argument is used to control whether the Estimator will group the input observables into qubit-wise commutable observables which reduces the number of circuit executions required to compute the expectation value and improves the runtime performance of the Estimator. By default this is set to True.

• AerState has a new method initialize_density_matrix() that sets a density matrix to AER::QV::DensityMatrix. This method will be called in q.i.states.DensityMatrix to initialize its data with ndarray. initialize_density_matrix() has a boolean argument that specifies copy or share of ndarray data. If the data is shared with C++ and python, the data must not be collected in python while C++ accesses it.

• The overhead for running simulations with run() (for all simulator backend classess) has been greatly reduced. This was accomplished by no longer internally serializing QuantumCircuit objects into QasmQobj and instead the QuantumCircuit object directly to an internal C++ circuit structure used for simulation. This improvement is most noticeable for simulations of circuts with a small number of qubits or parameterized circuits using the parameter_binds keyword argument of run(). Note that pulse simualation (via the now deprecated PulseSimulator) and DASK-based simulation still use the internal serialization and will not see this performance improvement.

• Added a new simulation method based on NVIDIA's cuTensorNet APIs of cuQuantum SDK. This provides a GPU accelerated general tensor network simulator that can simulate any quantum circuit, by internally translating the circuit into a tensor network to perform the simulation. To use this simulation method, set method="tensor_network" and device="GPU" when initializing an AerSimulator object. For example:

from qiskit_aer import AerSimulator

tensor_net_sim = AerSimulator(method="tensor_network", device="GPU")


This method supports both statevector and density matrix simulations. Noise simulation can also be done with a density matrix single shot simulation if there are not any SaveStatevector operations in the circuit.

This new simulation method also supports parallelization with multiple GPUs and MPI processes by using tensor network slicing technique. However, this type of simulation will likely take a very long time if the input circuits are complicated.

• The BLA_VENDOR environment variable can now be specified to use a different BLAS library when building Qiskit Aer from source. By default if this is not specified OpenBLAS will be used by default. If the BLAS library specified in BLA_VENDOR can not be found then the Cmake build process will stop.

##### Known Issues¶
• This release of Qiskit Aer is not compatible with the Conan 2.X release series. If you are building Qiskit Aer from source manually ensure that you are using a Conan 1.x release. Compatibility with newer versions of Conan will be fixed in a future release. You can refer to issue #1730 for more details.

• The default behavior of the Estimator primitive will now group the input observable into qubit-wise commutable observables. The grouping reduces the number of circuits to be executed and improves the performance. If you desire the previous behavior you can initialize your Estimator instance with the keyword argument abelian_grouping=False.

• Removed the usage of primitives with the context manager and the initialization with circuits, (observables only for Estimator), and parameters which has been deprecated in the Qiskit Terra 0.22.0 release in October 2022.

• The behavior of run() method has changed when invalid or otherwise unsimulatable QuantumCircuit objects are passed as an input. Previously, in these cases the run() method would return an AerJob whose result() method would return a Result with the ERROR or PARTIAL COMPLETED (depending on whether all the circuit inputs or only some were invalid or not). Starting in this release instead of returning a result object with these statuses an exception will be raised instead. This change was necessary because of the performance improvements by no longer internally serializing the QuantumCircuit objects to a Qobj before passing it to C++, instead the direct conversion from QuantumCircuit now errors directly when trying to simulate a circuit Qiskit Aer is unable to execute. If you desire the previous behavior you can build Qiskit Aer in standalone mode and manually serialize your QuantumCircuit objects to a JSON representation of the QasmQobj which you then pass to the standalone Aer binary which will retain the previous behavior.

• A deprecated method add_nonlocal_quantum_error() in NoiseModel has been removed. No alternative method is available. If you want to add non-local quantum errors, you should write a transpiler pass that inserts your own quantum error into a circuit, and run the pass just before running the circuit on Aer simulator.

• A deprecated standard_gates argument broadly used in several methods and functions (listed below) across noise module has been removed.

• NoiseModel.from_backend() and noise.device.basic_device_gate_errors()

• kraus_error(), mixed_unitary_error(), pauli_error() and depolarizing_error() in noise.errors.standard_errors

• QuantumError.__init__()

No alternative means are available because the user should be agnostic about how the simulator represents noises (quantum errors) internally.

• The constructor of QuantumError has now dropped the support of deprecated json-like input for noise_ops argument. Use the new styple input for noise_ops argument instead, for example,

from qiskit.circuit.library import IGate, XGate
from qiskit_aer.noise import QuantumError

error = QuantumError([
((IGate(), [1]), 0.9),
((XGate(), [1]), 0.1),
])

# json-like input is no longer accepted (the following code fails)
#  error = QuantumError([
#      ([{"name": "I", "qubits": [1]}], 0.9),
#      ([{"name": "X", "qubits": [1]}], 0.1),
#  ])


Also it has dropped deprecated arguments:

• number_of_qubits: Use QuantumCircuit to define noise_ops instead.

• atol: Use QuantumError.atol attribute instead.

• standard_gates: No alternative is available (users should not too much care about internal representation of quantum errors).

• The deprecated noise.errors.errorutils module has been entirely removed and no alternatives are available. All functions in the module were helper functions meant to be used only for implementing functions in standard_errors (i.e. they should have been provided as private functions) and no longer used in it.

• The deprecated utils.noise_remapper have been entirely removed and no alternatives are available since the C++ code now automatically truncates and remaps noise models if it truncates circuits.

• All deprecated functions (pauli_operators() and reset_operators()) and class (NoiseTransformer) in utils.noise_transformation module have been removed, and no alternatives are available. They were in fact private functions/class used only for implementing approximate_quantum_error() and should not have been public.

• Aer's setup.py has been updated to no longer attempt to make calls to pip to install build requirements, both manually and via the setup_requires option in setuptools.setup. The preferred way to build Aer is to use a PEP 517-compatible builder such as:

pip install .


This change means that a direct call to setup.py will no longer work if the build requirements are not installed. This is inline with modern Python packaging guidelines.

##### Deprecation Notes¶
• Support for running Qiskit Aer with Python 3.7 support has been deprecated and will be removed in a future release. This means starting in a future release you will need to upgrade the Python version you're using to Python 3.8 or above.

• The qobj() method of the AerJob class is now deprecated and will be removed in a future release. The use of the qobj format as input to run() has been deprecated since qiskit-aer 0.9.0 and in most cases this method would return None now anyway. If you'd like to get the input to the run() method now you can use the circuits() method instead, which will return the QuantumCircuit objects that were simulated in the job.

• A warnings argument broadly used in several methods and functions across noise module has been deprecated in favor of the use of filtering functions in Python's standard warnings library.

##### Bug Fixes¶
• Fixed an issue when creating a new AerStatevector instance from a numpy.ndarray that had non-contiguous memory. Previously, this would result in unexpected behavior (and a potential error) as the AerStatevector assumed the input array was contiguous. This has been fixed so that memory layout is checked and the numpy.ndarray will be copied internally as a contiguous array before using it.

• The bits count of classical register used on the GPU was not set before calculating free available memory for chunks that causes infinite loop. So this fix set bits count before allocating chunks if batch shots execution is enabled.

• Fix build errors and test errors when enabling GPU but disabling cuQuantum.

• Fixed an issue in the matrix product state simulation method (i.e. setting the keyword argument method="matrix_product_state" when initializing an AerSimulator object) where the simulator would incorrectly sort the qubits prior to performing measurment potentially resulting in an infinite loop. This has been fixed so the measurement of the qubits occurs in the order of the current MPS structure and then sorting afterwards as a post-processing step. This also will likely improve the performance of the simulation method and enable more accurate representation of entangled states. Fixed #1694

• The AerSimulator backend with methods:

• statevector

• density_matrix

• matrix_product_state

• stabilizer

now report that they support break_loop and continue_loop instructions when used as backends for the Terra transpile() function. The simulators already did support these, but had just not been reporting it.

#### IBM Q Provider 0.20.2¶

This release removes the overly restrictive version constraints set in the requirements for the package added in 0.20.1. For the 0.20.1 the only dependency that was intended to have a version cap was the requests-ntlm package as its new release was the only dependency which currently has an incompatibility with qiskit-ibmq-provider. The other version caps which were added as part of 0.20.1 were causing installation issues in several environments because it made the qiskit-ibmq-provider package incompatible with the dependency versions used in other packages.

### Qiskit 0.41.1¶

#### Terra 0.23.2¶

##### Prelude¶

The Qiskit Terra 0.23.2 patch release fixes further bugs identified in the 0.23 series.

##### Bug Fixes¶
• Add a decomposition of an ECRGate into Clifford gates (up to a global phase) to the standard equivalence library.

• Fixed an incorrect return value of the method BackendV2Converter.meas_map() that had returned the backend dt instead.

• Fixed a bug in the VQD algorithm where the energy evaluation function could not process batches of parameters, making it incompatible with optimizers with max_evals_grouped>1. Fixed #9500.

• Fixed bug in QNSPSA which raised a type error when the computed fidelities happened to be of type int but the perturbation was of type float.

No change

#### IBM Q Provider 0.20.1¶

Since qiskit-ibmq-provider is now deprecated, the dependencies have been bumped and fixed to the latest working versions. There was an issue with the latest version of the requests-ntlm package which caused some end to end tests to fail.

### Qiskit 0.41.0¶

#### Terra 0.23.1¶

##### Prelude¶

Qiskit Terra 0.23.1 is a small patch release to fix bugs identified in Qiskit Terra 0.23.0

##### Bug Fixes¶
• Fixed a performance bug in ReverseEstimatorGradient where the calculation did a large amount of unnecessary copies if the gradient was only calculated for a subset of parameters, or in a circuit with many unparameterized gates.

• Fixed a bad deprecation of Register.name_format which had made the class attribute available only from instances and not the class. When trying to send dynamic-circuits jobs to hardware backends, this would frequently cause the error:

AttributeError: 'property' object has no attribute 'match'


Fixed #9493.

No change

#### IBM Q Provider 0.20.0¶

##### Prelude¶

This release of the qiskit-ibmq-provider package marks the package as deprecated and will be retired and archived in the future. The functionality in qiskit-ibmq-provider has been supersceded by 3 packages qiskit-ibm-provider, qiskit-ibm-runtime, and qiskit-ibm-experiment which offer different subsets of functionality that qiskit-ibmq-provider contained. You can refer to the table here:

https://github.com/Qiskit/qiskit-ibmq-provider#migration-guides

for links to the migration guides for moving from qiskit-ibmq-provider to its replacmeent packages.

##### Deprecation Notes¶
• As of version 0.20.0, qiskit-ibmq-provider has been deprecated with its support ending and eventual archival being no sooner than 3 months from that date. The function provided by qiskit-ibmq-provider is not going away rather it has being split out to separate repositories. Please see https://github.com/Qiskit/qiskit-ibmq-provider#migration-guides.

##### 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 for the details). PR #1135 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.

• PR #1129 updates least_busy() method to no longer support BaseBackend as a valid input or output type since it has been long deprecated in qiskit-terra and has recently been removed.

• threading.currentThread and notifyAll were deprecated in Python 3.10 (October 2021) and will be removed in Python 3.12 (October 2023). PR #1133 replaces them with threading.current_thread, notify_all added in Python 2.6 (October 2008).

• Calls to run a quantum circuit with dynamic=True now raise an error that asks the user to install the new qiskit-ibm-provider.

### Qiskit 0.40.0¶

This release officially deprecates the Qiskit IBMQ provider project as part of the Qiskit metapackage. This means that in a future release, pip install qiskit will no longer automatically include qiskit-ibmq-provider. If you're currently installing or listing qiskit as a dependency to get qiskit-ibmq-provider, you should update to explicitly include qiskit-ibmq-provider as well. This is being done as the Qiskit project moves towards a model where the qiskit package only contains the common core functionality for building and compiling quantum circuits, programs, and applications. Packages that build on that core or link Qiskit to hardware or simulators will be installable as separate packages.

#### Terra 0.23.0¶

##### Prelude¶

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

This release also deprecates support for running with Python 3.7. A DeprecationWarning will now be emitted if you run Qiskit with Python 3.7. Support for Python 3.7 will be removed as part of the 0.25.0 release (currently planned for release in July 2023), at which point you will need Python 3.8 or newer to use Qiskit.

##### New Features¶
• The pulses in qiskit.pulse.library

can be initialized with new parameter angle, such that two float parameters could be provided: amp and angle. Initialization with complex amp is still supported.

• The AdaptVQE class has a new attribute, eigenvalue_history, which is used to track the lowest achieved energy per iteration of the AdaptVQE. For example:

from qiskit.algorithms.minimum_eigensolvers import VQE
from qiskit.algorithms.optimizers import SLSQP
from qiskit.circuit.library import EvolvedOperatorAnsatz
from qiskit.opflow import PauliSumOp
from qiskit.primitives import Estimator
from qiskit.quantum_info import SparsePauliOp
from qiskit.utils import algorithm_globals

excitation_pool = [
PauliSumOp(
SparsePauliOp(["IIIY", "IIZY"], coeffs=[0.5 + 0.0j, -0.5 + 0.0j]), coeff=1.0
),
PauliSumOp(
SparsePauliOp(["ZYII", "IYZI"], coeffs=[-0.5 + 0.0j, 0.5 + 0.0j]), coeff=1.0
),
PauliSumOp(
SparsePauliOp(
["ZXZY", "IXIY", "IYIX", "ZYZX", "IYZX", "ZYIX", "ZXIY", "IXZY"],
coeffs=[
-0.125 + 0.0j,
0.125 + 0.0j,
-0.125 + 0.0j,
0.125 + 0.0j,
0.125 + 0.0j,
-0.125 + 0.0j,
0.125 + 0.0j,
-0.125 + 0.0j,
],
),
coeff=1.0,
),
]
ansatz = EvolvedOperatorAnsatz(excitation_pool, initial_state=self.initial_state)
optimizer = SLSQP()
h2_op = PauliSumOp.from_list(
[
("IIII", -0.8105479805373266),
("ZZII", -0.2257534922240251),
("IIZI", +0.12091263261776641),
("ZIZI", +0.12091263261776641),
("IZZI", +0.17218393261915543),
("IIIZ", +0.17218393261915546),
("IZIZ", +0.1661454325638243),
("ZZIZ", +0.1661454325638243),
("IIZZ", -0.2257534922240251),
("IZZZ", +0.16892753870087926),
("ZZZZ", +0.17464343068300464),
("IXIX", +0.04523279994605788),
("ZXIX", +0.04523279994605788),
("IXZX", -0.04523279994605788),
("ZXZX", -0.04523279994605788),
]
)

algorithm_globals.random_seed = 42
res = calc.compute_minimum_eigenvalue(operator=h2_op)

print(calc.eigenvalue_history)


the returned value of calc.history should be roughly [-1.85727503] as there is a single iteration.

• The runtime logging when running the AdaptVQE has been improved. When running the class now, DEBUG and INFO level log messages will be emitted as the class runs.

• The CollectLinearFunctions transpiler pass has several new arguments on its constructor:

• do_commutative_analysis: enables exploiting commutativity between gates in order to collect larger blocks of nodes.

• split_blocks: enables spliting collected blocks into sub-blocks over disjoint subsets of qubits. For example, in the following circuit:

qc = QuantumCircuit(4)
qc.cx(0, 2)
qc.cx(1, 3)
qc.cx(2, 0)
qc.cx(3, 1)
qc.cx(1, 3)


the single block of CX gates over qubits {0, 1, 2, 3} can be split into two disjoint sub-blocks, one over qubits {0, 2} and the other over qubits {1, 3}.

• min_block_size: allows to specify the minimum size of the block to be consolidated, blocks with fewer gates will not be modified. For example, in the following circuit:

qc = QuantumCircuit(4)
qc.cx(1, 2)
qc.cx(2, 1)


the two CX gates will be consolidated when min_block_size is 1 or 2, and will remain unchanged when min_block_size is 3 or larger.

• Added a new class PermutationGate for representing permutation logic as a circuit element. Unlike the existing Permutation circuit library element which had a static definition this new class avoids synthesizing a permutation circuit when it is declared. This delays the actual synthesis to the transpiler. It also allows enables using several different algorithms for synthesizing permutations, which are available as high-level-synthesis permutation plugins.

Another key feature of the PermutationGate is that implements the __array__ interface for efficiently returning a unitary matrix for a permutation.

• Added several high-level-synthesis plugins for synthesizing permutations:

For example:

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import PermutationGate
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig, HighLevelSynthesis
from qiskit.transpiler.passes.synthesis.plugin import HighLevelSynthesisPluginManager

# Create a permutation and add it to a quantum circuit
perm = PermutationGate([4, 6, 3, 7, 1, 2, 0, 5])
qc = QuantumCircuit(8)
qc.append(perm, range(8))

# Print available plugin names for synthesizing permutations
# Returns ['acg', 'basic', 'default', 'kms']
print(HighLevelSynthesisPluginManager().method_names("permutation"))

# Default plugin for permutations
# Returns a quantum circuit with size 6 and depth 3
qct = PassManager(HighLevelSynthesis()).run(qc)
print(f"Default: {qct.size() = }, {qct.depth() = }")

# KMSSynthesisPermutation plugin for permutations
# Returns a quantum circuit with size 18 and depth 6
# but adhering to the linear nearest-neighbor architecture.
qct = PassManager(HighLevelSynthesis(HLSConfig(permutation=[("kms", {})]))).run(qc)
print(f"kms: {qct.size() = }, {qct.depth() = }")

# BasicSynthesisPermutation plugin for permutations
# Returns a quantum circuit with size 6 and depth 3
qct = PassManager(HighLevelSynthesis(HLSConfig(permutation=[("basic", {})]))).run(qc)
print(f"basic: {qct.size() = }, {qct.depth() = }")

# ACGSynthesisPermutation plugin for permutations
# Returns a quantum circuit with size 6 and depth 2
qct = PassManager(HighLevelSynthesis(HLSConfig(permutation=[("acg", {})]))).run(qc)
print(f"acg: {qct.size() = }, {qct.depth() = }")

• Added a new option circuit_reverse_bits to the user config file. This allows users to set a boolean for their preferred default behavior of the reverse_bits argument of the circuit drawers QuantumCircuit.draw() and circuit_drawer(). For example, adding a section to the user config file in the default location ~/.qiskit/settings.conf with:

[default]
circuit_reverse_bits = True


will change the default to display the bits in reverse order.

• Added a new pulse directive TimeBlockade. This directive behaves almost identically to the delay instruction, but will be removed before execution. This directive is intended to be used internally within the pulse builder and helps ScheduleBlock represent instructions with absolute time intervals. This allows the pulse builder to convert Schedule into ScheduleBlock, rather than wrapping with Call instructions.

• Added primitive-enabled algorithms for Variational Quantum Time Evolution that implement the interface for Quantum Time Evolution. The qiskit.algorithms.VarQRTE class is used for real and the qiskit.algorithms.VarQITE class is used for imaginary quantum time evolution according to a variational principle passed.

Each algorithm accepts a variational principle which implements the ImaginaryVariationalPrinciple abstract interface. The following implementations are included:

For example:

from qiskit.algorithms import TimeEvolutionProblem, VarQITE
from qiskit.algorithms.time_evolvers.variational import ImaginaryMcLachlanPrinciple
from qiskit.circuit.library import EfficientSU2
from qiskit.quantum_info import SparsePauliOp
import numpy as np

observable = SparsePauliOp.from_list(
[
("II", 0.2252),
("ZZ", 0.5716),
("IZ", 0.3435),
("ZI", -0.4347),
("YY", 0.091),
("XX", 0.091),
]
)

ansatz = EfficientSU2(observable.num_qubits, reps=1)
init_param_values = np.zeros(len(ansatz.parameters))
for i in range(len(ansatz.parameters)):
init_param_values[i] = np.pi / 2
var_principle = ImaginaryMcLachlanPrinciple()
time = 1
evolution_problem = TimeEvolutionProblem(observable, time)
var_qite = VarQITE(ansatz, var_principle, init_param_values)
evolution_result = var_qite.evolve(evolution_problem)

• Added a new keyword argument, allow_unknown_parameters, to the ParameterExpression.bind() and ParameterExpression.subs() methods. When set this new argument enables passing a dictionary containing unknown parameters to these methods without causing an error to be raised. Previously, this would always raise an error without any way to disable that behavior.

• The BaseEstimator.run() method's observables argument now accepts a str or sequence of str input type in addition to the other types already accepted. When used the input string format should match the Pauli string representation accepted by the constructor for Pauli objects.

• Added a new constructor method QuantumCircuit.from_instructions() that enables creating a QuantumCircuit object from an iterable of instructions. For example:

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.quantumcircuitdata import CircuitInstruction
from qiskit.circuit import Measure
from qiskit.circuit.library import HGate, CXGate

qr = QuantumRegister(2)
cr = ClassicalRegister(2)
instructions = [
CircuitInstruction(HGate(), [qr[0]], []),
CircuitInstruction(CXGate(), [qr[0], qr[1]], []),
CircuitInstruction(Measure(), [qr[0]], [cr[0]]),
CircuitInstruction(Measure(), [qr[1]], [cr[1]]),
]
circuit = QuantumCircuit.from_instructions(instructions)
circuit.draw("mpl")

• The Clifford class now takes an optional copy keyword argument in its constructor. If set to False, then a StabilizerTable provided as input will not be copied, but will be used directly. This can have performance benefits, if the data in the table will never be mutated by any other means.

• The performance of Clifford.compose() has been greatly improved for all numbers of qubits. For operators of 20 qubits, the speedup is on the order of 100 times.

• Added a new synthesis function synth_clifford_layers(), for synthesizing a Clifford into layers. The algorithm is based on S. Bravyi, D. Maslov, Hadamard-free circuits expose the structure of the Clifford group, arxiv:2003.09412. This decomposes the Clifford into 8 layers of gates including two layers of CZ gates, and one layer of CX gates. For example, a 5-qubit Clifford circuit is decomposed into the following layers:

     ┌─────┐┌─────┐┌────────┐┌─────┐┌─────┐┌─────┐┌─────┐┌────────┐
q_0: ┤0    ├┤0    ├┤0       ├┤0    ├┤0    ├┤0    ├┤0    ├┤0       ├
│     ││     ││        ││     ││     ││     ││     ││        │
q_1: ┤1    ├┤1    ├┤1       ├┤1    ├┤1    ├┤1    ├┤1    ├┤1       ├
│     ││     ││        ││     ││     ││     ││     ││        │
q_2: ┤2 S2 ├┤2 CZ ├┤2 CX_dg ├┤2 H2 ├┤2 S1 ├┤2 CZ ├┤2 H1 ├┤2 Pauli ├
│     ││     ││        ││     ││     ││     ││     ││        │
q_3: ┤3    ├┤3    ├┤3       ├┤3    ├┤3    ├┤3    ├┤3    ├┤3       ├
│     ││     ││        ││     ││     ││     ││     ││        │
q_4: ┤4    ├┤4    ├┤4       ├┤4    ├┤4    ├┤4    ├┤4    ├┤4       ├
└─────┘└─────┘└────────┘└─────┘└─────┘└─────┘└─────┘└────────┘


This method will allow to decompose a Clifford in 2-qubit depth $$7n+2$$ for linear nearest neighbor (LNN) connectivity.

• The EquivalenceLibrary is now represented internally as a PyDiGraph, this underlying graph object can be accesed from the new graph attribute. This attribute is intended for use internally in Qiskit and therefore should always be copied before being modified by the user to prevent possible corruption of the internal equivalence graph.

• The Operator.from_circuit() constructor method now will reverse the output permutation caused by the routing/swap mapping stage of the transpiler. By default if a transpiled circuit had Swap gates inserted the output matrix will have that permutation reversed so the returned matrix will be equivalent to the original un-transpiled circuit. If you'd like to disable this default behavior the ignore_set_layout keyword argument can be set to True to do this (in addition to previous behavior of ignoring the initial layout from transpilation). If you'd like to manually set a final layout you can use the new final_layout keyword argument to pass in a Layout object to use for the output permutation.

• Added support for using the Python exponentiation operator, **, with Gate objects is now supported. It is equivalent to running the Gate.power() method on the object.

For example:

from qiskit.circuit.library import XGate

sx = XGate() ** 0.5

• Added new GaussianSquareDrag pulse shape to the qiskit.pulse.library module. This pulse shape is similar to GaussianSquare but uses the Drag shape during its rise and fall. The correction from the DRAG pulse shape can suppress part of the frequency spectrum of the rise and fall of the pulse which can help avoid exciting spectator qubits when they are close in frequency to the drive frequency of the pulse.

• Added a new keyword argument, method, to the constructors for the FiniteDiffEstimatorGradient and FiniteDiffSamplerGradient classes. The method argument accepts a string to indicate the computation method to use for the gradient. There are three methods, available "central", "forward", and "backward". The definition of the methods are:

Method

Computation

"central"

$$\frac{f(x+e)-f(x-e)}{2e}$$

"forward"

$$\frac{f(x+e) - f(x)}{e}$$

"backward"

$$\frac{f(x)-f(x-e)}{e}$$

where $$e$$ is the offset epsilon.

• All gradient classes in qiskit.algorithms.gradients now preserve unparameterized operations instead of attempting to unroll them. This allows to evaluate gradients on custom, opaque gates that individual primitives can handle and keeps a higher level of abstraction for optimized synthesis and compilation after the gradient circuits have been constructed.

• Added a TranslateParameterizedGates pass to map only parameterized gates in a circuit to a specified basis, but leave unparameterized gates untouched. The pass first attempts unrolling and finally translates if a parameterized gate cannot be further unrolled.

• The CollectCliffords transpiler pass has been expanded to collect and combine blocks of "clifford gates" into Clifford objects, where "clifford gates" may now also include objects of type LinearFunction, Clifford, and PauliGate. For example:

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import LinearFunction, PauliGate
from qiskit.quantum_info.operators import Clifford
from qiskit.transpiler.passes import CollectCliffords
from qiskit.transpiler import PassManager

# Create a Clifford
cliff_circuit = QuantumCircuit(2)
cliff_circuit.cx(0, 1)
cliff_circuit.h(0)
cliff = Clifford(cliff_circuit)

# Create a linear function
lf = LinearFunction([[0, 1], [1, 0]])

# Create a pauli gate
pauli_gate = PauliGate("XYZ")

# Create a quantum circuit with the above and also simple clifford gates.
qc = QuantumCircuit(4)
qc.cz(0, 1)
qc.append(cliff, [0, 1])
qc.h(0)
qc.append(lf, [0, 2])
qc.append(pauli_gate, [0, 2, 1])
qc.x(2)

# Run CollectCliffords transpiler pass
qct = PassManager(CollectCliffords()).run(qc)


All the gates will be collected and combined into a single Clifford. Thus the final circuit consists of a single Clifford object.

• CouplingMap is now implicitly iterable, with the iteration being identical to iterating through the output of CouplingMap.get_edges(). In other words,

from qiskit.transpiler import CouplingMap
coupling = CouplingMap.from_line(3)
list(coupling) == list(coupling.get_edges())


will now function as expected, as will other iterations. This is purely a syntactic convenience.

• Added a new function synth_cnot_count_full_pmh() which is used to synthesize linear reversible circuits for all-to-all architectures using the Patel, Markov and Hayes method. This function is identical to the available qiskit.transpiler.synthesis.cnot_synth() function but has a more descriptive name and is more logically placed in the package tree. This new function supersedes the legacy function which will likely be deprecated in a future release.

• InstructionScheduleMap has been updated to store backend calibration data in the format of PulseQobj JSON and invokes conversion when the data is accessed for the first time, i.e. lazy conversion. This internal logic update drastically improves the performance of loading backend especially with many calibration entries.

• New module qiskit.pulse.calibration_entries has been added. This contains several wrapper classes for different pulse schedule representations.

• ScheduleDef

• CallableDef

• PulseQobjDef

These classes implement the get_schedule() and get_signature() methods that returns pulse schedule and parameter names to assign, respectively. These classes are internally managed by the InstructionScheduleMap or backend Target, and thus they will not appear in a typical user programs.

• Introduced a new subclass ScalableSymbolicPulse, as a subclass of SymbolicPulse. The new subclass behaves the same as SymbolicPulse, except that it assumes that the envelope of the pulse includes a complex amplitude pre-factor of the form $$\text{amp} * e^{i \times \text{angle}}$$. This envelope shape matches many common pulses, including all of the pulses in the Qiskit Pulse library (which were also converted to amp, angle representation in this release).

The new subclass removes the non-unique nature of the amp, angle representation, and correctly compares pulses according to their complex amplitude.

• Support for importing OpenQASM 3 programs into Qiskit has been added. This can most easily be accessed using the functions qasm3.loads() and qasm3.load(), to load a program directly from a string and indirectly from a filename, respectively. For example, one can now do:

from qiskit import qasm3

OPENQASM 3.0;
include "stdgates.inc";

qubit q;
qubit[5] qr;
bit c;
bit[5] cr;

h q;
c = measure q;

if (c) {
h qr[0];
cx qr[0], qr[1];
cx qr[0], qr[2];
cx qr[0], qr[3];
cx qr[0], qr[4];
} else {
h qr[4];
cx qr[4], qr[3];
cx qr[4], qr[2];
cx qr[4], qr[1];
cx qr[4], qr[0];
}
cr = measure qr;
""")


This will load the program into a QuantumCircuit instance in the variable circuit.

Not all OpenQASM 3 features are supported at first, because Qiskit does not yet have a way to represent advanced classical data processing. The capabilities of the importer will increase along with the capabilities of the rest of Qiskit. The initial feature set of the importer is approximately the same set of features that would be output by the exporter (qasm3.dump() and qasm3.dumps()).

Note that Qiskit's support of OpenQASM 3 is not meant to provide a totally lossless representation of QuantumCircuits. For that, consider using qiskit.qpy.

• The primitives-based gradient classes defined by the BaseEstimatorGradient and BaseSamplerGradient abstract classes have been updated to simplify extending the base interface. There are three new internal overridable methods, _preprocess(), _postprocess(), and _run_unique(). _preprocess() enables a subclass to customize the input gradient circuits and parameters, _postprocess enables to customize the output result, and _run_unique enables calculating the gradient of a circuit with unique parameters.

• The SabreLayout transpiler pass has greatly improved performance as it has been re-written in Rust. As part of this rewrite the pass has been transformed from an analysis pass to a transformation pass that will run both layout and routing. This was done to not only improve the runtime performance but also improve the quality of the results. The previous functionality of the pass as an analysis pass can be retained by manually setting the routing_pass argument or using the new skip_routing argument.

• The SabreLayout transpiler pass has a new constructor argument layout_trials. This argument is used to control how many random number generator seeds will be attempted to run SabreLayout with. When set the SABRE layout algorithm is run layout_trials number of times and the best quality output (measured in the lowest number of swap gates added) is selected. These seed trials are executed in parallel using multithreading to minimize the potential performance overhead of running layout multiple times. By default if this is not specified the SabreLayout pass will default to using the number of physical CPUs are available on the local system.

• Added two new classes SciPyRealEvolver and SciPyImaginaryEvolver that implement integration methods for time evolution of a quantum state. The value and standard deviation of observables as well as the times they are evaluated at can be queried as TimeEvolutionResult.observables and TimeEvolutionResult.times. For example:

from qiskit.algorithms.time_evolvers.time_evolution_problem import TimeEvolutionProblem
from qiskit.quantum_info import SparsePauliOp
from qiskit.quantum_info.states.statevector import Statevector
from qiskit.algorithms import SciPyImaginaryEvolver

initial_state = Statevector.from_label("+++++")
hamiltonian = SparsePauliOp("ZZZZZ")
evolution_problem = TimeEvolutionProblem(hamiltonian, 100, initial_state, {"Energy":hamiltonian})
classic_evolver = SciPyImaginaryEvolver(num_timesteps=300)
result = classic_evolver.evolve(evolution_problem)
print(result.observables)

• Added the SolovayKitaev transpiler pass to run the Solovay-Kitaev algorithm for approximating single-qubit unitaries using a discrete gate set. In combination with the basis translator, this allows to convert any unitary circuit to a universal discrete gate set, which could be implemented fault-tolerantly.

This pass can e.g. be used after compiling to U and CX gates:

from qiskit import transpile
from qiskit.circuit.library import QFT
from qiskit.transpiler.passes.synthesis import SolovayKitaev

qft = QFT(3)

# optimize to general 1-qubit unitaries and CX
transpiled = transpile(qft, basis_gates=["u", "cx"], optimization_level=1)

skd = SolovayKitaev()  # uses T Tdg and H as default basis
discretized = skd(transpiled)

print(discretized.count_ops())


The decomposition can also be used with the unitary synthesis plugin, as the "sk" method on the UnitarySynthesis transpiler pass:

from qiskit import QuantumCircuit
from qiskit.quantum_info import Operator
from qiskit.transpiler.passes import UnitarySynthesis

circuit = QuantumCircuit(1)
circuit.rx(0.8, 0)
unitary = Operator(circuit).data

unitary_circ = QuantumCircuit(1)
unitary_circ.unitary(unitary, [0])

synth = UnitarySynthesis(basis_gates=["h", "s"], method="sk")
out = synth(unitary_circ)

out.draw('mpl')

• The Optimize1qGatesDecomposition transpiler pass has a new keyword argument, target, on its constructor. This argument can be used to specify a Target object that represnts the compilation target. If used it superscedes the basis argument to determine if an instruction in the circuit is present on the target backend.

• The UnrollCustomDefinitions transpiler pass has a new keyword argument, target, on its constructor. This argument can be used to specify a Target object that represnts the compilation target. If used it superscedes the basis_gates argument to determine if an instruction in the circuit is present on the target backend.

• Added the ReverseEstimatorGradient class for a classical, fast evaluation of expectation value gradients based on backpropagation or reverse-mode gradients. This class uses statevectors and thus provides exact gradients but scales exponentially in system size. It is designed for fast reference calculation of smaller system sizes. It can for example be used as:

from qiskit.circuit.library import EfficientSU2
from qiskit.quantum_info import SparsePauliOp

observable = SparsePauliOp.from_sparse_list([("ZZ", [0, 1], 1)], num_qubits=10)
circuit = EfficientSU2(num_qubits=10)
values = [i / 100 for i in range(circuit.num_parameters)]


• Added the ability for analysis passes to set custom heuristic weights for the VF2Layout and VF2PostLayout transpiler passes. If an analysis pass sets the vf2_avg_error_map key in the property set, its value is used for the error weights instead of the error rates from the backend's Target (or BackendProperties for BackendV1). The value should be an ErrorMap instance, where each value represents the avg error rate for all 1 or 2 qubit operation on those qubits. If a value is NaN, the corresponding edge is treated as an ideal edge (or qubit for 1q operations). For example, an error map created as:

from qiskit.transpiler.passes.layout.vf2_utils import ErrorMap

error_map = ErrorMap(3)


describes a 2 qubit target, where the avg 1q error rate is 0.0024 on qubit 0 and 0.0032 on qubit 1, the avg 2q error rate for gates that operate on (0, 1) is 0.01, and (1, 0) is not supported by the target. This will be used for scoring if it's set for the vf2_avg_error_map key in the property set when VF2Layout and VF2PostLayout are run. For example:

from qiskit.transpiler import AnalysisPass, PassManager, Target
from qiskit.transpiler.passes import VF2Layout
from qiskit.transpiler.passes.layout.vf2_utils import ErrorMap
from qiskit.circuit.library import CZGate, UGate
from qiskit.circuit import Parameter

class CustomVF2Scoring(AnalysisPass):
"""Set custom score for vf2."""

def run(self, dag):
error_map = ErrorMap(3)
self.property_set["vf2_avg_error_map"] = error_map

target = Target(num_qubits=2)
UGate(Parameter('theta'), Parameter('phi'), Parameter('lam')),
{(0,): None, (1,): None}
)
CZGate(), {(0, 1): None}
)

vf2_pass = VF2Layout(target=target, seed=1234568942)
pm = PassManager([CustomVF2Scoring(), vf2_pass])


That will run VF2Layout with the custom scoring from error_map for a 2 qubit Target that doesn't contain any error rates.

• When initializing any of the pulse classes in qiskit.pulse.library:

providing a complex amp argument with a finite angle will result in PulseError now. For example, instead of calling Gaussian(duration=100,sigma=20,amp=0.5j) one should use Gaussian(duration=100,sigma=20,amp=0.5,angle=np.pi/2) instead now. The pulse envelope which used to be defined as amp * ... is in turn defined as amp * exp(1j * angle) * .... This change was made to better support Qiskit Experiments where the amplitude and angle of pulses are calibrated in separate experiments.

• For Python 3.7 singledispatchmethod is now a dependency. This was added to enable leveraging the method dispatch mechanism in the standard library of newer versions of Python. If you're on Python >= 3.8 there is no extra dependency required.

• EquivalenceLibrary objects that are initialized with the base attribute will no long have a shared reference with the EquivalenceLibrary passed in. In earlier releases if you mutated base after it was used to create a new EquivalenceLibrary instance both instances would reflect that change. This no longer is the case and updates to base will no longer be reflected in the new EquivalenceLibrary. For example, if you created an equivalence library with:

import math

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import XGate
from qiskit.circuit.equivalence import EquivalenceLibrary

original_lib = EquivalenceLibrary()
qc = QuantumCircuit(1)
qc.rx(math.pi, 0)
new_lib = EquivalenceLibrary(base=original_lib)


if you modified original_lib with:

import from qiskit.circuit.library import SXGate

qc = QuantumCircuit(1)
qc.rx(math.pi / 2, 0)


in previous releases new_lib would also include the definition of SXGate after it was added to original_lib, but in this release this no longer will be the case. This change was made because of the change in internal data structure to be a graph, which improved performance of the EquivalenceLibrary class, especially when there are multiple runs of the BasisTranslator transpiler pass.

• The initial_state argument for the constructor of the NLocal class along with assigning directly to the NLocal.initial_state atrribute must be a QuantumCircuit now. Support for using other types for this argument and attribute is no longer supported. Support for other types was deprecated as part of the Qiskit Terra 0.18.0 release (July 2021).

• The LaTeX array drawers (e.g. array_to_latex, Statevector.draw('latex')) now use the same sympy function as the ket-convention drawer. This means it may render some numbers differently to previous releases, but will provide a more consistent experience. For example, it may identify new factors, or rationalize denominators where it did not previously. The default precision has been changed from 5 to 10.

• The QPY version format version emitted by dump() has been increased to version 6. 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 6. This change was necessary to support the introduction of ScalableSymbolicPulse which was handled by adding a class_name_size attribute to the header of the dumped SymbolicPulse objects.

• The __hash__ method for the SymbolicPulse was removed. This was done to reflect the mutable nature (via parameter assignment) of this class which could result in errors when using SymbolicPulse in situtations where a hashable object was required. This means the builtin hash() method and using SymbolicPulse as keys in dictionaries or set members will no longer work.

• The names of Register instances (which includes instances of QuantumRegister and ClassicalRegigster) are no longer constrained to be valid OpenQASM 2 identifiers. This is being done as the restriction is overly strict as Qiskit becomes more decoupled from OpenQASM 2, and even the OpenQASM 3 specification is not so restrictive. If you were relying on registers having valid OpenQASM 2 identifier names, you will need to begin escaping the names. A simplistic version of this could be done, for example, by:

import re
import string

def escape(name: str) -> str:
out = re.sub(r"\W", "_", name, flags=re.ASCII)
if not out or out[0] not in string.ascii_lowercase:
return "reg_" + out
return out

• The previously deprecated ParameterView methods which were inherited from set have been removed from ParameterView, the type returned by QuantumCircuit.parameters. The specific methods which have been removed are:

• add()

• difference()

• difference_update()

• discard()

• intersection()

• intersection_update()

• issubset()

• issuperset()

• symmetric_difference()

• symmetric_difference_update()

• union()

• update()

along with support for the Python operators:

• ixor: ^=

• isub: -=

• ior: |=

These were deprecated in the Qiskit Terra 0.17.0 release (April, 2021). The ParameterView type is now a general sequence view type and doesn't support these set operations any longer.

• The previously deprecated NetworkX converter methods for the DAGCircuit and DAGDependency classes: DAGCircuit.to_networkx(), DAGCircuit.from_networkx(), and DAGDependency.to_networkx() have been removed. These methods were originally deprecated as part of the Qiskit Terra 0.21.0 release (June, 2022). Qiskit has been using rustworkx as its graph library since the qiskit-terra 0.12.0 release and since then the NetworkX converter function have been a lossy process. They were originally added so that users could leverage NetworkX's algorithms library to leverage functionality not present in DAGCircuit and/or rustworkx. However, since that time both DAGCircuit and rustworkx has matured and offers more functionality and the DAGCircuit is tightly coupled to rustworkx for its operation and having these converter methods provided limited functionality and therefore have been removed.

• tweedledum has been removed as a core requirement of Qiskit Terra. The functionality provided (qiskit.circuit.classicalfunction) is still available, if tweedledum is installed manually, such as by:

pip install tweedledum


This change was made because tweedledum development has slowed to the point of not keeping up with new Python and OS releases, and was blocking some Qiskit users from installing Qiskit.

• The previously deprecated gate argument to the constructor of the Decompose transpiler pass, along with its matching attribute Decompose.gate have been removed. The argument and attribute were deprecated as part of the Qiskit Terra 0.19.0 release (December, 2021). Instead the gates_to_decompose argument for the constructor along with the Decompose.gates_to_decompose attribute should be used instead. The gates_to_decompose argument and attribute should function the same, but has a more explicit name and also enables specifying lists of gates instead of only supporting a single gate.

• The retworkx dependency for Qiskit has been removed and replaced by rustworkx library. These are the same packages, but rustworkx is the new name for retworkx which was renamed as part of their combined 0.12.0 release. If you were previously using retworkx 0.12.0 with Qiskit then you already installed rustworkx (retworkx 0.12.0 was just a redirect shim for backwards compatibility). This change was made to migrate to the new package name which will be the only supported package in the future.

• The default behavior of the SabreLayout compiler pass has changed. The pass is no longer an AnalysisPass and by default will compute the initital layout, apply it to the circuit, and will also run SabreSwap internally and apply the swap mapping and set the final_layout property set with the permutation caused by swap insertions. This means for users running SabreLayout as part of a custom PassManager will need to adjust the pass manager to account for this (unless they were setting the routing_pass argument for SabreLayout). This change was made in the interest of improving the quality output, the layout and routing quality are highly coupled and SabreLayout will now run multiple parallel seed trials and to calculate which seed provides the best results it needs to perform both the layout and routing together. There are three ways you can adjust the usage in your custom pass manager. The first is to avoid using embedding in your preset pass manager. If you were previously running something like:

from qiskit.transpiler import PassManager
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.passes.SabreLayout

pm = PassManager()
pm.append(SabreLayout(coupling_map)
pm += common.generate_embed_passmanager(coupling_map)


to compute the layout and then apply it (which was typically followed by routing) you can adjust the usage to just simply be:

from qiskit.transpiler import PassManager
from qiskit.transpiler.preset_passmanagers import common
from qiskit.transpiler.passes.SabreLayout

pm = PassManager()
pm.append(SabreLayout(coupling_map)


as SabreLayout will apply the layout and you no longer need the embedding stage. Alternatively, you can specify the routing_pass argument which will revert SabreLayout to its previous behavior. For example, if you want to run SabreLayout as it was run in previous releases you can do something like:

from qiskit.transpiler.passes import SabreSwap, SabreLayout
routing_pass = SabreSwap(
coupling_map, "decay", seed=seed, fake_run=True
)
layout_pass = SabreLayout(coupling_map, routing_pass=routing_pass, seed=seed)


which will have SabreLayout run as an analysis pass and just set the layout property set. The final approach is to leverage the skip_routing argument on SabreLayout, when this argument is set to True it will skip applying the found layout and inserting the swap gates from routing. However, doing this has a runtime penalty as SabreLayout will still be computing the routing and just does not use this data. The first two approaches outlined do not have additional overhead associated with them.

• The layouts computed by the SabreLayout pass (when run without the routing_pass argument) 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 SabreLayout 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. Alternatively you can explicitly set the routing_pass argument to an instance of SabreSwap to mirror the previous behavior of SabreLayout:

from qiskit.transpiler.passes import SabreSwap, SabreLayout

routing_pass = SabreSwap(
coupling_map, "decay", seed=seed, fake_run=True
)
layout_pass = SabreLayout(coupling_map, routing_pass=routing_pass, seed=seed)


which will mirror the behavior of the pass in the previous release. Note, that if you were using the swap_trials argument on SabreLayout in previous releases when adjusting the usage to this form that you will need to set trials argument on the SabreSwap constructor if you want to retain the previous output with a fixed seed.

• The exact circuit returned by qiskit.circuit.random.random_circuit for a given seed has changed. This is due to efficiency improvements in the internal random-number generation for the function.

• The version requirement for the optional feature package qiskit-toqm, installable via pip install qiskit-terra[toqm], has been upgraded from version 0.0.4 to 0.1.0. To use the toqm routing method with transpile() you must now use qiskit-toqm version 0.1.0 or newer. Older versions are no longer discoverable by the transpiler.

• The output QuasiDistribution from the Sampler.run method has been updated to filter out any states with a probability of zero. Now if a valid state is missing from the dictionary output it can be assumed to have a 0 probability. Previously, all possible outcomes for a given number of bits (e.g. for a 3 bit result 000, 001, 010, 011, 100, 101, 110, and 111) even if the probability of a given state was 0. This change was made to reduce the size of the output as for larger number of bits the output size could be quite large. Also, filtering the zero probability results makes the output consistent with other implementations of BaseSampler.

• The behavior of the pulse builder when a Schedule is called has been upgraded. Called schedules are internally converted into ScheduleBlock representation and now reference mechanism is always applied rather than appending the schedules wrapped by the Call instruction. Note that the converted block doesn't necessary recover the original alignment context. This is simply an ASAP aligned sequence of pulse instructions with absolute time intervals. This is an upgrade of internal representation of called pulse programs and thus no API changes. However the Call instruction and Schedule no longer appear in the builder's pulse program. This change guarantees the generated schedule blocks are always QPY compatible. If you are filtering the output schedule instructions by Call, you can access to the ScheduleBlock.references instead to retrieve the called program.

##### Deprecation Notes¶
• Support for running Qiskit with Python 3.7 support has been deprecated and will be removed in the qiskit-terra 0.25.0 release. This means starting in the 0.25.0 release you will need to upgrade the Python version you're using to Python 3.8 or above.

• The class LinearFunctionsSynthesis class is now deprecated and will be removed in a future release. It has been superseded by the more general HighLevelSynthesis class which should be used instead. For example, you can instantiate an instance of HighLevelSynthesis that will behave the same way as LinearFunctionSynthesis with:

from qiskit.transpiler.passes import HighLevelSynthesis
from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig

HighLevelSynthesis(
HLSConfig(
linear_function=[("default", {})],
use_default_on_unspecified=False,
)
)

• Support for passing in lists of argument values to the transpile() function is deprecated and will be removed in the 0.25.0 release. This is being done to facilitate greatly reducing the overhead for parallel execution for transpiling multiple circuits at once. If you're using this functionality currently you can call transpile() multiple times instead. For example if you were previously doing something like:

from qiskit.transpiler import CouplingMap
from qiskit import QuantumCircuit
from qiskit import transpile

qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
cmaps = [CouplingMap.from_heavy_hex(d) for d in range(3, 15, 2)]
results = transpile([qc] * 6, coupling_map=cmaps)


instead you should run something like:

from itertools import cycle
from qiskit.transpiler import CouplingMap
from qiskit import QuantumCircuit
from qiskit import transpile

qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
cmaps = [CouplingMap.from_heavy_hex(d) for d in range(3, 15, 2)]

results = []
for qc, cmap in zip(cycle([qc]), cmaps):
results.append(transpile(qc, coupling_map=cmap))


You can also leverage parallel_map() or multiprocessing from the Python standard library if you want to run this in parallel.

• The legacy version of the pulse drawer present in the qiskit.visualization.pulse has been deprecated and will be removed in a future release. This includes the ScheduleDrawer and :classWaveformDrawer classes. This module has been superseded by the qiskit.visualization.pulse_v2 drawer and the typical user API pulse_drawer() and PulseBlock.draw() are already updated internally to use qiskit.visualization.pulse_v2.

• The pulse.Instruction.draw() method has been deprecated and will removed in a future release. The need for this method has been superseded by the qiskit.visualization.pulse_v2 drawer which doesn't require Instrucion objects to have their own draw method. If you need to draw a pulse instruction you should leverage the pulse_drawer() instead.

• The import qiskit.circuit.qpy_serialization is deprecated, as QPY has been promoted to the top level. You should import the same objects from qiskit.qpy instead. The old path will be removed in a future of Qiskit Terra.

• The qiskit.IBMQ object is deprecated. This alias object lazily redirects attribute access to qiskit.providers.ibmq.IBMQ. As the qiskit-ibmq-provider package has been supersceded by qiskit-ibm-provider package which maintains its own namespace maintaining this alias is no longer relevant with the new package. If you were relying on the qiskit.IBMQ alias you should update your usage to use qiskit.providers.ibmq.IBMQ directly instead (and also consider migrating to qiskit-ibm-provider, see the migration guide for more details).

• Several public methods of pulse Qobj converters have been deprecated and in a future release they will no longer be directly callable. The list of methods is:

In InstructionToQobjConverter,

• convert_acquire()

• convert_bundled_acquires()

• convert_set_frequency()

• convert_shift_frequency()

• convert_set_phase()

• convert_shift_phase()

• convert_delay()

• convert_play()

• convert_snapshot()

In QobjToInstructionConverter,

• convert_acquire()

• convert_set_phase()

• convert_shift_phase()

• convert_set_frequency()

• convert_shift_frequency()

• convert_delay()

• bind_pulse()

• convert_parametric()

• convert_snapshot()

Instead of calling any of these methods directly they will be implicitly selected when a converter instance is directly called. For example:

converter = QobjToInstructionConverter()
converter(pulse_qobj)

• The qiskit.visualization.state_visualization.num_to_latex_ket() and qiskit.visualization.state_visualization.num_to_latex_terms() functions have been deprecated and will be removed in a future release. These function were primarily used internally by the LaTeX output from Statevector.draw() and DensityMatrix.draw() which no longer are using these function and are leverging sympy for this instead. If you were using these functions you should cosinder using Sympy's nsimplify() latex() functions.

• The method Register.qasm() is deprecated and will be removed in a future release. This method is found on the subclasses QuantumRegister and ClassicalRegister. The deprecation is because the qasm() method promotes a false view of the responsible party for safe conversion to OpenQASM 2; a single object alone does not have the context to provide a safe conversion, such as whether its name clashes after escaping it to produce a valid identifier.

• The class-variable regular expression Register.name_format is deprecated and wil be removed in a future release. The names of registers are now permitted to be any valid Python string, so the regular expression has no use any longer.

##### Bug Fixes¶
• Fixed an issue in the PauliOp.adjoint() method where it would return the correct value for Paulis with complex coefficients, for example: PauliOp(Pauli("iX")). Fixed #9433.

• Fixed an issue with the amplitude estimation algorithms in the qiskit.algorithms.amplitude_estimators module (see Amplitude Estimators) for the usage with primitives built from the abstract BaseSampler primitive (such as Sampler and BackendSampler). Previously, the measurement results were expanded to more bits than actually measured which for oracles with more than one qubit led to potential errors in the detection of the "good" quantum states for oracles.

• Fixed an issue where the QuantumCircuit.add_calibrations() and DAGCircuit.add_calibrations() methods had a mismatch in their behavior of parameter-formatting logic. Previously DAGCircuit.add_calibrations() tried to cast every parameter into float, QuantumCircuit.add_calibrations() used given parameters as-is. This would potentially cause an error when running transpile() on a QuantumCircuit with pulse gates as the parameters of the calibrations could be kept as ParameterExpresion objects.

• Fixed an issue in TensoredOp.to_matrix() where the global coefficient of the operator was multiplied to the final matrix more than once. Now, the global coefficient is correctly applied, independent of the number of tensored operators or states. Fixed #9398.

• The OpenQASM 2 exporter method QuantumCircuit.qasm() will now emit higher precision floating point numbers for gate parameters by default. In addition, a tighter bound ($$1e-12$$ instead of $$1e-6$$) is used for checking whether a given parameter is close to a fraction/power of $$\pi$$. Fixed #7166.

• Fixed support in the primitives module for running QuantumCircuit objects with control flow instructions (e.g. IfElseOp). Previously, the BaseSampler and BaseEstimator base classes could not correctly normalize such circuits. However, executing these circuits is dependent on the particular implementation of the primitive supporting control flow instructions. This just fixed support to enable a particular implementation of BaseSampler or BaseEstimator to use control flow instructions.

• Fixed an issue with the PauliOp.matmul() method where it would return incorrect results with iI. Fixed #8680.

• Fixed an issue with the Approximate Quantum Compiler (AQC) class which caused it to return an incorrect circuit when the input unitary had a determinant of -1. Fixed #9327

• Fixed an issue with the QuantumCircuit.compose() method where it would incorrectly map registers in conditions on the given circuit to complete registers on the base. Previously, the mapping was very imprecise; the bits used within each condition were not subject to the mapping, and instead an inaccurate attempt was made to find a corresponding register. This could also result in a condition on a smaller register being expanded to be on a larger register, which is not a valid transformation. Now, a condition on a single bit or a register will be composed to be on precisely the bits as defined by the clbits argument. A new aliasing register will be added to the base circuit to facilitate this, if necessary. Fixed #6583.

• Fixed an issue with the transpile() function when run with optimization_level set to 1, 2, or 3 and no backend, basis_gates, or target argument specified. If the input circuit had runs of single qubit gates which could be simplified the output circuit would not be as optimized as possible as those runs of single qubit gates would not have been removed. This could have been corrected previously by specifying either the backend, basis_gates, or target arguments on the transpile() call, but now the output will be as simplified as it can be without knowing the target gates allowed. Fixed #9217

• Fixed an issue with the transpile() function when run with optimization_level=3 and no backend, basis_gates, or target argument specified. If the input circuit contained any 2 qubit blocks which were equivalent to an identity matrix the output circuit would not be as optimized as possible and and would still contain that identity block. This could have been corrected previously by specifying either the backend, basis_gates, or target arguments on the transpile() call, but now the output will be as simplified as it can be without knowing the target gates allowed. Fixed #9217

• Fixed an issue in the metadata output from primitives where the list made copies by reference and all elements were updated with the same value at every iteration.

• Fixed an issue with the QobjToInstructionConverter when multiple backends are called and they accidentally have the same pulse name in the pulse library. This was an edge case that could only be caused when a converter instance was reused across multiple backends (this was not a typical usage pattern).

• Fixed an issue with the PVQD class where the loss function was incorrecly squaring the fidelity. This has been fixed so that the loss function matches the definition in the original algorithm definition.

• Fixed a bug in QPY (qiskit.qpy) where circuits containing registers whose bits occurred in the circuit after loose bits would fail to deserialize. See #9094.

• The class TwoQubitWeylDecomposition is now compatible with the pickle protocol. Previously, it would fail to deserialize and would raise a TypeError. See #7312.

• Fixed an issue with the TwoQubitWeylDecomposition class (and its subclasses) to enable the Python standard library pickle to serialize these classes. This partially fixed #7312

No change

No change

### Qiskit 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 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 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 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.

No change

No change

### Qiskit 0.39.4¶

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

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

No change

### Qiskit 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.

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

No change

No change

### Qiskit 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 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.

No change

No change

### Qiskit 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_listargument. 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¶
• 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

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


This will now correctly raise a TranspilerError instead of causing runtime issues when interacting with the target. Fixed #8914

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

• 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

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

• 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

• 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

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

• 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

• 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

#### 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 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 and Estimator can now be used with qiskit-terra >= 0.22.0.

No change

### Qiskit 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),
}
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),
}
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),
}
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),
}
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),
}
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),
}


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 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 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:

For example:

estimator = Estimator(...)

• 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 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 $$n-1$$ CXGate gates, instead of $$\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.

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

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

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

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

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)

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

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

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

def objective(x):
return (np.linalg.norm(x) - 1) ** 2

return 2 * (np.linalg.norm(x) - 1) * x / np.linalg.norm(x)

initial_point = np.random.normal(0, 1, size=(100,))

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

def objective(x):
if random.choice([True, False]):
return None
else:
return (np.linalg.norm(x) - 1) ** 2

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,))

while optimizer.continue_condition():

optimizer.state.njev += 1

optmizer.state.nit += 1

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:

Layout-related

Routing-related

Translation-related

Optimization-related

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.

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

• 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)
cmap = target.build_coupling_map()
if cmap is None:
cmap = CouplingMap()
for i in range(target.num_qubits):

• 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 $$n-1$$ instead of $$\frac{n(n-1)}{2}$$ CXGate gates. If you desire the previous default you can explicity set entanglement="full" when calling either constructor.

• 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 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 $$n$$ 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.

• 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 on the optimizer for more detail on the relationship between these arguments.

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

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

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

##### Bug Fixes¶
• 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)

• 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

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

• 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

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

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

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

No change

No change

### Qiskit 0.38.0¶

No change

#### Aer 0.11.0¶

##### Prelude¶

The Qiskit Aer 0.11.0 release highlights are:

##### New Features¶
• Added a shared library to Qiskit Aer that allows external programs to use Aer's simulation methods. This is an experimental feature and its API may be changed without the deprecation period.

• Added support for M1 macOS systems. Precompiled binaries for supported Python versions >=3.8 on arm64 macOS will now be published on PyPI for this and future releases.

• Added support for cuQuantum, NVIDIA's APIs for quantum computing, to accelerate statevector, density matrix and unitary simulators by using GPUs. This is experiemental implementation for cuQuantum Beta 2. (0.1.0) cuStateVec APIs are enabled to accelerate instead of Aer's implementations by building Aer by setting path of cuQuantum to CUSTATEVEC_ROOT. (binary distribution is not available currently.) cuStateVector is enabled by setting device='GPU' and cuStateVec_threshold options. cuStateVec is enabled when number of qubits of input circuit is equal or greater than cuStateVec_threshold.

• Added partial support for running on ppc64le and s390x Linux platforms. This release will start publishing pre-compiled binaries for ppc64le and s390x Linux platforms on all Python versions. However, unlike other supported platforms not all of Qiskit's upstream dependencies support these platforms yet. So a C/C++ compiler may be required to build and install these dependencies and a simple pip install qiskit-aer with just a working Python environment will not be sufficient to install Qiskit Aer. Additionally, these same constraints prevent us from testing the pre-compiled wheels before publishing them, so the same guarantees around platform support that exist for the other platforms don't apply to these platforms.

• Allow initialization with a label, that consists of +-rl. Now the following code works:

import qiskit
from qiskit_aer import AerSimulator

qc = qiskit.QuantumCircuit(4)
qc.initialize('+-rl')
qc.save_statevector()

AerSimulator(method="statevector").run(qc)

##### Known Issues¶
• When running on Linux s390x platforms (or other big endian platforms) running circuits that contain UnitaryGate operations will not work because of an endianess bug. See #1506 for more details.

• MPI parallelization for large number of qubits is optimized to apply multiple chunk-swaps as all-to-all communication that can decrease data size exchanged over MPI processes. This upgrade improve scalability of parallelization.

• Set default fusion_max_qubit and fusion_threshold depending on the configured method for AerSimulator. Previously, the default values of fusion_max_qubit and fusion_threshold were 5 and 14 respectively for all simulation methods. However, their optimal values depend on running methods. If you depended on the previous defaults you can explicitly set fusion_max_qubit=5 or fusion_threshold=14 to retain the previous default behavior. For example:

from qiskit_aer import AerSimulator

sim = AerSimulator(method='mps', fusion_max_qubit=5, fusion_threshold=14)

• This is update to support cuQuantum 22.5.0.41 including bug fix of thread safety in some cuStateVec APIs. Now Qiskit Aer turns on multi-threading for multi-shots and multi-chunk parallelization when enabling cuStateVec.

• Running qiskit-aer with Python 3.6 is no longer supported. Python >= 3.7 is now required to install and run qiskit-aer.

• The qiskit-aer Python package has moved to be a self-contained namespace, qiskit_aer. Previously, it shared a namespace with qiskit-terra by being qiskit.providers.aer. This was problematic for several reasons, and this release moves away from it. For the time being import qiskit.providers.aer will continue to work and redirect to qiskit_aer automatically. Imports from the legacy qiskit.provider.aer namespace will emit a DeprecationWarning in the future. To avoid any potential issues starting with this release, updating all imports from qiskit.providers.aer to qiskit_aer and from qiskit.Aer to qiskit_aer.Aer is recommended.

• Removed snapshot instructions (such as SnapshotStatevector) which were deprecated since 0.9.0. Applications that use these instructions need to be modified to use corresponding save instructions (such as SaveStatevector).

• Removed the qiskit_aer.extensions module completely. With the removal of the snapshot instructions, this module has become empty and no longer serves a purpose.

• The required version of Qiskit Terra has been bumped to 0.20.0.

##### Bug Fixes¶
• Fixes for MPI chunk distribution. Including fix for global indexing for Thrust implementations, fix for cache blocking of non-gate operations. Also savestatevector returns same statevector to all processes (only 1st process received statevector previously.)

• Handles a multiplexer gate as a unitary gate if it has no control qubits. Previously, if a multiplexer gate does not have control qubits, quantum state was not updated.

• Fixes a bug in RelaxationNoisePass where instruction durations were always assumed to be in dt time units, regardless of the actual unit of the isntruction. Now unit conversion is correctly handled for all instruction duration units.

See #1453 for details.

• Fixed simulation of for loops where the loop parameter was not used in the body of the loop. For example, previously this code would fail, but will now succeed:

import qiskit
from qiskit_aer import AerSimulator

qc = qiskit.QuantumCircuit(2)
with qc.for_loop(range(4)) as i:
qc.h(0)
qc.cx(0, 1)

AerSimulator(method="statevector").run(qc)

• Fixes a bug in NoiseModel.from_backend() that raised an error when T2 value greater than 2 * T1 was supplied by the backend. After this fix, it becomes to truncate T2 value up to 2 * T1 and issue a user warning if truncates. The bug was introduced at #1391 and, before that, NoiseModel.from_backend() had truncated the T2 value up to 2 * T1 silently.

See Issue 1464 for details.

• Fix performance regression in noisy simulations due to large increase in serialization overhead for loading noise models from Python into C++ resulting from unintended nested Python multiprocessing calls. See issue 1407 for details.

• This is the fix for Issue #1557. Different seed numbers are generated for each process if seed_simulator option is not set. This fix average seed set in Circuit for all processes to use the same seed number.

• This is a fix of MPI parallelization for multi-chunk parallelization and multi-shot distribution over parallel processes. There were missing distribution configuration that prevents MPI distribution, is now fixed.

• This is fix for cache blocking transpiler and chunk parallelization for GPUs or MPI. This fix fixes issue with qubits which has many control or target qubits (> blocking_qubits). From this fix, only target qubits of the multi-controlled gate is cache blocked in blocking_qubits. But it does not support case if number of target qubits is still larger than blocking_qubits (i.e. large unitary matrix multiplication)

• Fixes a bug in QuantumError.to_dict() where N-qubit circuit instructions where the assembled instruction always applied to qubits [0, ..., N-1] rather than the instruction qubits. This bug also affected device and fake backend noise models.

See Issue 1415 for details.

• Because a seed was randomly assigned to each circuit if seed_simulator is not set, multi-circuit simulation was not reproducible with another multi-circuit simulation. Users needed to run multiple single-circuit simulation with the seed_simulator which is randomly assigned in the multi-circuit simulation. This fix allows users to reproduce multi-circuit simulation with another multi-circuit simulation by setting seed_simulator of the first circuit in the first multi-circuit simulation. This fix also resolve an issue reported in https://github.com/Qiskit/qiskit-aer/issues/1511, where simulation with parameter-binds returns identical results for each circuit instance.

• Fix performance issue in multi-shots batched optimization for GPU when using Pauli noise. This fix allows multi-threading to runtime noise sampling, and uses nested OpenMP parallelization when using multiple GPUs. This is fix for issue 1473 <https://github.com/Qiskit/qiskit-aer/issues/1473>

• This is the fix for cuStateVec support, fix for build error because of specification change of some APIs of cuStateVec from cuQuantum version 0.40.

• Fixes an issue when while_loop is the tail of QuantumCircuit. while_loop is translated to jump and mark instructions. However, if a while_loop is at the end of a circuit, its mark instruction is truncated wrongly. This fix corrects the truncation algorithm to always remain mark instructions.

No change

### Qiskit 0.37.2¶

#### Terra 0.21.2¶

##### Prelude¶

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.

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

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

No change

No change

### Qiskit 0.37.1¶

#### 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()
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]])]
)

• 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)
right_circuit.x(0)

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)
print(encoding.decompose().draw())


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.

No change

No change

### Qiskit 0.37.0¶

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 project. You can refer to the migration guide for details on how to switch from Qiskit Ignis to Qiskit Experiments.

#### Terra 0.21.0¶

##### Prelude¶

The Qiskit 0.21.0 release highlights are:

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(),
ConsolidateBlocks(basis_gates=basis_gates),
UnitarySynthesis(basis_gates)])

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 the @ (__matmul__) binary operator to BaseOperator subclasses in the qiskit.quantum_info module. This is shorthand to call the classes' dot method (A @ B == A.dot(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()
circuit.decompose(reps=2)

# 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)
qc.cx(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, qct.data))

• 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 $$\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 $$\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 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.

• Added a new layout and routing method to transpile() based on the paper "Time-optimal qubit mapping". To use it, the optional package Qiskit TOQM 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,
quantum_instance=QuantumInstance(backend=backend),
reps=p)

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 pulse.build() as schedule:
pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0))

with open('schedule.qpy', 'wb') as fd:
qpy.dump(schedule, fd)

with open('schedule.qpy', 'rb') as fd:


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

• 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 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(
instruction_schedule_map=inst_map,
qubit_channel_mapping=channel_map,
)


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(
instruction_schedule_map=inst_map,
qubit_channel_mapping=channel_map,
)

• 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:

sgn_prod

Use Pauli.compose() or Pauli.dot() instead.

to_spmatrix

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

kron

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.

insert_paulis
append_paulis
delete_qubits
pauli_single

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

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

random

Use quantum_info.random_pauli() instead.

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

• 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¶
• The NetworkX 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 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 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.

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

• Fixed the ConfigurableFakeBackend.t2 attribute, which was previously incorrectly set based on the provided t1 value.

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

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

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 for the details). PR #1135 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 replaces them with threading.current_thread, notify_all added in Python 2.6 (October 2008).

### Qiskit 0.36.2¶

#### Terra 0.20.2¶

##### Prelude¶

Qiskit Terra 0.20.2 is a bugfix release, addressing some minor issues identified since the last patch release.

##### Bug Fixes¶
• Fixed an issue with BackendV2-based fake backend classes from the qiskit.providers.fake_provider module such as FakeMontrealV2, where the values for the dtm and dt attributes and the associated attribute Target.dt would not be properly converted to seconds. This would cause issues when using these fake backends with scheduling. See #8018.

• marginal_counts() will now succeed when asked to marginalize memory with an indices parameter containing non-zero elements. Previously, shots whose hexadecimal result representation was sufficiently small could raise a ValueError. See #8044.

• The OpenQASM 3 exporter (qiskit.qasm3) will now output input or output declarations before gate declarations. This is more consistent with the current reference ANTLR grammar from the OpenQASM 3 team. See #7964.

• Fixed a bug in the RZXCalibrationBuilder transpiler pass where the scaled cross-resonance pulse amplitude could appear to be parametrized even after assignment. This could cause the pulse visualization tools to use the parametrized format instead of the expected numeric one. See #8031.

• Fixed an issue with the transpile() function when run with a BackendV2-based backend and setting the scheduling_method keyword argument. Previously, the function would not correctly process the default durations of the instructions supported by the backend which would lead to an error.

• The SabreSwap transpiler pass, used in transpile() when routing_method="sabre" is set, will no longer sporadically drop classically conditioned gates and their successors from circuits during the routing phase of transpilation. See #8040.

• Statevector will now allow direct iteration through its values (such as for coefficient in statevector) and correctly report its length under len. Previously it would try and and access out-of-bounds data and raise a QiskitError. See #8039.

No change

#### Ignis 0.7.1¶

##### Prelude¶

This is a bugfix release that primarily fixes a packaging issue that was causing the docs/ directory, which contains the source files used to build the qiskit-ignis documentation, to get included in the Python package.

No change

### Qiskit 0.36.1¶

#### Terra 0.20.1¶

##### Prelude¶

Qiskit Terra 0.20.1 is a bugfix release resolving issues identified in release 0.20.0.

##### Known Issues¶
• Since its original introduction in Qiskit Terra 0.20, XXPlusYYGate has used a negative angle convention compared to all other rotation gates. In Qiskit Terra 0.21, this will be corrected to be consistent with the other rotation gates. This does not affect any other rotation gates, nor XXMinusYYGate.

##### Bug Fixes¶
• Fixed an issue where the eval_observables() function would raise an error if its quantum_state argument was of type StateFn. eval_observables now correctly supports all input types denoted by its type hints.

• Fixed parameter validation for class Drag. Previously, it was not sensitive to large beta values with negative signs, which may have resulted in waveform samples with a maximum value exceeding the amplitude limit of 1.0.

• Fixed a bug that could result in exponential runtime and nontermination when a Pauli instance is given to method init_observables().

• Fixed SabreSwap, and by extension transpile() with optimization_level=3, occasionally re-ordering measurements invalidly. Previously, if two measurements wrote to the same classical bit, SabreSwap could (depending on the coupling map) re-order them to produce a non-equivalent circuit. This behaviour was stochastic, so may not have appeared reliably. Fixed #7950

• The SabreSwap transpiler pass, and by extension SabreLayout and transpile() at optimization_level=3, now has an escape mechanism to guarantee that it can never get stuck in an infinite loop. Certain inputs previously could, with a great amount of bad luck, get stuck in a stable local minimum of the search space and the pass would never make further progress. It will now force a series of swaps that allow the routing to continue if it detects it has not made progress recently. Fixed #7707.

No change

No change

#### 0.19.1¶

##### Bug Fixes¶
• PR #1129 updates least_busy() method to no longer support BaseBackend as a valid input or output type since it has been long deprecated in qiskit-terra and has recently been removed.

### Qiskit 0.36.0¶

No change

#### Aer 0.10.4¶

• Qiskit Aer is no longer compiled with unsafe floating-point optimisations. While most of the effects should have been localised to Qiskit Aer, some aspects of subnormal handling may previously have been leaked into user code by the library incorrectly setting the "flush to zero" mode. This will not happen any more.

##### Bug Fixes¶
• Fix cache blocking transpiler to recognize superop to be cache blocked. This is fix for issue 1479 <https://github.com/Qiskit/qiskit-aer/issues/1479> now density_matrix with noise models can be parallelized. New test, test_noise.TestNoise.test_kraus_gate_noise_on_QFT_cache_blocking is added to verify this issue. Also this fix include fix for issue 1483 <https://github.com/Qiskit/qiskit-aer/issues/1483> discovered by adding new test case. This fixes measure over chunks for statevector.

• Fixes a bug in NoiseModel.from_backend() that raised an error when T2 value greater than 2 * T1 was supplied by the backend. After this fix, it becomes to truncate T2 value up to 2 * T1 and issue a user warning if truncates. The bug was introduced at #1391 and, before that, NoiseModel.from_backend() had truncated the T2 value up to 2 * T1 silently.

See Issue 1464 for details.

• device=Thrust was very slow for small number of qubits because OpenMP threading was always applied. This fix applies OpenMP threads as same as device=CPU by using statevector_parallel_threshold.

• Qiskit Aer will no longer set the floating-point mode to "flush to zero" when loaded. Downstream users may previously have seen warnings from Numpy such as:

The value of the smallest subnormal for <class 'numpy.float64'> type is zero.

These will now no longer be emitted, and the floating-point handling will be correct.

• Fixed a potential issue with running simulations on circuits that have the QuantumCircuit.metadata attribute set. The metadata attribute can be any python dictionary and previously qiskit-aer would attempt to JSON serialize the contents of the attribute to process it with the rest of the rest of the circuit input, even if the contents were not JSON serializable. This no longer occurs as the QuantumCircuit.metadata attribute is not used to run the simulation so now the contents are no serialized and instead are directly attached to the qiskit.result.Result object without attempting to JSON serialize the contents. Fixed #1435

No change

#### IBM Q Provider 0.19.0¶

##### New Features¶
• The qiskit-ibmq-provider package now supports IBM Quantum LiveData features. These features allow users to observe the real-time behavior of IBM Quantum backends while executing jobs. Specifically, the provider now includes a new tab in the backend Jupyter-related widget and supports the execution of jobs (via qiskit.providers.ibmq.IBMQBackend.run() method) with the live_data_enabled=True parameter in allowed IBM Quantum backends.

• You can now specify a different logging level in the options keyword when submitting a Qiskit Runtime job with the qiskit.providers.ibmq.runtime.IBMRuntimeService.run() method.

• Python 3.6 support has been dropped since it has reached end of life in Dec 2021.

• qiskit.providers.ibmq.random, the random number service which was used to access the CQC randomness extractor is no longer supported and has been removed.

### Qiskit 0.35.0¶

#### Terra 0.20.0¶

##### Prelude¶

The Qiskit Terra 0.20.0 release highlights are:

• The introduction of multithreaded modules written in Rust to accelerate the performance of certain portions of Qiskit Terra and improve scaling with larger numbers of qubits. However, when building Qiskit from source a Rust compiler is now required.

• More native support for working with a Target in the transpiler. Several passes now support working directly with a Target object which makes the transpiler robust in the types of backends it can target.

• The introduction of the qiskit.primitives module. These APIs provide different abstraction levels for computing outputs of interest from QuantumCircuit and using backends. For example, the BaseEstimator defines an abstract interface for estimating an expectation value of an observable. This can then be used to construct higher level algorithms and applications that are built using the estimation of expectation values without having to worry about the implementation of computing the expectation value. This decoupling allows the implementation to improve in speed and quality while adhering to the defined abstract interface. Likewise, the BaseSampler computes quasi-probability distributions from circuit measurements. Other primitives will be introduced in the future.

This release no longer has support for Python 3.6. With this release, Python 3.7 through Python 3.10 are required.

##### New Features¶
• Added a new constructor method for the Operator class, Operator.from_circuit() for creating a new Operator object from a QuantumCircuit. While this was possible normally using the default constructor, the Operator.from_circuit() method provides additional options to adjust how the operator is created. Primarily this lets you permute the qubit order based on a set Layout. For, example:

from qiskit.circuit import QuantumCircuit
from qiskit import transpile
from qiskit.transpiler import CouplingMap
from qiskit.quantum_info import Operator

circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)

cmap = CouplingMap.from_line(3)
out_circuit = transpile(circuit, initial_layout=[2, 1, 0], coupling_map=cmap)
operator = Operator.from_circuit(out_circuit)


the operator variable will have the qubits permuted based on the layout so that it is identical to what is returned by Operator(circuit) before transpilation.

• The fake backend and fake provider classes which were previously available in qiskit.test.mock are now also accessible in a new module: qiskit.providers.fake_provider. This new module supersedes the previous module qiskit.test.mock which will be deprecated in Qiskit 0.21.0.

• FlowController classes (such as ConditionalController) can now be nested inside a PassManager instance when using the PassManager.append() method. This enables the use of nested logic to control the execution of passes in the PassManager. For example:

from qiskit.transpiler import ConditionalController, PassManager
from qiskit.transpiler.passes import (
BasisTranslator, GatesInBasis, Optimize1qGatesDecomposition, FixedPoint, Depth
)
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel

pm = PassManager()

def opt_control(property_set):
return not property_set["depth_fixed_point"]

def unroll_condition(property_set):
return not property_set["all_gates_in_basis"]

depth_check = [Depth(), FixedPoint("depth")]
opt = [Optimize1qGatesDecomposition(['rx', 'ry', 'rz', 'rxx'])]
unroll = [BasisTranslator(sel, ['rx', 'ry', 'rz', 'rxx'])]
unroll_check = [GatesInBasis(['rx', 'ry', 'rz', 'rxx'])]
flow_unroll = [ConditionalController(unroll, condition=unroll_condition)]

pm.append(depth_check + opt + unroll_check + flow_unroll, do_while=opt_control)


The pm PassManager object will only execute the BasisTranslator pass (in the unroll step) in each loop iteration if the unroll_condition is met.

• The constructors for the ZFeatureMap and ZZFeatureMap classes have a new keyword argument parameter_prefix. This new argument is used to set the prefix of parameters of the data encoding circuit. For example:

from qiskit.circuit.library import ZFeatureMap

feature_map = ZFeatureMap(feature_dimension=4, parameter_prefix="my_prefix")
feature_map.decompose().draw('mpl')


the generated ZFeatureMap circuit has prefixed all its internal parameters with the prefix "my_prefix".

• The TemplateOptimization transpiler pass can now work with Gate objects that have ParameterExpression parameters. An illustrative example of using Parameters with TemplateOptimization is the following:

from qiskit import QuantumCircuit, transpile, schedule
from qiskit.circuit import Parameter

from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import TemplateOptimization

# New contributions to the template optimization
from qiskit.transpiler.passes.calibration import RZXCalibrationBuilder, rzx_templates

from qiskit.test.mock import FakeCasablanca
backend = FakeCasablanca()

phi = Parameter('φ')

qc = QuantumCircuit(2)
qc.cx(0,1)
qc.p(2*phi, 1)
qc.cx(0,1)
print('Original circuit:')
print(qc)

pass_ = TemplateOptimization(**rzx_templates.rzx_templates(['zz2']))
qc_cz = PassManager(pass_).run(qc)
print('ZX based circuit:')
print(qc_cz)

pass_ = RZXCalibrationBuilder(backend)
cal_qc = PassManager(pass_).run(qc_cz.bind_parameters({phi: 0.12}))

# Transpile to the backend basis gates
cal_qct = transpile(cal_qc, backend)
qct = transpile(qc.bind_parameters({phi: 0.12}), backend)

# Compare the schedule durations
print('Duration of schedule with the calibration:')
print(schedule(cal_qct, backend).duration)
print('Duration of standard with two CNOT gates:')
print(schedule(qct, backend).duration)


outputs

Original circuit:

q_0: ──■──────────────■──
┌─┴─┐┌────────┐┌─┴─┐
q_1: ┤ X ├┤ P(2*φ) ├┤ X ├
└───┘└────────┘└───┘
ZX based circuit:
┌─────────────┐            »
q_0: ────────────────────────────────────┤0            ├────────────»
┌──────────┐┌──────────┐┌──────────┐│  Rzx(2.0*φ) │┌──────────┐»
q_1: ┤ Rz(-π/2) ├┤ Rx(-π/2) ├┤ Rz(-π/2) ├┤1            ├┤ Rx(-2*φ) ├»
└──────────┘└──────────┘└──────────┘└─────────────┘└──────────┘»
«
«q_0: ────────────────────────────────────────────────
«     ┌──────────┐┌──────────┐┌──────────┐┌──────────┐
«q_1: ┤ Rz(-π/2) ├┤ Rx(-π/2) ├┤ Rz(-π/2) ├┤ P(2.0*φ) ├
«     └──────────┘└──────────┘└──────────┘└──────────┘
Duration of schedule with the calibration:
1600
Duration of standard with two CNOT gates:
6848

• The performance of the SparsePauliOp.simplify() method has greatly improved by replacing the use of numpy.unique to compute unique elements of an array by a new similar function implemented in Rust that doesn't pre-sort the array.

• Added a new method equiv() to the SparsePauliOp class for testing the equivalence of a SparsePauliOp with another SparsePauliOp object. Unlike the == operator which compares operators element-wise, equiv() compares whether two operators are equivalent or not. For example:

op = SparsePauliOp.from_list([("X", 1), ("Y", 1)])
op2 = SparsePauliOp.from_list([("X", 1), ("Y", 1), ("Z", 0)])
op3 = SparsePauliOp.from_list([("Y", 1), ("X", 1)])

print(op == op2)  # False
print(op == op3)  # False
print(op.equiv(op2))  # True
print(op.equiv(op3))  # True

• Added new fake backend classes from snapshots of the IBM Quantum systems based on the BackendV2 interface and provided a Target for each backend. BackendV2 based versions of all the existing backends are added except for three old backends FakeRueschlikon, FakeTenerife and FakeTokyo as they do not have snapshots files available which are required for creating a new fake backend class based on BackendV2.

These new V2 fake backends will enable testing and development of new features introduced by BackendV2 and Target such as improving the transpiler.

• The FakeBogota, FakeManila, FakeRome, and FakeSantiago fake backends which can be found in the qiskit.providers.fake_provider module can now be used as backends in Pulse experiments as they now include a PulseDefaults created from a snapshot of the equivalent IBM Quantum machine's properties.

• The ConsolidateBlocks pass has a new keyword argument on its constructor, target. This argument is used to specify a Target object representing the compilation target for the pass. If it is specified it supersedes the basis_gates kwarg. If a target is specified, the pass will respect the gates and qubits for the instructions defined in the Target when deciding which gates to consolidate into a unitary.

• Added a new kwarg, metadata_serializer, to the qpy.dump() function for specifying a custom JSONEncoder subclass for use when serializing the QuantumCircuit.metadata attribute and a dual kwarg metadata_deserializer to the qpy.load() function for specifying a JSONDecoder subclass. By default the dump() and load() functions will attempt to JSON serialize and deserialize with the stdlib default json encoder and decoder. Since QuantumCircuit.metadata can contain any Python dictionary, even those with contents not JSON serializable by the default encoder, will lead to circuits that can't be serialized. The new metadata_serializer argument for dump() enables users to specify a custom JSONEncoder that will be used with the internal json.dump() call for serializing the QuantumCircuit.metadata dictionary. This can then be paired with the new metadata_deserializer argument of the qpy.load() function to decode those custom JSON encodings. If metadata_serializer is specified on dump() but metadata_deserializer is not specified on load() calls the QPY will be loaded, but the circuit metadata may not be reconstructed fully.

For example if you wanted to define a custom serialization for metadata and then load it you can do something like:

from qiskit.qpy import dump, load
from qiskit.circuit import QuantumCircuit, Parameter
import json
import io

class CustomObject:
"""Custom string container object."""

def __init__(self, string):
self.string = string

def __eq__(self, other):
return self.string == other.string

class CustomSerializer(json.JSONEncoder):
"""Custom json encoder to handle CustomObject."""

def default(self, o):
if isinstance(o, CustomObject):
return {"__type__": "Custom", "value": o.string}
return json.JSONEncoder.default(self, o)

class CustomDeserializer(json.JSONDecoder):
"""Custom json decoder to handle CustomObject."""

def __init__(self, *args, **kwargs):
super().__init__(*args, object_hook=self.object_hook, **kwargs)

def object_hook(self, o):
"""Hook to override default decoder."""
if "__type__" in o:
obj_type = o["__type__"]
if obj_type == "Custom":
return CustomObject(o["value"])
return o

theta = Parameter("theta")
qc = QuantumCircuit(2, global_phase=theta)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
circuits = [qc, qc.copy()]
with io.BytesIO() as qpy_buf:
qpy_buf.seek(0)

• The DenseLayout pass has a new keyword argument on its constructor, target. This argument is used to specify a Target object representing the compilation target for the pass. If it is specified it supersedes the other arguments on the constructor, coupling_map and backend_prop.

• A new pass DynamicalDecouplingPadding has been added to the qiskit.transpiler.passes module. This new pass supersedes the existing DynamicalDecoupling pass to work with the new scheduling workflow in the transpiler. It is a subclass of the BasePadding pass and depends on having scheduling and alignment analysis passes run prior to it in a PassManager. This new pass can take a pulse_alignment argument which represents a hardware constraint for waveform start timing. The spacing between gates comprising a dynamical decoupling sequence is now adjusted to satisfy this constraint so that the circuit can be executed on hardware with the constraint. This value is usually found in BackendConfiguration.timing_constraints. Additionally the pass also has an extra_slack_distribution option has been to control how to distribute the extra slack when the duration of the created dynamical decoupling sequence is shorter than the idle time of your circuit that you want to fill with the sequence. This defaults to middle which is identical to conventional behavior. The new strategy split_edges evenly divide the extra slack into the beginning and end of the sequence, rather than adding it to the interval in the middle of the sequence. This might result in better noise cancellation especially when pulse_alignment > 1.

• The Z2Symmetries class now exposes the threshold tolerances used to chop small real and imaginary parts of coefficients. With this one can control how the coefficients of the tapered operator are simplified. For example:

from qiskit.opflow import Z2Symmetries
from qiskit.quantum_info import Pauli

z2_symmetries = Z2Symmetries(
symmetries=[Pauli("IIZI"), Pauli("IZIZ"), Pauli("ZIII")],
sq_paulis=[Pauli("IIXI"), Pauli("IIIX"), Pauli("XIII")],
sq_list=[1, 0, 3],
tapering_values=[1, -1, -1],
tol=1e-10,
)


By default, coefficients are chopped with a tolerance of tol=1e-14.

• Added a chop() method to the SparsePauliOp class that truncates real and imaginary parts of coefficients individually. This is different from the SparsePauliOp.simplify() method which removes a coefficient only if the absolute value is close to 0. For example:

>>> from qiskit.quantum_info import SparsePauliOp
>>> op = SparsePauliOp(["X", "Y", "Z"], coeffs=[1+1e-17j, 1e-17+1j, 1e-17])
>>> op.simplify()
SparsePauliOp(['X', 'Y'],
coeffs=[1.e+00+1.e-17j, 1.e-17+1.e+00j])
>>> op.chop()
SparsePauliOp(['X', 'Y'],
coeffs=[1.+0.j, 0.+1.j])


Note that the chop method does not accumulate the coefficents of the same Paulis, e.g.

>>> op = SparsePauliOp(["X", "X"], coeffs=[1+1e-17j, 1e-17+1j)
>>> op.chop()
SparsePauliOp(['X', 'X'],
coeffs=[1.+0.j, 0.+1.j])

• Added partial support for running on ppc64le and s390x Linux platforms. This release will start publishing pre-compiled binaries for ppc64le and s390x Linux platforms on all Python versions. However, unlike other supported platforms not all of Qiskit's upstream dependencies support these platforms yet. So a C/C++ compiler may be required to build and install these dependencies and a simple pip install qiskit-terra with just a working Python environment will not be sufficient to install Qiskit. Additionally, these same constraints prevent us from testing the pre-compiled wheels before publishing them, so the same guarantees around platform support that exist for the other platforms don't apply here.

• The Gradient and QFI classes can now calculate the imaginary part of expectation value gradients. When using a different measurement basis, i.e. -Y instead of Z, we can measure the imaginary part of gradients The measurement basis can be set with the aux_meas_op argument.

For the gradients, aux_meas_op = Z computes 0.5Re[(⟨ψ(ω)|)O(θ)|dωψ(ω)〉] and aux_meas_op = -Y computes 0.5Im[(⟨ψ(ω)|)O(θ)|dωψ(ω)〉]. For the QFIs, aux_meas_op = Z computes 4Re[(dω⟨<ψ(ω)|)(dω|ψ(ω)〉)] and aux_meas_op = -Y computes 4Im[(dω⟨<ψ(ω)|)(dω|ψ(ω)〉)]. For example:

from qiskit import QuantumRegister, QuantumCircuit
from qiskit.opflow import CircuitStateFn, Y
from qiskit.circuit import Parameter

a = Parameter("a")
b = Parameter("b")
params = [a, b]

q = QuantumRegister(1)
qc = QuantumCircuit(q)
qc.h(q)
qc.rz(params[0], q[0])
qc.rx(params[1], q[0])
op = CircuitStateFn(primitive=qc, coeff=1.0)

aux_meas_op = -Y


• Added a new value for the style keyword argument on the circuit drawer function circuit_drawer() and QuantumCircuit.draw() method, iqx_dark. When style is set to iqx_dark with the mpl drawer backend, the output visualization will use a color scheme similar to the the dark mode color scheme used by the IBM Quantum composer. For example:

from qiskit.circuit import QuantumCircuit
from matplotlib.pyplot import show

circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.p(0.2, 1)

circuit.draw("mpl", style="iqx-dark")

• Several lazy dependency checkers have been added to the new module qiskit.utils.optionals, which can be used to query if certain Qiskit functionality is available. For example, you can ask if Qiskit has detected the presence of matplotlib by asking if qiskit.utils.optionals.HAS_MATPLOTLIB. These objects only attempt to import their dependencies when they are queried, so you can use them in runtime code without affecting import time.

• Import time for qiskit has been significantly improved, especially for those with many of Qiskit Terra's optional dependencies installed.

• The marginal_counts() function now supports marginalizing the memory field of an input Result object. For example, if the input result argument is a qiskit Result object obtained from a 4-qubit measurement we can marginalize onto the first qubit with:

print(result.results[0].data.memory)
marginal_result = marginal_counts(result, [0])
print(marginal_result.results[0].data.memory)


The output is:

['0x0', '0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7']
['0x0', '0x1', '0x0', '0x1', '0x0', '0x1', '0x0', '0x1']

• The internals of the StochasticSwap algorithm have been reimplemented to be multithreaded and are now written in the Rust programming language instead of Cython. This significantly increases the run time performance of the compiler pass and by extension transpile() when run with optimization_level 0, 1, and 2. By default the pass will use up to the number of logical CPUs on your local system but you can control the number of threads used by the pass by setting the RAYON_NUM_THREADS environment variable to an integer value. For example, setting RAYON_NUM_THREADS=4 will run the StochasticSwap with 4 threads.

• A new environment variable QISKIT_FORCE_THREADS is available for users to directly control whether potentially multithreaded portions of Qiskit's code will run in multiple threads. Currently this is only used by the StochasticSwap transpiler pass but it likely will be used other parts of Qiskit in the future. When this env variable is set to TRUE any multithreaded code in Qiskit Terra will always use multiple threads regardless of any other runtime conditions that might have otherwise caused the function to use a single threaded variant. For example, in StochasticSwap if the pass is being run as part of a transpile() call with > 1 circuit that is being executed in parallel with multiprocessing via parallel_map() the StochasticSwap will not use multiple threads to avoid potentially oversubscribing CPU resources. However, if you'd like to use multiple threads in the pass along with multiple processes you can set QISKIT_FORCE_THREADS=TRUE.

• New fake backend classes are available under qiskit.providers.fake_provider. These include mocked versions of ibm_cairo, ibm_hanoi, ibmq_kolkata, ibm_nairobi, and ibm_washington. As with the other fake backends, these include snapshots of calibration and error data taken from the real system, and can be used for local testing, compilation and simulation.

• Introduced a new class StatePreparation. This class allows users to prepare a desired state in the same fashion as Initialize without the reset being automatically applied.

For example, to prepare a qubit in the state $$(|0\rangle - |1\rangle) / \sqrt{2}$$:

import numpy as np
from qiskit import QuantumCircuit

circuit = QuantumCircuit(1)
circuit.prepare_state([1/np.sqrt(2), -1/np.sqrt(2)], 0)
circuit.draw()


The output is as:

     ┌─────────────────────────────────────┐
q_0: ┤ State Preparation(0.70711,-0.70711) ├
└─────────────────────────────────────┘

• The Optimize1qGates transpiler pass now has support for optimizing U1Gate, U2Gate, and PhaseGate gates with unbound parameters in a circuit. Previously, if these gates had unbound parameters the pass would not use them. For example:

from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import Optimize1qGates, Unroller

phi = Parameter('φ')
alpha = Parameter('α')

qc = QuantumCircuit(1)
qc.u1(2*phi, 0)
qc.u1(alpha, 0)
qc.u1(0.1, 0)
qc.u1(0.2, 0)

pm = PassManager([Unroller(['u1', 'cx']), Optimize1qGates()])
nqc = pm.run(qc)


will be combined to the circuit with only one single-qubit gate:

qc = QuantumCircuit(1)
qc.u1(2*phi + alpha + 0.3, 0)

• The methods Pauli.evolve() and PauliList.evolve() now have a new keyword argument, frame, which is used to perform an evolution of a Pauli by a Clifford. If frame='h' (default) then it does the Heisenberg picture evolution of a Pauli by a Clifford ($$P' = C^\dagger P C$$), and if frame='s' then it does the Schrödinger picture evolution of a Pauli by a Clifford ($$P' = C P C^\dagger$$). The latter option yields a faster calculation, and is also useful in certain cases. This new option makes the calculation of the greedy Clifford decomposition method in decompose_clifford significantly faster.

• Added a new module to Qiskit: qiskit.primitives. The primitives module is where APIs are defined which provide different abstractions around computing certain common functions from QuantumCircuit which abstracts away the details of the underlying execution on a Backend. This enables higher level algorithms and applications to concentrate on performing the computation and not need to worry about the execution and processing of results and have a standardized interface for common computations. For example, estimating an expectation value of a quantum circuit and observable can be performed by any class implementing the BaseEstimator class and consumed in a standardized manner regardless of the underlying implementation. Applications can then be written using the primitive interface directly.

To start the module contains two types of primitives, the Sampler (see BaseSampler for the abstract class definition) and Estimator (see BaseEstimator for the abstract class definition). Reference implementations are included in the qiskit.primitives module and are built using the qiskit.quantum_info module which perform ideal simulation of primitive operation. The expectation is that provider packages will offer their own implementations of these interfaces for providers which can efficiently implement the protocol natively (typically using a classical runtime). Additionally, in the future for providers which do not offer a native implementation of the primitives a method will be provided which will enable constructing primitive objects from a Backend.

• The basis search strategy in BasisTranslator transpiler pass has been modified into a variant of Dijkstra search which greatly improves the runtime performance of the pass when attempting to target an unreachable basis.

• The DenseLayout transpiler pass is now multithreaded, which greatly improves the runtime performance of the pass. By default, it will use the number of logical CPUs on your local system, but you can control the number of threads used by the pass by setting the RAYON_NUM_THREADS environment variable to an integer value. For example, setting RAYON_NUM_THREADS=4 will run the DenseLayout pass with 4 threads.

• Added a new SparsePauliOp.from_sparse_list() constructor that takes an iterable, where the elements represent Pauli terms that are themselves sparse, so that "XIIIIIIIIIIIIIIIX" can now be written as ("XX", [0, 16]). For example, the operator

$H = X_0 Z_3 + 2 Y_1 Y_4$

can now be constructed as

op = SparsePauliOp.from_sparse_list([("XZ", [0, 3], 1), ("YY", [1, 4], 2)], num_qubits=5)
# or equivalently, as previously
op = SparsePauliOp.from_list([("IZIIX", 1), ("YIIYI", 2)])


This facilitates the construction of very sparse operators on many qubits, as is often the case for Ising Hamiltonians.

• The UnitarySynthesis transpiler pass has a new keyword argument on its constructor, target. This can be used to optionally specify a Target object which represents the compilation target for the pass. When it's specified it will supersede the values set for basis_gates, coupling_map, and backend_props.

• Introduced a new transpiler pass workflow for building PassManager objects for scheduling QuantumCircuit objects in the transpiler. In the new workflow scheduling and alignment passes are all AnalysisPass objects that only update the property set of the pass manager, specifically new property set item node_start_time, which holds the absolute start time of each opnode. A separate TransformationPass such as PadDelay is subsequently used to apply scheduling to the DAG. This new workflow is both more efficient and can correct for additional timing constraints exposed by a backend.

Previously, the pass chain would have been implemented as scheduling -> alignment which were both transform passes thus there were multiple DAGCircuit instances recreated during each pass. In addition, scheduling occured in each pass to obtain instruction start time. Now the required pass chain becomes scheduling -> alignment -> padding where the DAGCircuit update only occurs at the end with the padding pass.

For those who are creating custom PassManager objects that involve circuit scheduling you will need to adjust your PassManager to insert one of the BasePadding` passes (currently either