Release Notes#

Up until version 0.44, qiskit was a “metapackage” that contained several different “elements”, such as the Aer simulator. What is called “Qiskit Terra” within this document is principally what is now just called “Qiskit”, i.e. the SDK.

Starting with qiskit 0.45, qiskit and qiskit-terra will have the same version and will not include any additional “elements”.

Metapackage Version Equivalency#

This table tracks the metapackage versions and the version of each legacy Qiskit element installed:

Qiskit Metapackage Version

qiskit-terra

qiskit-aer

qiskit-ignis

qiskit-ibmq-provider

qiskit-aqua

Release Date

0.44.1

0.25.1

2023-08-17

0.44.0

0.25.0

2023-07-27

0.43.3

0.24.2

0.12.2

0.20.2

2023-07-19

0.43.2

0.24.1

0.12.1

0.20.2

2023-06-28

0.43.1

0.24.1

0.12.0

0.20.2

2023-06-02

0.43.0

0.24.0

0.12.0

0.20.2

2023-05-04

0.42.1

0.23.3

0.12.0

0.20.2

2023-03-21

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

Note

For the 0.7.0, 0.7.1, and 0.7.2 meta-package releases the meta-package versioning strategy was not formalized yet.

Qiskit 0.44.1#

Terra 0.25.1#

Prelude#

Qiskit Terra 0.25.1 is a bugfix release, addressing some issues identified since the 0.25.1 release.

Bug Fixes#

  • Fixed a bug in QPY serialization (qiskit.qpy) where multiple controlled custom gates in a circuit could result in an invalid QPY file that could not be parsed. Fixed #9746.

  • Fixed #9363. by labeling the non-registerless synthesis in the order that Tweedledum returns. For example, compare this example before and after the fix:

    from qiskit.circuit import QuantumCircuit
    from qiskit.circuit.classicalfunction import BooleanExpression
    
    boolean_exp = BooleanExpression.from_dimacs_file("simple_v3_c2.cnf")
    circuit = QuantumCircuit(boolean_exp.num_qubits)
    circuit.append(boolean_exp, range(boolean_exp.num_qubits))
    circuit.draw("text")
    
    from qiskit.circuit.classicalfunction import classical_function
    from qiskit.circuit.classicalfunction.types import Int1
    
    @classical_function
    def grover_oracle(a: Int1, b: Int1, c: Int1) -> Int1:
        return (a and b and not c)
    
    quantum_circuit = grover_oracle.synth(registerless=False)
    print(quantum_circuit.draw())
    

    Which would print

         Before             After
    
         c: ──■──           a: ──■──
              │                  │
         b: ──■──           b: ──■──
              │                  │
         a: ──o──           c: ──o──
            ┌─┴─┐              ┌─┴─┐
    return: ┤ X ├      return: ┤ X ├
            └───┘              └───┘
    
  • Fixed plot_state_paulivec(), which previously damped the state coefficients by a factor of \(2^n\), where \(n\) is the number of qubits. Now the bar graph correctly displays the coefficients as \(\mathrm{Tr}(\sigma\rho)\), where \(\rho\) is the state to be plotted and \(\sigma\) iterates over all possible tensor products of single-qubit Paulis.

  • Angles in the OpenQASM 2 exporter (QuantumCircuit.qasm()) will now always include a decimal point, for example in the case of 1.e-5. This is required by a strict interpretation of the floating-point-literal specification in OpenQASM 2. Qiskit’s OpenQASM 2 parser (qasm2.load() and loads()) is more permissive by default, and will allow 1e-5 without the decimal point unless in strict mode.

  • The setter for SparsePauliOp.paulis will now correctly reject attempts to set the attribute with incorrectly shaped data, rather than silently allowing an invalid object to be created. See #10384.

  • Fixed a performance regression in the SabreLayout and SabreSwap transpiler passes. Fixed #10650

Qiskit 0.44.0#

This release officially marks the end of support for the Qiskit IBMQ Provider package and the removal of Qiskit Aer from the Qiskit metapackage. After this release the metapackage only contains Qiskit Terra, so this is the final release we will refer to the Qiskit metapackage and Qiskit Terra as separate things. Starting in the next release Qiskit 0.45.0 the Qiskit package will just be what was previously Qiskit Terra and there will no longer be a separation between them.

If you’re still using the qiskit-ibmq-provider package it has now been retired and is no longer supported. You should follow the links to the migration guides in the README for the package on how to switch over to the new replacement packages qiskit-ibm-provider, qiskit-ibm-runtime, and qiskit-ibm-experiment:

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

The Qiskit Aer project is still active and maintained moving forward it is just no longer included as part of the qiskit package. To continue using qiskit-aer you will need to explicitly install qiskit-aer and import the package from qiskit_aer.

As this is the final release of the Qiskit metapackage the following setuptools extras used to install optional dependencies will no longer work in the next release Qiskit 0.45.0:

  • nature

  • machine-learning

  • finance

  • optimization

  • experiments

If you’re using the extras to install any packages you should migrate to using the packages directly instead of the extra. For example if you were using pip install qiskit[experiments] previously you should switch to pip install qiskit qiskit-experiments to install both packages. Similarly the all extra (what gets installed via pip install "qiskit[all]") will no longer include these packages in Qiskit 0.45.0.

Terra 0.25.0#

Prelude#

The Qiskit Terra 0.25.0 release highlights are:

  • Control-flow operations are now supported through the transpiler at all optimization levels, including levels 2 and 3 (e.g. calling transpile() or generate_preset_pass_manager() with keyword argument optimization_level specified as 2 or 3 is now supported).

  • The fields IfElseOp.condition, WhileLoopOp.condition and SwitchCaseOp.target can now be instances of the new runtime classical-expression type expr.Expr. This is distinct from ParameterExpression because it is evaluated at runtime for backends that support such operations.

    These new expressions have significantly more power than the old two-tuple form of supplying classical conditions. For example, one can now represent equality constraints between two different classical registers, or the logic “or” of two classical bits. These two examples would look like:

    from qiskit.circuit import QuantumCircuit, ClassicalRegister, QuantumRegister
    from qiskit.circuit.classical import expr
    
    qr = QuantumRegister(4)
    cr1 = ClassicalRegister(2)
    cr2 = ClassicalRegister(2)
    qc = QuantumCircuit(qr, cr1, cr2)
    qc.h(0)
    qc.cx(0, 1)
    qc.h(2)
    qc.cx(2, 3)
    qc.measure([0, 1, 2, 3], [0, 1, 2, 3])
    
    # If the two registers are equal to each other.
    with qc.if_test(expr.equal(cr1, cr2)):
      qc.x(0)
    
    # While either of two bits are set.
    with qc.while_loop(expr.logic_or(cr1[0], cr1[1])):
      qc.reset(0)
      qc.reset(1)
      qc.measure([0, 1], cr1)
    

    For more examples, see the documentation for qiskit.circuit.classical.

    This feature is new for both Qiskit and the available quantum hardware that Qiskit works with. As the features are still being developed there are likely to be places where there are unexpected edge cases that will need some time to be worked out. If you encounter any issue around classical expression support or usage please open an issue with Qiskit or your hardware vendor.

    In this initial release, Qiskit has added the operations:

    These can act on Python integer and Boolean literals, or on ClassicalRegister and Clbit instances.

    All these classical expressions are fully supported through the Qiskit transpiler stack, through QPY serialisation (qiskit.qpy) and for export to OpenQASM 3 (qiskit.qasm3). Import from OpenQASM 3 is currently managed by a separate package (which is re-exposed via qiskit.qasm3), which we hope will be extended to match the new features in Qiskit.

  • The qiskit.algorithms module has been deprecated and will be removed in a future release. It has been superseded by a new standalone library qiskit-algorithms which can be found on PyPi or on Github here:

    https://github.com/qiskit-community/qiskit-algorithms

    The qiskit.algorithms module will continue to work as before and bug fixes will be made to it until its future removal, but active development of new features has moved to the new package. If you’re relying on qiskit.algorithms you should update your Python requirements to also include qiskit-algorithms and update the imports from qiskit.algorithms to qiskit_algorithms. Please note that this new package does not include already deprecated algorithms code, including opflow and QuantumInstance-based algorithms. If you have not yet migrated from QuantumInstance-based to primitives-based algorithms, you should follow the migration guidelines in https://qisk.it/algo_migration. The decision to migrate the algorithms module to a separate package was made to clarify the purpose Qiskit and make a distinction between the tools and libraries built on top of it.

Qiskit Terra 0.25 has dropped support for Python 3.7 following deprecation warnings started in Qiskit Terra 0.23. This is consistent with Python 3.7’s end-of-life on the 27th of June, 2023. To continue using Qiskit, you must upgrade to a more recent version of Python.

New Features#

  • The following features have been added in this release.

Transpiler Features#
  • Added two new options to BlockCollector.

    The first new option split_layers allows collected blocks to be split into sub-blocks over disjoint qubit subsets, i.e. into depth-1 sub-blocks.

    The second new option collect_from_back allows blocks to be greedily collected starting from the outputs of the circuit. This is important in combination with ALAP-scheduling passes where we may prefer to put gates in the later rather than earlier blocks.

  • Added new options split_layers and collect_from_back to CollectLinearFunctions and CollectCliffords transpiler passes.

    When split_layers is True, the collected blocks are split into into sub-blocks over disjoint qubit subsets, i.e. into depth-1 sub-blocks. Consider the following example:

    from qiskit.circuit import QuantumCircuit
    from qiskit.transpiler.passes import CollectLinearFunctions
    
    circuit = QuantumCircuit(5)
    circuit.cx(0, 2)
    circuit.cx(1, 4)
    circuit.cx(2, 0)
    circuit.cx(0, 3)
    circuit.swap(3, 2)
    circuit.swap(4, 1)
    
    # Collect all linear gates, without splitting into layers
    qct = CollectLinearFunctions(split_blocks=False, min_block_size=1, split_layers=False)(circuit)
    assert qct.count_ops()["linear_function"] == 1
    
    # Collect all linear gates, with splitting into layers
    qct = CollectLinearFunctions(split_blocks=False, min_block_size=1, split_layers=True)(circuit)
    assert qct.count_ops()["linear_function"] == 4
    

    The original circuit is linear. When collecting linear gates without splitting into layers, we should end up with a single linear function. However, when collecting linear gates and splitting into layers, we should end up with 4 linear functions.

    When collect_from_back is True, the blocks are greedily collected from the outputs towards the inputs of the circuit. Consider the following example:

    from qiskit.circuit import QuantumCircuit
    from qiskit.transpiler.passes import CollectLinearFunctions
    
    circuit = QuantumCircuit(3)
    circuit.cx(1, 2)
    circuit.cx(1, 0)
    circuit.h(2)
    circuit.swap(1, 2)
    
    # This combines the CX(1, 2) and CX(1, 0) gates into a single linear function
    qct = CollectLinearFunctions(collect_from_back=False)(circuit)
    
    # This combines the CX(1, 0) and SWAP(1, 2) gates into a single linear function
    qct = CollectLinearFunctions(collect_from_back=True)(circuit)
    

    The original circuit contains a Hadamard gate, so that the CX(1, 0) gate can be combined either with CX(1, 2) or with SWAP(1, 2), but not with both. When collect_from_back is False, the linear blocks are greedily collected from the start of the circuit, and thus CX(1, 0) is combined with CX(1, 2). When collect_from_back is True, the linear blocks are greedily collected from the end of the circuit, and thus CX(1, 0) is combined with SWAP(1, 2).

  • Added DAGCircuit.classical_predecessors() and DAGCircuit.classical_successors(), an alternative to selecting classical wires that doesn’t require accessing the inner graph of a DAG node directly. The following example illustrates the new functionality:

    from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
    from qiskit.converters import circuit_to_dag
    from qiskit.circuit.library import RZGate
    
    q = QuantumRegister(3, 'q')
    c = ClassicalRegister(3, 'c')
    circ = QuantumCircuit(q, c)
    circ.h(q[0])
    circ.cx(q[0], q[1])
    circ.measure(q[0], c[0])
    circ.rz(0.5, q[1]).c_if(c, 2)
    circ.measure(q[1], c[0])
    dag = circuit_to_dag(circ)
    
    rz_node = dag.op_nodes(RZGate)[0]
    # Contains the "measure" on clbit 0, and the "wire start" nodes for clbits 1 and 2.
    classical_predecessors = list(dag.classical_predecessors(rz_node))
    # Contains the "measure" on clbit 0, and the "wire end" nodes for clbits 1 and 2.
    classical_successors = list(dag.classical_successors(rz_node))
    
  • Added DAGCircuit.quantum_causal_cone() to obtain the causal cone of a qubit in a DAGCircuit. The following example shows its correct usage:

    from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
    from qiskit.circuit.library import CXGate, CZGate
    from qiskit.dagcircuit import DAGCircuit
    
    # Build a DAGCircuit
    dag = DAGCircuit()
    qreg = QuantumRegister(5)
    creg = ClassicalRegister(5)
    dag.add_qreg(qreg)
    dag.add_creg(creg)
    dag.apply_operation_back(CXGate(), qreg[[1, 2]], [])
    dag.apply_operation_back(CXGate(), qreg[[0, 3]], [])
    dag.apply_operation_back(CZGate(), qreg[[1, 4]], [])
    dag.apply_operation_back(CZGate(), qreg[[2, 4]], [])
    dag.apply_operation_back(CXGate(), qreg[[3, 4]], [])
    
    # Get the causal cone of qubit at index 0
    result = dag.quantum_causal_cone(qreg[0])
    
  • A new method find_bit() has been added to the DAGCircuit class, which returns the bit locations of the given Qubit or Clbit as a tuple of the positional index of the bit within the circuit and a list of tuples which locate the bit in the circuit’s registers.

  • The transpiler’s built-in EquivalenceLibrary (qiskit.circuit.equivalence_library.SessionEquivalenceLibrary) has been taught the circular Pauli relations \(X = iYZ\), \(Y = iZX\) and \(Z = iXY\). This should make transpiling to constrained, and potentially incomplete, basis sets more reliable. See #10293 for more detail.

  • Control-flow operations are now supported through the transpiler at all optimization levels, including levels 2 and 3 (e.g. calling transpile() or generate_preset_pass_manager() with keyword argument optimization_level=3).

  • DAGCircuit.substitute_node() gained a propagate_condition keyword argument that is analogous to the same argument in substitute_node_with_dag(). Setting this to False opts out of the legacy behaviour of copying a condition on the node onto the new op that is replacing it.

    This option is ignored for general control-flow operations, which will never propagate their condition, nor accept a condition from another node.

  • Introduced a new method, DAGCircuit.separable_circuits(), which returns a list of DAGCircuit objects, one for each set of connected qubits which have no gates connecting them to another set.

    Each DAGCircuit instance returned by this method will contain the same number of clbits as self. This method will not return DAGCircuit instances consisting solely of clbits.

  • Added the attribute Target.concurrent_measurements which represents a hardware constraint of qubits measured concurrently. This constraint is provided in a nested list form, in which each element represents a qubit group to be measured together. In an example below:

    [[0, 1], [2, 3, 4]]
    

    qubits 0 and 1, and 2, 3 and 4 are measured together on the device. This constraint doesn’t block measuring an individual qubit, but you may need to consider the alignment of measure operations for these qubits when working with the Qiskit Pulse scheduler and when authoring new transpiler passes that are timing-aware (i.e. passes that perform scheduling).

  • The transpiler pass SetLayout can now be constructed with a list of integers that represent the physical qubits on which the quantum circuit will be mapped on. That is, the first qubit in the circuit will be allocated to the physical qubit in position zero of the list, and so on.

  • The transpiler’s built-in EquivalenceLibrary has been taught more Pauli-rotation equivalences between the one-qubit \(R_X\), \(R_Y\) and \(R_Z\) gates, and between the two-qubit \(R_{XX}\), \(R_{YY}\) and \(R_{ZZ}\) gates. This should make simple basis translations more reliable, especially circuits that use \(Y\) rotations. See #7332.

  • Control-flow operations are now supported by the Sabre family of transpiler passes, namely layout pass SabreLayout and routing pass SabreSwap. Function transpile() keyword arguments layout_method and routing_method now accept the option "sabre" for circuits with control flow, which was previously unsupported.

Circuits Features#
  • The fields IfElseOp.condition, WhileLoopOp.condition and SwitchCaseOp.target can now be instances of the new runtime classical-expression type expr.Expr. This is distinct from ParameterExpression because it is evaluated at runtime for backends that support such operations.

    These new expressions have significantly more power than the old two-tuple form of supplying classical conditions. For example, one can now represent equality constraints between two different classical registers, or the logic “or” of two classical bits. These two examples would look like:

    from qiskit.circuit import QuantumCircuit, ClassicalRegister, QuantumRegister
    from qiskit.circuit.classical import expr
    
    qr = QuantumRegister(4)
    cr1 = ClassicalRegister(2)
    cr2 = ClassicalRegister(2)
    qc = QuantumCircuit(qr, cr1, cr2)
    qc.h(0)
    qc.cx(0, 1)
    qc.h(2)
    qc.cx(2, 3)
    qc.measure([0, 1, 2, 3], [0, 1, 2, 3])
    
    # If the two registers are equal to each other.
    with qc.if_test(expr.equal(cr1, cr2)):
      qc.x(0)
    
    # While either of two bits are set.
    with qc.while_loop(expr.logic_or(cr1[0], cr1[1])):
      qc.reset(0)
      qc.reset(1)
      qc.measure([0, 1], cr1)
    

    For more examples, see the documentation for qiskit.circuit.classical.

    This feature is new for both Qiskit and the available quantum hardware that Qiskit works with. As the features are still being developed there are likely to be places where there are unexpected edge cases that will need some time to be worked out. If you encounter any issue around classical expression support or usage please open an issue with Qiskit or your hardware vendor.

    In this initial release, Qiskit has added the operations:

    These can act on Python integer and Boolean literals, or on ClassicalRegister and Clbit instances.

    All these classical expressions are fully supported through the Qiskit transpiler stack, through QPY serialisation (qiskit.qpy) and for export to OpenQASM 3 (qiskit.qasm3). Import from OpenQASM 3 is currently managed by a separate package (which is re-exposed via qiskit.qasm3), which we hope will be extended to match the new features in Qiskit.

  • Tooling for working with the new representations of classical runtime expressions has been added. A general ExprVisitor is provided for consumers of these expressions to subclass. Two utilities based on this structure, iter_vars() and structurally_equivalent(), are also provided, which respectively produce an iterator through the Var nodes and check whether two Expr instances are structurally the same, up to some mapping of the Var nodes contained.

  • Added function lift_legacy_condition() which can be used to convert old-style conditions into new-style Expr nodes. Note that these expression nodes are not permitted in old-style Instruction.condition fields, which are due to be replaced by more advanced classical handling such as IfElseOp.

  • Added support for taking absolute values of ParameterExpressions. For example, the following is now possible:

    from qiskit.circuit import QuantumCircuit, Parameter
    
    x = Parameter("x")
    circuit = QuantumCircuit(1)
    circuit.rx(abs(x), 0)
    
    bound = circuit.bind_parameters({x: -1})
    
  • The method QuantumCircuit.assign_parameters() has gained two new keywords arguments: flat_input and strict. These are advanced options that can be used to speed up the method when passing the parameter bindings as a dictionary; flat_input=True is a guarantee that the dictionary keys contain only Parameter instances (not ParameterVectors), and strict=False allows the dictionary to contain parameters that are not present in the circuit. Using these two options can reduce the overhead of input normalisation in this function.

  • Added support for constructing LinearFunctions from more general quantum circuits, that may contain:

    • Barriers (of type Barrier) and delays (Delay), which are simply ignored

    • Permutations (of type PermutationGate)

    • Other linear functions

    • Cliffords (of type Clifford), when the Clifford represents a linear function (and a CircuitError exception is raised if not)

    • Nested quantum circuits of this form

  • Added LinearFunction.__eq__() method. Two objects of type LinearFunction are considered equal when their representations as binary invertible matrices are equal.

  • Added LinearFunction.extend_with_identity() method, which allows to extend a linear function over k qubits to a linear function over n >= k qubits, specifying the new positions of the original qubits and padding with identities on the remaining qubits.

  • The instructions StatePreparation and Initialize, and their associated circuit methods QuantumCircuit.prepare_state() and initialize(), gained a keyword argument normalize, which can be set to True to automatically normalize an array target. By default this is False, which retains the current behaviour of raising an exception when given non-normalized input.

Algorithms Features#
  • Added the option to pass a callback to the UMDA optimizer, which allows keeping track of the number of function evaluations, the current parameters, and the best achieved function value.

OpenQASM Features#
  • The OpenQASM 3 exporters (qasm3.dump(), dumps() and Exporter) have a new allow_aliasing argument, which will eventually replace the alias_classical_registers argument. This controls whether aliasing is permitted for either classical bits or qubits, rather than the option only being available for classical bits.

Quantum Information Features#
  • Added a new function negativity() that calculates the entanglement measure of negativity of a quantum state. Example usage of the above function is given below:

    from qiskit.quantum_info.states.densitymatrix import DensityMatrix
    from qiskit.quantum_info.states.statevector import Statevector
    from qiskit.quantum_info import negativity
    import numpy as np
    
    # Constructing a two-qubit bell state vector
    state = np.array([0, 1/np.sqrt(2), -1/np.sqrt(2), 0])
    # Calculating negativity of statevector
    negv = negativity(Statevector(state), [1])
    
    # Creating the Density Matrix (DM)
    rho = DensityMatrix.from_label("10+")
    # Calculating negativity of DM
    negv2 = negativity(rho, [0, 1])
    
  • Adds support for multiplication of SparsePauliOp objects with Parameter objects by using the * operator, for example:

    from qiskit.circuit import Parameter
    from qiskit.quantum_info import SparsePauliOp
    
    param = Parameter("a")
    op = SparsePauliOp("X")
    param * op
    
Pulse Features#
  • The method filter() is activated in the ScheduleBlock class. This method enables users to retain only Instruction objects which pass through all the provided filters. As builtin filter conditions, pulse Channel subclass instance and Instruction subclass type can be specified. User-defined callbacks taking Instruction instance can be added to the filters, too.

  • The method exclude() is activated in the ScheduleBlock class. This method enables users to retain only Instruction objects which do not pass at least one of all the provided filters. As builtin filter conditions, pulse Channel subclass instance and Instruction subclass type can be specified. User-defined callbacks taking Instruction instance can be added to the filters, too. This method is the complement of filter(), so the following condition is always satisfied: block.filter(*filters) + block.exclude(*filters) == block in terms of instructions included, where block is a ScheduleBlock instance.

  • Added a new function gaussian_square_echo() to the pulse library. The returned pulse is composed of three GaussianSquare pulses. The first two are echo pulses with duration half of the total duration and implement rotary tones. The third pulse is a cancellation tone that lasts the full duration of the pulse and implements correcting single qubit rotations.

  • QPY supports the Discriminator and Kernel objects. This feature enables users to serialize and deserialize the Acquire instructions with these objects using QPY.

Synthesis Features#
  • Added a new synthesis function synth_cx_cz_depth_line_my() which produces the circuit form of a CX circuit followed by a CZ circuit for linear nearest neighbor (LNN) connectivity in 2-qubit depth of at most 5n, using CX and phase gates (S, Sdg or Z). The synthesis algorithm is based on the paper of Maslov and Yang, arXiv:2210.16195.

    The algorithm accepts a binary invertible matrix mat_x representing the CX-circuit, a binary symmetric matrix mat_z representing the CZ-circuit, and returns a quantum circuit with 2-qubit depth of at most 5n computing the composition of the CX and CZ circuits. The following example illustrates the new functionality:

    import numpy as np
    from qiskit.synthesis.linear_phase import synth_cx_cz_depth_line_my
    mat_x = np.array([[0, 1], [1, 1]])
    mat_z = np.array([[0, 1], [1, 0]])
    qc = synth_cx_cz_depth_line_my(mat_x, mat_z)
    

    This function is now used by default in the Clifford synthesis algorithm synth_clifford_depth_lnn() that optimizes 2-qubit depth for LNN connectivity, improving the 2-qubit depth from 9n+4 to 7n+2. The clifford synthesis algorithm can be used as follows:

    from qiskit.quantum_info import random_clifford
    from qiskit.synthesis import synth_clifford_depth_lnn
    
    cliff = random_clifford(3)
    qc = synth_clifford_depth_lnn(cliff)
    

    The above synthesis can be further improved as described in the paper by Maslov and Yang, using local optimization between 2-qubit layers. This improvement is left for follow-up work.

Visualization Features#
  • QuantumCircuit.draw() and function circuit_drawer() when using option output='mpl' now support drawing the nested circuit blocks of ControlFlowOp operations, including if, else, while, for, and switch/case. Circuit blocks are wrapped with boxes to delineate the circuits.

  • Some restrictions when using wire_order in the circuit drawers have been relaxed. Now, wire_order can list just qubits and, in that case, it can be used with cregbundle=True, since it will not affect the classical bits.

    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('text', wire_order=[2, 3, 0, 1], cregbundle=True)
    
     q_2: ────────────
          ┌───┐ ┌───┐
     q_3: ┤ H ├─┤ X ├─
          ├───┤ └─╥─┘
     q_0: ┤ H ├───╫───
          ├───┤   ║
     q_1: ┤ X ├───╫───
          └───┘┌──╨──┐
     c: 4/═════╡ 0xa ╞
               └─────┘
    ca: 2/════════════
    
Misc. Features#
  • The magic %qiskit_version_table from qiskit.tools.jupyter now includes all imported modules with qiskit in their name.

Upgrade Notes#

  • Qiskit Terra 0.25 has dropped support for Python 3.7 following deprecation warnings started in Qiskit Terra 0.23. This is consistent with Python 3.7’s end-of-life on the 27th of June, 2023. To continue using Qiskit, you must upgrade to a more recent version of Python.

  • Qiskit Terra 0.25 now requires versison 0.13.0 of rustworkx.

  • By default Qiskit builds its compiled extensions using the Python Stable ABI with support back to the oldest version of Python supported by Qiskit (currently 3.8). This means that moving forward there will be a single precompiled wheel that is shipped on release that works with all of Qiskit’s supported Python versions. There isn’t any expected runtime performance difference using the limited API so it is enabled by default for all builds now. Previously, the compiled extensions were built using the version specific API and would only work with a single Python version. This change was made to reduce the number of package files we need to build and publish in each release. When building Qiskit from source, there should be no changes necessary to the build process except that the default tags in the output filenames will be different to reflect the use of the limited API.

Transpiler Upgrade Notes#
  • Support for passing in lists of argument values to the transpile() function is removed. This functionality was deprecated as part of the 0.23.0 release. You are still able to pass in a list of QuantumCircuit objects for the first positional argument. What has been removed is list broadcasting of the other arguments to each circuit in that input list. Removing this functionality was necessary to greatly reduce 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 now run 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, coupling_map=cm) for cm in cmap]
    

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

Circuits Upgrade Notes#
  • The OpenQASM 2 constructor methods on QuantumCircuit (from_qasm_str() and from_qasm_file()) have been switched to use the Rust-based parser added in Qiskit Terra 0.24. This should result in significantly faster parsing times (10 times or more is not uncommon) and massively reduced intermediate memory usage.

    The QuantumCircuit methods are kept with the same interface for continuity; the preferred way to access the OpenQASM 2 importer is to use qasm2.load() and qasm2.loads(), which offer an expanded interface to control the parsing and construction.

  • The deprecated circuit_cregs argument to the constructor for the InstructionSet class has been removed. It was deprecated in the 0.19.0 release. If you were using this argument and manually constructing an InstructionSet object (which should be quite uncommon as it’s mostly used internally) you should pass a callable to the resource_requester keyword argument instead. For example:

    from qiskit.circuit import Clbit, ClassicalRegister, InstructionSet
    from qiskit.circuit.exceptions import CircuitError
    
    def my_requester(bits, registers):
        bits_set = set(bits)
        bits_flat = tuple(bits)
        registers_set = set(registers)
    
        def requester(specifier):
            if isinstance(specifer, Clbit) and specifier in bits_set:
                return specifier
            if isinstance(specifer, ClassicalRegster) and specifier in register_set:
                return specifier
            if isinstance(specifier, int) and 0 <= specifier < len(bits_flat):
                return bits_flat[specifier]
            raise CircuitError(f"Unknown resource: {specifier}")
    
        return requester
    
    my_bits = [Clbit() for _ in [None]*5]
    my_registers = [ClassicalRegister(n) for n in range(3)]
    
    InstructionSet(resource_requester=my_requester(my_bits, my_registers))
    
OpenQASM Upgrade Notes#
  • The OpenQASM 2 constructor methods on QuantumCircuit (from_qasm_str() and from_qasm_file()) have been switched to use the Rust-based parser added in Qiskit Terra 0.24. This should result in significantly faster parsing times (10 times or more is not uncommon) and massively reduced intermediate memory usage.

    The QuantumCircuit methods are kept with the same interface for continuity; the preferred way to access the OpenQASM 2 importer is to use qasm2.load() and qasm2.loads(), which offer an expanded interface to control the parsing and construction.

  • The OpenQASM 3 exporters (qasm3.dump(), dumps() and Exporter) will now use fewer “register alias” definitions in its output. The circuit described will not change, but it will now preferentially export in terms of direct bit, qubit and qubit[n] types rather than producing a _loose_bits register and aliasing more registers off this. This is done to minimise the number of advanced OpenQASM 3 features in use, and to avoid introducing unnecessary array structure into programmes that do not require it.

Quantum Information Upgrade Notes#
  • Clifford.from_circuit() will no longer attempt to resolve instructions whose definition fields are mutually recursive with some other object. Such recursive definitions are already a violation of the strictly hierarchical ordering that the definition field requires, and code should not rely on this being possible at all. If you want to define equivalences that are permitted to have (mutual) cycles, use an EquivalenceLibrary.

Visualization Upgrade Notes#
  • In the internal ~qiskit.visualization.circuit.matplotlib.MatplotlibDrawer object, the arguments layout, global_phase, qregs and cregs have been removed. They were originally deprecated in Qiskit Terra 0.20. These objects are simply inferred from the given circuit now.

    This is an internal worker class of the visualization routines. It is unlikely you will need to change any of your code.

Misc. Upgrade Notes#
  • The qiskit.util import location has been removed, as it had been deprecated since Qiskit Terra 0.17. Users should use the new import location, qiskit.utils.

Deprecation Notes#

  • Extensions of the qiskit and qiskit.providers namespaces by external packages are now deprecated and the hook points enabling this will be removed in a future release. In the past, the Qiskit project was composed of elements that extended a shared namespace and these hook points enabled doing that. However, it was not intended for these interfaces to ever be used by other packages. Now that the overall Qiskit package is no longer using that packaging model, leaving the possibility for these extensions carry more risk than benefits and is therefore being deprecated for future removal. If you’re maintaining a package that extends the Qiskit namespace (i.e. your users import from qiskit.x or qiskit.providers.y) you should transition to using a standalone Python namespace for your package. No warning will be raised as part of this because there is no method to inject a warning at the packaging level that would be required to warn external packages of this change.

  • The dictionary qiskit.__qiskit_version__ is deprecated, as Qiskit is defined with a single package (qiskit-terra). In the future, qiskit.__version__ will be the single point to query the Qiskit version, as a standard string.

Transpiler Deprecations#
  • The function get_vf2_call_limit available via the module qiskit.transpiler.preset_passmanagers.common has been deprecated. This will likely affect very few users since this function was neither explicitly exported nor documented. Its functionality has been replaced and extended by a function in the same module.

Circuits Deprecations#
  • The method qasm() and all overriding methods of subclasses of :class:~qiskit.circuit.Instruction are deprecated. There is no replacement for generating an OpenQASM2 string for an isolated instruction as typically a single instruction object has insufficient context to completely generate a valid OpenQASM2 string. If you’re relying on this method currently you’ll have to instead rely on the OpenQASM2 exporter: QuantumCircuit.qasm() to generate the OpenQASM2 for an entire circuit object.

Algorithms Deprecations#
  • The qiskit.algorithms module has been deprecated and will be removed in a future release. It has been superseded by a new standalone library qiskit-algorithms which can be found on PyPi or on Github here:

    https://github.com/qiskit-community/qiskit-algorithms

    The qiskit.algorithms module will continue to work as before and bug fixes will be made to it until its future removal, but active development of new features has moved to the new package. If you’re relying on qiskit.algorithms you should update your Python requirements to also include qiskit-algorithms and update the imports from qiskit.algorithms to qiskit_algorithms. Please note that this new package does not include already deprecated algorithms code, including opflow and QuantumInstance-based algorithms. If you have not yet migrated from QuantumInstance-based to primitives-based algorithms, you should follow the migration guidelines in https://qisk.it/algo_migration. The decision to migrate the algorithms module to a separate package was made to clarify the purpose Qiskit and make a distinction between the tools and libraries built on top of it.

Pulse Deprecations#
  • Initializing a ScalableSymbolicPulse with complex value for amp. This change also affects the following library pulses:

    Initializing amp for these with a complex value is now deprecated as well.

    Instead, use two floats when specifying the amp and angle parameters, where amp represents the magnitude of the complex amplitude, and angle represents the angle of the complex amplitude. i.e. the complex amplitude is given by \(\texttt{amp} \times \exp(i \times \texttt{angle})\).

  • The Call instruction has been deprecated and will be removed in a future release. Instead, use function call() from module qiskit.pulse.builder within an active building context.

Misc. Deprecations#
  • The Jupyter magic %circuit_library_info and the objects in qiskit.tools.jupyter.library it calls in turn:

    • circuit_data_table

    • properties_widget

    • qasm_widget

    • circuit_digram_widget

    • circuit_library_widget

    are deprecated and will be removed in a future release. These objects were only intended for use in the documentation build. They are no longer used there, so are no longer supported or maintained.

Known Issues#

  • Circuits containing classical expressions made with the expr module are not yet supported by the circuit visualizers.

Bug Fixes#

  • Fixed a bug in Channel where index validation was done incorrectly and only raised an error when the index was both non-integer and negative, instead of either.

  • Fixed an issue with the transpile() function and all the preset pass managers generated via generate_preset_pass_manager() where the output QuantumCircuit object’s layout attribute would have an invalid TranspileLayout.final_layout attribute. This would occur in scenarios when the VF2PostLayout pass would run and find an alternative initial layout that has lower reported error rates. When altering the initial layout the final_layout attribute was never updated to reflect this change. This has been corrected so that the final_layout is always correctly reflecting the output permutation caused by the routing stage. Fixed #10457

  • The OpenQASM 2 parser (qasm2.load() and loads()) running in strict mode will now correctly emit an error if a barrier statement has no arguments. When running in the (default) more permissive mode, an argument-less barrier statement will continue to cause a barrier on all qubits currently in scope (the qubits a gate definition affects, or all the qubits defined by a program, if the statement is in a gate body or in the global scope, respectively).

  • The OpenQASM 2 exporter (QuantumCircuit.qasm()) will now no longer attempt to output barrier statements that act on no qubits. Such a barrier statement has no effect in Qiskit either, but is invalid OpenQASM 2.

  • Qiskit can represent custom instructions that act on zero qubits, or on a non-zero number of classical bits. These cannot be exported to OpenQASM 2, but previously QuantumCircuit.qasm() would try, and output invalid OpenQASM 2. Instead, a QASM2ExportError will now correctly be raised. See #7351 and #10435.

  • A parametrised circuit that contains a custom gate whose definition has a parametrised global phase can now successfully bind the parameter in the inner global phase. See #10283 for more detail.

  • Construction of a Statevector from a QuantumCircuit containing zero-qubit operations will no longer raise an error. These operations impart a global phase on the resulting statevector.

  • The control-flow builder interface will now correctly include ClassicalRegister resources from nested switch statements in their containing circuit scopes. See #10398.

  • Fixed an issue in QuantumCircuit.decompose() where passing a circuit name to the function that matched a composite gate name would not decompose the gate if it had a label assigned to it as well. Fixed #9136

  • When the parameter conditional=True is specified in random_circuit(), conditional operations in the resulting circuit will now be preceded by a full mid-circuit measurment. Fixes #9016

  • Reduced overhead of the ConsolidateBlocks pass by performing matrix operations on all two-qubit blocks instead of creating an instance of QuantumCircuit and passing it to an Operator. The speedup will only be applicable when consolidating two-qubit blocks. Anything higher than that will still be handled by the Operator class. Check #8779 for details.

  • The OpenQASM 3 exporter (qiskit.qasm3) will no longer output invalid OpenQASM 3 for non-unitary Instruction instances, but will instead raise a QASM3ExporterError explaining that these are not yet supported. This feature is slated for a later release of Qiskit, when there are more classical-processing facilities throughout the library.

  • Fixed an issue with function state_to_latex(). Previously, it produced invalid LaTeX with unintended coefficient rounding, which resulted in errors when calling state_drawer(). Fixed #9297.

Qiskit 0.43.3#

Terra 0.24.2#

Prelude#

Qiskit Terra 0.24.2 is a bugfix release, addressing some minor issues identified since the 0.24.1 release.

Upgrade Notes#

  • The QPY format version emitted by dump has increased to 8. This new format version adds support for serializing the QuantumCircuit.layout attribute.

Bug Fixes#

  • Fixed the deserialization of DiagonalGate instances through QPY. Fixed #10364

  • Fixed an issue with the qs_decomposition() function, which does quantum Shannon decomposition, when it was called on trivial numeric unitaries that do not benefit from this decomposition, an unexpected error was raised. This error has been fixed so that such unitaries are detected and the equivalent circuit is returned. Fixed #10036

  • Fixed an issue in the the BasicSwap class that prevented the BasicSwap.run() method from functioning if the fake_run keyword argument was set to True when the class was instantiated. Fixed #10147

  • Fixed an issue with copying circuits with new-style Clbits and Qubits (bits without registers) where references to these bits from the containing circuit could be broken, causing issues with serialization and circuit visualization. Fixed #10409

  • The CheckMap transpiler pass will no longer spuriously error when dealing with nested conditional structures created by the control-flow builder interface. See #10394.

  • Importing qiskit.primitives will no longer cause deprecation warnings stemming from the deprecated qiskit.opflow module. These warnings would have been hidden to users by the default Python filters, but triggered the eager import of opflow, which meant that a subsequent import by a user would not trigger the warnings. Fixed #10245

  • Fixed the OpenQASM 2 output of QuantumCircuit.qasm() when a custom gate object contained a gate with the same name. Ideally this shouldn’t happen for most gates, but complex algorithmic operations like the GroverOperator class could produce such structures accidentally. See #10162.

  • Fixed a regression in the LaTeX drawer of QuantumCircuit.draw() when temporary files are placed on a separate filesystem to the working directory. See #10211.

  • Fixed an issue with UnitarySynthesis when using the target parameter where circuits with control flow were not properly mapped to the target.

  • Fixed bug in VQD where result.optimal_values was a copy of result.optimal_points. It now returns the corresponding values. Fixed #10263

  • Improved the error messages returned when an attempt to convert a fully bound ParameterExpression into a concrete float or int failed, for example because the expression was naturally a complex number. Fixed #9187

  • Fixed float conversions for ParameterExpression values which had, at some point in their construction history, an imaginary component that had subsequently been cancelled. When using Sympy as a backend, these conversions would usually already have worked. When using Symengine as the backend, these conversions would often fail with type errors, despite the result having been symbolically evaluated to be real, and ParameterExpression.is_real() being true. Fixed #10191

Aer 0.12.2#

Prelude#

Qiskit Aer 0.12.2 is the second patch release to 0.12.0. This fixes some bugs that have been discovered since the release of 0.12.1.

Upgrade Notes#

  • Qiskit Aer now requires CUDA version for GPU simulator to 11.2 or higher. Previously, CUDA 10.1 was the minimum supported version. This change was necessary because of changes in the upstream CUDA ecosystem, including cuQuantum support. To support users running with different versions of CUDA there is now a separate package available for running with CUDA 11: qiskit-aer-gpu-cu11 and using the qiskit-aer-gpu package now requires CUDA 12. If you’re an existing user of the qiskit-aer-gpu package and want to use CUDA 11 you will need to run:

    pip uninstall qiskit-aer-gpu && pip install -U qiskit-aer-gpu-cu11
    

    to go from the previously CUDA 10.x compatible qiskit-aer-gpu package’s releases to upgrade to the new CUDA 11 compatible package. If you’re running CUDA 12 locally already you can upgrade the qiskit-aer-gpu package as normal.

Bug Fixes#

  • If a circuit has conditional and parameters, the circuit was not be correctly simulated because parameter bindings of Aer used wrong positions to apply parameters. This is from a lack of consideration of bfunc operations injected by conditional. With this commit, parameters are set to correct positions with consideration of injected bfun operations.

  • Parameters for global phases were not correctly set in #1814. https://github.com/Qiskit/qiskit-aer/pull/1814 Parameter values for global phases were copied to a template circuit and not to actual circuits to be simulated. This commit correctly copies parameter values to circuits to be simulated.

  • Results of backend.run() were not serializable because they include AerCircuits. This commit makes the results serializable by removing AerCircuits from metadata.

  • :meth:QuantumCircuit.save_statevector() does not work if the circuit is generated from OpenQASM3 text because its quantum registers have duplicated qubit instances. With this commit, :meth:QuantumCircuit.save_statevector() uses :data:QuantumCircuit.qubits to get qubits to be saved.

IBM Q Provider 0.20.2#

No change.

Qiskit 0.43.2#

As a reminder, Qiskit Aer’s inclusion in the qiskit package is deprecated. The next minor version of Qiskit Aer (0.13) will not be included in any release of the qiskit package, and you should immediately begin installing Aer separately by:

pip install qiskit-aer

and importing it as:

import qiskit_aer

Starting from Qiskit 0.44, the command pip install qiskit will no longer install Qiskit Aer, or the obsolete IBM Q Provider that has already been replaced by the new IBM Provider <https://qiskit.org/ecosystem/ibm-provider/>__.

Terra 0.24.1#

No change

Aer 0.12.1#

Prelude#

Qiskit Aer 0.12.1 is the first patch release to 0.12.0. This fixes some bugs that have been discovered since the release of 0.12.0.

Known Issues#

  • Fix a bug that returns wrong expectation values in Estimator when abelian_grouping=True.

Upgrade Notes#

  • Improved performance when the same circuits and multiple parameters are passed to Estimator with approximation=True.

Deprecation Notes#

  • Options of meth:~.AerSimulator.run need to use correct types.

Bug Fixes#

  • Performance regression due to introduction of AER::Config is fixed. This class has many fields but is frequently copied in AER::Transpile::CircuitOptimization. Originally json_t (former class for configuration) was also frequently copied but it does have entries in most cases and then this copy overhead is not a problem. With this fix, AER::Transpile::CircuitOptimization does not copy AER::Config.

  • When BLAS calls are failed, because omp threads do not handle exceptions, Aer crashes without any error messages. This fix is for omp threads to catch exceptions correctly and then rethrow them outside of omp loops.

  • Previously, parameters for gates are not validate in C++. If parameters are shorter than expected (due to custom gate), segmentaion faults are thrown. This commit adds checks whether parameter lenght is expceted. This commit will fix issues reported in #1612. https://github.com/Qiskit/qiskit-aer/issues/1612

  • Since 0.12.0, parameter values in circuits are temporarily replaced with constant values and parameter values are assigned in C++ library. Therefore, if parameter_binds is specified, simulator returns results with the constnat values as paramter values. With this commit, Aer raises an error if parameter_binds is not specified though circuits have parameters.

  • Available devices and methods are no longer queried when importing Aer.

  • Previously AerSimulator modifies circuit metadata to maintain consistency between input and output of simulation with side effect of unexpected view of metadata from applicatiln in simiulation. This fix avoids using circuit metadata to maintain consistency internaly and then always provides consistent view of metadata to application.

  • Fixed a bug where the variance in metadata in EstimatorResult was complex and now returns float.

  • Fixed a build break to compile Qiskit Aer with cuQuautum support (AER_ENABLE_CUQUANTUM=true). This change does not affect build for CPU and normal GPU binaries.

  • Fixed a bug in from_backend() that raised an error when the backend has no T1 and T2 values (i.e. None) for a qubit in its qubit properties. This commit updates NoiseModel.from_backend() and basic_device_gate_errors() so that they add an identity QuantumError (i.e. effectively no thermal relaxation error) to a qubit with no T1 and T2 values for all gates acting on qubits including the qubit. Fixed #1779 and #1815.

  • Fix an issue even if the number of qubits is set by a coupling map or device’s configuration, when the simulation method is configured, the number of qubits is overwritten in accordance with the method. Fixed #1769

  • This is fix for library path setting in CMakeLists.txt for cuQuantum SDK. Because the latest cuQuantum includes libraries for CUDA 11.x and 12.x, this fix uses CUDA version returned from FindCUDA to the path of libraries of cuQuantum and cuTENSOR.

  • This is fix for static link libraries of cuQuantum when building with CUQUANTUM_STATIC=true.

  • MPI parallelization was not enabled since we have not used qobj. This fix sets the number of processes and MPI rank correctly.

  • AerCircuit is created from a circuit by iterating its operations while skipping barrier instructions. However, skipping barrier instructions make wrong positionings of parameter bindings. This fix adds barrier() and keeps parametr bindings correct.

  • Aer still supports Qobj as an argument of run() though it was deprecated. However, since 0.12.0, it always fails if no run_options is specified. This fix enables simulation of Qobj without run_options.

  • Since 0.12.0, AerConfig is used for simulation configuration while performing strict type checking for arguments of meth:~.AerSimulator.run. This commit adds casting if argument types are not expected.

  • :meth:QuantumCircuit.initialize() with int value was not processed correctly as reported in #1821 <https://github.com/Qiskit/qiskit-aer/issues/1821>. This commit enables such initialization by decomposing initialize instructions.

  • Aer will now use omp_set_max_active_levels() instead of the deprecated omp_set_nested() when compiled against recent versions of OpenMP.

IBM Q Provider 0.20.2#

No change.

Qiskit 0.43.1#

Terra 0.24.1#

Prelude#

Qiskit Terra 0.24.1 is the first patch release to 0.24.0. This fixes some bugs that have been discovered since the release of 0.24.0.

Upgrade Notes#

Bug Fixes#

  • Fixed a bug in BlockCollapser where classical bits were ignored when collapsing a block of nodes.

  • Fixed a bug in QuantumCircuit.compose() where the SwitchCaseOp.target attribute in the subcircuit was not correctly mapped to a register in the base circuit.

  • Fix a bug in RZXCalibrationBuilder where calling calibration with wrong parameters would crash instead of raising an exception.

  • Using initial_layout in calls to transpile() will no longer error if the circuit contains qubits not in any registers, or qubits that exist in more than one register. See #10125.

  • Fixes a bug introduced in Qiskit 0.24.0 where numeric rotation angles were no longer substituted for symbolic ones before preparing for two-qubit synthesis. This caused an exception to be raised because the synthesis routines require numberic matrices.

  • Fix a bug in the VF2Layout and VF2PostLayout passes where the passes were failing to account for the 1 qubit error component when evaluating a potential layout.

Aer 0.12.0#

No change

IBM Q Provider 0.20.2#

No change

Qiskit 0.43.0#

Terra 0.24.0#

Prelude#

This is a major feature release that includes numerous new features and bugfixes.

This release is the final release with support for running Qiskit with Python 3.7. Starting in the next minor version release Python >=3.8 will be required to run Qiskit.

The highlights of this release:

QuantumInstance, OpFlow, and algorithms usage deprecation#

This release officially deprecates the QuantumInstance class (and its associated helper methods and classes), the qiskit.opflow module, and any usage of those in qiskit.algorithms. This deprecation comes from a long thread of work that started in Qiskit Terra 0.21.0 to refactor the qiskit.algorithms module to be based on the computational primitives. There are associated migration guides for any existing users to migrate to the new workflow:

OpenQASM2 improvements#

This release includes a major refactoring for the OpenQASM 2.0 support in Qiskit. The first change is the introduction of a new parser for OpenQASM 2.0 in the qiskit.qasm2 module. This new module replaces the existing qiskit.qasm module. The new parser is more explicit and correct with respect to the language specification. It is also implemented in Rust and is significantly faster than the previous parser. Paired with the new parser the OpenQASM 2.0 exporter underwent a large refactor that improved the correctness of the output when using the QuantumCircuit.qasm() method to generate QASM output from a QuantumCircuit object.

Transpiler support for devices with disjoint connectivity#

The transpiler now supports targeting backends with disjoint connectivity. Previously, the transpiler only supported backends which were fully connected (where there is a path to run operations between all pairs of qubits in the backend). Now, if a backend has disconnected connectivity the transpiler is able to reason about how to apply layout (Layout Stage) and routing (Routing Stage) for the backend. If the input circuit is not able to be executed on the hardware given the lack of connectivity between connected components, a descriptive error will be returned.

For example, the Heron device outlined in IBM Quantum’s hardware roadmap describes a future backend which will have shared control hardware and real-time classical communication between separate quantum processors. This support enables the Target to accurately model these types of future devices or other hardware with similar constraints.

Switch Operation#

This release adds a new control flow operation, the switch statement. This is implemented using a new operation class SwitchCaseOp and the QuantumCircuit.switch() method. This allows switching on a numeric input (such as a classical register or bit) and executing the circuit that corresponds to the matching value.

New Features#

  • Added the functions add_deprecation_to_docstring(), deprecate_arg(), and deprecate_func() to the qiskit.utils module.

    add_deprecation_to_docstring() will rewrite the function’s docstring to include a Sphinx .. deprecated:: directive so that the deprecation shows up in docs and with help(). The deprecation decorators from qiskit.utils call add_deprecation_to_docstring() already for you; but you can call it directly if you are using different mechanisms for deprecations.

    @deprecate_func replaces @deprecate_function and is used to deprecate an entire function. It will auto-generate most of the deprecation message for you.

    @deprecate_arg replaces @deprecate_arguments and is used to deprecate an argument on a function. It will generate a more useful message than the previous function. It is also more flexible, for example it allows setting a predicate so that you only deprecate certain situations, such as using a deprecated value or data type.

Transpiler Features#
  • Added an alternative way to specify in HLSConfig the list of synthesis methods used for a given high-level object. As before, a synthesis method can be specified as a tuple consisting of the name of the method and additional arguments. Additionally, a synthesis method can be specified as a tuple consisting of an instance of HighLevelSynthesisPlugin and additional arguments. Moreover, when there are no additional arguments, a synthesis method can be specified simply by name or by an instance of HighLevelSynthesisPlugin. The following example illustrates the new functionality:

    from qiskit import QuantumCircuit
    from qiskit.circuit.library.generalized_gates import PermutationGate
    from qiskit.transpiler import PassManager
    from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig, HighLevelSynthesis
    from qiskit.transpiler.passes.synthesis.high_level_synthesis import ACGSynthesisPermutation
    
    qc = QuantumCircuit(6)
    qc.append(PermutationGate([1, 2, 3, 0]), [1, 2, 3, 4])
    
    # All of the ways to specify hls_config are equivalent
    hls_config = HLSConfig(permutation=[("acg", {})])
    hls_config = HLSConfig(permutation=["acg"])
    hls_config = HLSConfig(permutation=[(ACGSynthesisPermutation(), {})])
    hls_config = HLSConfig(permutation=[ACGSynthesisPermutation()])
    
    # The hls_config can then be passed as an argument to HighLevelSynthesis
    pm = PassManager(HighLevelSynthesis(hls_config=hls_config))
    qc_synthesized = pm.run(qc)
    
  • Added support to the CouplingMap object to have a disjoint connectivity. Previously, a CouplingMap could only be constructed if the graph was connected. This will enable using CouplingMap to represent hardware with disjoint qubits, such as hardware with qubits on multiple separate chips.

  • Added high-level-synthesis plugins for LinearFunction and for qiskit.quantum_info.Clifford, extending the set of synthesis methods that can be called from HighLevelSynthesis transpiler pass.

    For LinearFunction the available plugins are listed below:

    Plugin name

    High-level synthesis plugin

    default

    DefaultSynthesisLinearFunction

    kms

    KMSSynthesisLinearFunction

    pmh

    PMHSynthesisLinearFunction

    For qiskit.quantum_info.Clifford the available plugins are listed below:

    Plugin name

    High-level synthesis plugin

    default

    DefaultSynthesisClifford

    ag

    AGSynthesisClifford

    bm

    BMSynthesisClifford

    greedy

    GreedySynthesisClifford

    layers

    LayerSynthesisClifford

    lnn

    LayerLnnSynthesisClifford

    Please refer to qiskit.synthesis documentation for more information about each individual method.

    The following example illustrates some of the new plugins:

    from qiskit.circuit import QuantumCircuit
    from qiskit.circuit.library import LinearFunction
    from qiskit.quantum_info import Clifford
    from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig, HighLevelSynthesis
    
    # Create a quantum circuit with one linear function and one clifford
    qc1 = QuantumCircuit(3)
    qc1.cx(0, 1)
    qc1.swap(0, 2)
    lin_fun = LinearFunction(qc1)
    
    qc2 = QuantumCircuit(3)
    qc2.h(0)
    qc2.cx(0, 2)
    cliff = Clifford(qc2)
    
    qc = QuantumCircuit(4)
    qc.append(lin_fun, [0, 1, 2])
    qc.append(cliff, [1, 2, 3])
    
    # Choose synthesis methods that adhere to linear-nearest-neighbour connectivity
    hls_config = HLSConfig(linear_function=["kms"], clifford=["lnn"])
    
    # Synthesize
    qct = HighLevelSynthesis(hls_config)(qc)
    print(qct.decompose())
    
  • Added a new transpiler pass, MinimumPoint which is used primarily as a pass to check a loop condition in a PassManager. This pass will track the state of fields in the property set over its past executions and set a boolean field when either a fixed point is reached over the backtracking depth or selecting the minimum value found if the backtracking depth is reached. This is an alternative to the FixedPoint which simply checks for a fixed value in a property set field between subsequent executions.

  • Added a new method, swap_nodes(), to the DAGCircuit to allow swapping nodes which are partially connected. Partially connected here means that the two nodes share at least one edge (which represents a qubit or clbit). If the nodes do not share any edges a DAGCircuitError is raised.

  • Add a new synthesis algorithm synth_cz_depth_line_mr() of a CZ circuit for linear nearest neighbor (LNN) connectivity in 2-qubit depth of 2n+2 using CX and phase gates (S, Sdg or Z). The synthesized circuit reverts the order of the qubits. The synthesis algorithm is based on the paper of Maslov and Roetteler (https://arxiv.org/abs/1705.09176).

  • Add a new synthesis algorithm synth_clifford_depth_lnn() of a Clifford circuit for LNN connectivity in 2-qubit depth of 9n+4 (which is still not optimal), using the layered Clifford synthesis (synth_clifford_layers()), synth_cnot_depth_line_kms() to synthesize the CX layer in depth 5n, and synth_cz_depth_line_mr() to synthesize each of the CZ layers in depth 2n+2. This PR will be followed by another PR based on the recent paper of Maslov and Yang (https://arxiv.org/abs/2210.16195), that synthesizes the CX-CZ layers in depth 5n for LNN connectivity and performs further optimization, and hence reduces the depth of a Clifford circuit to 7n-4 for LNN connectivity.

  • Equivalences between the controlled Pauli rotations and translations to two-Pauli rotations are now available in the equivalence library for Qiskit standard gates. This allows, for example, to translate a CRZGate to a RZZGate plus RZGate or a CRYGate to a single RZXGate plus single qubit gates:

    from qiskit.circuit import QuantumCircuit
    from qiskit.compiler import transpile
    
    angle = 0.123
    circuit = QuantumCircuit(2)
    circuit.cry(angle, 0, 1)
    
    basis = ["id", "sx", "x", "rz", "rzx"]
    transpiled = transpile(circuit, basis_gates=basis)
    print(transpiled.draw())
    
  • Added a new option, copy_operations, to circuit_to_dag() to enable optionally disabling deep copying the operations from the input QuantumCircuit to the output QuantumCircuit. In cases where the input :class`~.QuantumCircuit` is not used anymore after conversion this deep copying is unnecessary overhead as any shared references wouldn’t have any potential unwanted side effects if the input QuantumCircuit is discarded.

  • Added a new option, copy_operations, to dag_to_circuit() to enable optionally disabling deep copying the operations from the input DAGCircuit to the output QuantumCircuit. In cases where the input DAGCircuit is not used anymore after conversion this deep copying is unnecessary overhead as any shared references wouldn’t have any potential unwanted side effects if the input DAGCircuit is discarded.

  • Added a new function passmanager_stage_plugins() to the qiskit.transpiler.preset_passmanagers.plugin module. This function is used to obtain a mapping from plugin names to their their class type. This enables identifying and querying any defined pass manager stage plugin’s documentation. For example:

    >>> from qiskit.transpiler.preset_passmanagers.plugin import passmanager_stage_plugins
    >>> passmanager_stage_plugins('routing')['lookahead'].__class__
    
    qiskit.transpiler.preset_passmanagers.builtin_plugins.LookaheadSwapPassManager
    
    >>> help(passmanager_stage_plugins('routing')['lookahead'])
    Help on BasicSwapPassManager in module qiskit.transpiler.preset_passmanagers.builtin_plugins object:
    
    class BasicSwapPassManager(qiskit.transpiler.preset_passmanagers.plugin.PassManagerStagePlugin)
    |  Plugin class for routing stage with :class:`~.BasicSwap`
    ...
    
  • The transpiler pass Error now also accepts callable inputs for its msg parameter. If used these input callables will be passed the property_set attribute of the pass and are expected to return a string which will be used for the error message when the pass is run. For example:

    from qiskit.transpiler.passes import Error
    
    def error_message(property_set):
    
        size = property_set["size']
        return f"The circuit size is: {size}"
    
    error_pass = Error(error_message)
    

    When error_pass is included in a pass manager it will error using the message "The circuit size is: n" where n is the circuit size set in the property set (typically from the previous execution of the Size pass).

  • The build_coupling_map() method has a new keyword argument, filter_idle_qubits which when set to True will remove any qubits from the output CouplingMap that don’t support any operations.

  • The GateDirection transpiler pass can now correctly handle SwapGate instances that may be present in the circuit when executing on a circuit. In these cases if the swap gate’s qubit arguments are on the non-native direction of an edge, the pass will flip the argument order.

  • Added a new constructor for the Target class, Target.from_configuration(), which lets you construct a Target object from the separate object types for describing the constraints of a backend (e.g. basis gates, CouplingMap, BackendProperties, etc). For example:

    target = Target.from_configuration(
        basis_gates=["u", "cx", "measure"],
        coupling_map=CouplingMap.from_line(25),
    )
    

    This will construct a Target object that has UGate, CXGate, and Measure globally available on 25 qubits which are connected in a line.

  • Added a new function synth_cnot_phase_aam() which is used to synthesize cnot phase circuits for all-to-all architectures using the Amy, Azimzadeh, and Mosca method. This function is identical to the available qiskit.transpiler.synthesis.graysynth() 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.

  • Internal tweaks to the routing algorithm in SabreSwap, used in transpilation of non-dynamic circuits at all non-zero optimization levels, have sped up routing for very large circuits. For example, the time to route a depth-5 QuantumVolume circuit for a 1081-qubit heavy-hex coupling map is approximately halved.

  • The runtime performance of the Optimize1qGatesDecomposition transpiler pass has been significantly improved. This was done by both rewriting all the computation for the pass in Rust and also decreasing the amount of intermediate objects created as part of the pass’s execution. This should also correspond to a similar improvement in the runtime performance of transpile() with the optimization_level keyword argument set to 1, 2, or 3.

  • Add a new synthesis method synth_stabilizer_layers() of a stabilizer state into layers. It provides a similar decomposition to the synthesis described in Lemma 8 of Bravyi and Maslov, (arxiv:2003.09412) without the initial Hadamard-free sub-circuit which does not affect the stabilizer state.

  • Add a new synthesis method synth_stabilizer_lnn() of a stabilizer state for linear nearest neighbor connectivity in 2-qubit depth of 2n+2 and two distinct CX layers, using CX and phase gates (S, Sdg or Z). The synthesis algorithm is based on the paper of Maslov and Roetteler (https://arxiv.org/abs/1705.09176).

  • The SabreLayout pass now supports running against a target with a disjoint CouplingMap. When targeting a disjoint coupling the input DAGCircuit is split into its connected components of virtual qubits, each component is mapped to the connected components of the CouplingMap, layout is run on each connected component in isolation, and then all layouts are combined and returned. Note when the routing_pass argument is set the pass doesn’t support running with disjoint connectivity.

  • The pass manager construction helper function generate_scheduling() has a new keyword argument target which is used to specify a Target object to model the constraints of the target backend being compiled for when generating a new PassManager. If specified this new argument will supersede the other argument inst_map.

  • The default plugin used by the UnitarySynthesis transpiler pass now chooses one and two-qubit unitary synthesis based on the error rates reported in the Target. In particular, it runs all possible synthesis methods supported by the plugin and chooses the option which will result in the lowest error. For a one-qubit decomposition, it can target Pauli basis (e.g. RZ-RX-RZ or RZ-RY-RZ), generic unitary basis (e.g. U), and a few others. For a two-qubit decomposition, it can target any supercontrolled basis (e.g. CNOT, iSWAP, B) or multiple controlled basis (e.g. CZ, CH, ZZ^.5, ZX^.2, etc.).

  • The interface for UnitarySynthesisPlugin has two new optional properties supports_gate_lengths_by_qubit and supports_gate_errors_by_qubit which when set will add the fields gate_lengths_by_qubit and gate_errors_by_qubit respectively to the input options to the plugin’s run() method. These new fields are an alternative view of the data provided by gate_lengths and gate_errors but instead have the form: {(qubits,): [Gate, length]} (where Gate is the instance of Gate for that definition). This allows plugins to reason about working with gates of the same type but but that have different parameters set.

  • Added a new transpiler pass, UnrollForLoops, which is used to unroll any ForLoopOp operations in a circuit. This pass unrolls for-loops when possible, if there are no ContinueLoopOp or BreakLoopOp inside the body block of the loop. For example:

    from qiskit.transpiler.passes import UnrollForLoops
    from qiskit import QuantumCircuit
    
    unroll_pass = UnrollForLoops()
    
    qc = QuantumCircuit(1)
    # For loop over range 5
    with qc.for_loop(range(5)) as i:
        qc.rx(i, 0)
    # Unroll loop into 5 rx gates
    unroll_pass(qc).draw("mpl")
    

    (Source code)

    _images/release_notes-1.png
  • Added a new parameter max_trials to pass VF2PostLayout which, when specified, limits the number of layouts discovered and compared when searching for the best layout. This differs from existing parameters call_limit and time_limit (which are used to limit the number of state visits performed by the VF2 algorithm and the total time spent by pass VF2PostLayout, respectively) in that it is used to place an upper bound on the time spent scoring potential layouts, which may be useful for larger devices.

  • The CheckMap transpiler pass has a new keyword argument on its constructor, property_set_field. This argument can be used to specify a field in the property set to store the results of the analysis. Previously, it was only possible to store the result in the field "is_swap_mapped" (which is the default). This enables you to store the result of multiple instances of the pass in a PassManager in different fields.

Circuits Features#
  • Added a new argument, var_order, to the PhaseOracle class’s constructor to enable setting the order in which the variables in the logical expression are being considered. For example:

    from qiskit.tools.visualization import plot_histogram
    from qiskit.primitives import Sampler
    from qiskit.circuit.library import PhaseOracle
    from qiskit.algorithms import Grover, AmplificationProblem
    
    oracle = PhaseOracle('((A & C) | (B & D)) & ~(C & D)', var_order=['A', 'B', 'C', 'D'])
    problem = AmplificationProblem(oracle=oracle, is_good_state=oracle.evaluate_bitstring)
    grover = Grover(sampler=Sampler())
    result = grover.amplify(problem)
    print(result.circuit_results[0])
    
  • A new OpenQASM 2 parser is available in qiskit.qasm2. This has two entry points: qasm2.load() and qasm2.loads(), for reading the source code from a file and from a string, respectively:

    import qiskit.qasm2
    program = """
      OPENQASM 2.0;
      include "qelib1.inc";
      qreg q[2];
      h q[0];
      cx q[0], q[1];
    """
    bell = qiskit.qasm2.loads(program)
    

    This new parser is approximately 10x faster than the existing ones at QuantumCircuit.from_qasm_file() and QuantumCircuit.from_qasm_str() for large files, and has less overhead on each call as well. The new parser is more extensible, customisable and generally also more type-safe; it will not attempt to output custom Qiskit objects when the definition in the OpenQASM 2 file clashes with the Qiskit object, unlike the current exporter. See the qiskit.qasm2 module documentation for full details and more examples.

  • Improve the decomposition of multi-controlled Pauli-X and Pauli-Y rotations with QuantumCircuit.mcrx() and QuantumCircuit.mcry on :math:`n() controls to \(16n - 40\) CX gates, for \(n \geq 4\). This improvement is based on arXiv:2302.06377.

  • Qiskit now supports the representation of switch statements, using the new SwitchCaseOp instruction and the QuantumCircuit.switch() method. This allows switching on a numeric input (such as a classical register or bit) and executing the circuit that corresponds to the matching value. Multiple values can point to the same circuit, and CASE_DEFAULT can be used as an always-matching label.

    You can also use a builder interface, similar to the other control-flow constructs to build up these switch statements:

    from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
    
    qreg = QuantumRegister(2)
    creg = ClassicalRegister(2)
    qc = QuantumCircuit(qreg, creg)
    
    qc.h([0, 1])
    qc.measure([0, 1], [0, 1])
    with qc.switch(creg) as case:
      with case(0):  # if the register is '00'
        qc.z(0)
      with case(1, 2):  # if the register is '01' or '10'
        qc.cx(0, 1)
      with case(case.DEFAULT):  # the default case
        qc.h(0)
    

    The switch statement has support throughout the Qiskit compiler stack; you can transpile() circuits containing it (if the backend advertises its support for the construct), and it will serialize to QPY.

    The switch statement is not currently a feature of OpenQASM 3, but it is under active design and consideration, which is expected to be adopted in the near future. Qiskit Terra has experimental support for exporting this statement to the OpenQASM 3 syntax proposed in the linked pull request, using an experimental feature flag. To export a switch statement circuit (such as the one created above) to OpenQASM 3 using this speculative support, do:

    from qiskit import qasm3
    
    qasm3.dumps(qc, experimental=qasm3.ExperimentalFeatures.SWITCH_CASE_V1)
    
Algorithms Features#
  • Added a new attribute eigenvalue_threshold to the AdaptVQE class for configuring a new kind of threshold to terminate the algorithm once the eigenvalue changes less than a set value.

  • Added a new attribute gradient_threshold to the AdaptVQE class which will replace the threshold in the future. This new attribute behaves the same as the existing threshold attribute but has a more accurate name, given the introduction of additional threshold options in the class.

  • Adds a flag local to the ComputeUncompute state fidelity class that allows to compute the local fidelity, which is defined by averaging over single-qubit projectors.

  • Gradient classes rearrange the gradient result according to the order of the input parameters now.

    Example:

    from qiskit.algorithms.gradients import ParamShiftEstimatorGradient
    from qiskit.circuit import QuantumCircuit, Parameter
    from qiskit.primitives import Estimator
    from qiskit.quantum_info import SparsePauliOp
    
    # Create a circuit with a parameter
    p = {i: Parameter(f'p{i}') for i in range(3)}
    qc = QuantumCircuit(1)
    qc.rx(p[0], 0)
    qc.ry(p[1], 0)
    qc.rz(p[2], 0)
    op = SparsePauliOp.from_list([("Z", 1)])
    param_values = [0.1, 0.2, 0.3]
    
    # Create a gradient object
    estimator = Estimator()
    grad = ParamShiftEstimatorGradient(estimator)
    result = grad.run(qc, op, [param_values]).result()
    # would produce a gradient of the form [df/dp0, df/dp1, df/dp2]
    result = grad.run(qc, op, [param_values], parameters=[[p[2], p[0]]]).result()
    # would produce a gradient of the form [df/dp2, df/dp0]
    
  • Added support for handling time-dependent Hamiltonians (i.e. singly parametrized operators) to the TrotterQRTE class. To facilitate working with this, added the num_timesteps attribute and a matching keyword argument to the TrotterQRTE constructor to control the number of time steps to divide the full evolution.

  • Added support for observable evaluations at every time-step during the execution of the TrotterQRTE class. The TimeEvolutionProblem.aux_operators is evaluated at every time step if the ProductFormula.reps attribute of the input product_formula argument in the constructor is set to 1.

  • Added extensions to the VQD algorithm, which allow to pass a list of optimizers and initial points for the different minimization runs. For example, the k-th initial point and k-th optimizer will be used for the optimization of the k-1-th exicted state.

Quantum Information Features#
  • The constructor of Clifford now can take any Clifford gate object up to 3 qubits as long it implements a to_matrix method, including parameterized gates such as Rz(pi/2), which were not convertible before.

  • Added the method StabilizerState.equiv, that checks if the generating sets of two stabilizer states generate the same stabilizer group. For example, the stabilizer group of the two-qubit Bell state contains the four elements \(\{II, XX, -YY, ZZ\}\) and hence can be generated by either \([XX, ZZ]\), \([XX, -YY]\) or \([-YY, ZZ]\).

  • Added a new method, partial_transpose(), to the qiskit.quantum_info module’s DensityMatrix class. This method is used to compute the partial transposition of a density matrix, which is necessary for detecting entanglement between bipartite quantum systems.

  • Added a method qiskit.quantum_info.Operator.apply_permutation() that pre-composes or post-composes an Operator with a Permutation. This method works for general qudits.

    Here is an example to calculate \(P^\dagger.O.P\) which reorders Operator’s bits:

    import numpy as np
    from qiskit.quantum_info.operators import Operator
    
    op = Operator(np.array(range(576)).reshape((24, 24)), input_dims=(2, 3, 4), output_dims=(2, 3, 4))
    perm = [1, 2, 0]
    inv_perm = [2, 0, 1]
    conjugate_op = op.apply_permutation(inv_perm, front=True).apply_permutation(perm, front=False)
    

    The conjugate operator has dimensions (4, 2, 3) x (4, 2, 3), which is consistent with permutation moving qutrit to position 0, qubit to position 1, and the 4-qudit to position 2.

  • Natively support the construction of SparsePauliOp objects with ParameterExpression coefficients, without requiring the explicit construction of an object-array. Now the following is supported:

    from qiskit.circuit import Parameter
    from qiskit.quantum_info import SparsePauliOp
    
    x = Parameter("x")
    op = SparsePauliOp(["Z", "X"], coeffs=[1, x])
    
  • Added the SparsePauliOp.assign_parameters() method and SparsePauliOp.parameters attribute to assign and query unbound parameters inside a SparsePauliOp. This function can for example be used as:

    from qiskit.circuit import Parameter
    from qiskit.quantum_info import SparsePauliOp
    
    x = Parameter("x")
    op = SparsePauliOp(["Z", "X"], coeffs=[1, x])
    
    # free_params will be: ParameterView([x])
    free_params = op.parameters
    
    # assign the value 2 to the parameter x
    bound = op.assign_parameters([2])
    
Pulse Features#
  • Added new SymbolicPulse classes to the pulse library (qiskit.pulse.library) The new pulses in the library are:

    These new classes are instances of ScalableSymbolicPulse. With the exception of the Sawtooth phase, behavior is identical to that of the corresponding waveform generator function (e.g. sin()). The phase for the Sawtooth class is defined such that a phase of \(2\pi\) shifts by a full cycle.

  • Added support to QPY (qiskit.qpy) for working with pulse ScheduleBlock instances with unassigned references, and preserving the data structure for the reference to subroutines. This feature allows users to serialize and deserialize a template pulse program for tasks such as pulse calibration. For example:

    from qiskit import pulse
    from qiskit import qpy
    
    with pulse.build() as schedule:
        pulse.reference("cr45p", "q0", "q1")
        pulse.reference("x", "q0")
        pulse.reference("cr45p", "q0", "q1")
    
    with open('template_ecr.qpy', 'wb') as fd:
        qpy.dump(schedule, fd)
    
  • A new method CalibrationEntry.user_provided() has been added to calibration entries. This method can be called to check whether the entry is defined by an end user or backend.

  • Added a new method Target.get_calibration() which provides convenient access to the calibration of an instruction in a Target object This method can be called with parameter args and kwargs, and it returns a pulse schedule built with parameters when the calibration is templated with parameters.

Providers Features#
  • The BackendV2Converter class has a new keyword argument, filter_faulty, on its constructor. When this argument is set to True the converter class will filter out any qubits or operations listed as non-operational in the BackendProperties payload for the input BackendV1. While not extensively used a BackendProperties object supports annotating both qubits and gates as being non-operational. Previously, if a backend had set that flag on any qubits or gates the output BackendV2 instance and its Target would include all operations whether they were listed as operational or not. By leveraging the new flag you can filter out these non-operational qubits and gates from the Target. When the flag is set the output backend will still be listed as the full width (e.g. a 24 qubit backend with 4 qubits listed as not operational will still show it has 24 qubits) but the faulty qubits will not have any operations listed as being supported in the Target.

  • The Options class now implements the the Mapping protocol and __setitem__ method. This means that Options instances now offer the same interface as standard dictionaries, except for the deletion methods (__delitem__, pop, clear). Key assignments are validated by the validators, if any are registered.

Visualization Features#
  • Added a new function, staged_pass_manager_drawer(), which is used for visualizing a StagedPassManager instance. It draws the full pass manager with each stage represented as an outer box.

    For example:

    from qiskit.visualization import staged_pass_manager_drawer
    from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
    from qiskit.providers.fake_provider import FakeSherbrooke
    
    backend = FakeSherbrooke()
    pm = generate_preset_pass_manager(3, backend)
    staged_pass_manager_drawer(pm)
    
  • The StagedPassManager.draw() method has been updated to include visualization of the stages in addition to the overall pass manager. The stages are represented by outer boxes in the visualization. In previous releases the stages were not included in the visualization. For example:

    from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
    from qiskit.providers.fake_provider import FakeSherbrooke
    
    backend = FakeSherbrooke()
    pm = generate_preset_pass_manager(3, backend)
    pm.draw(pm)
    
  • Added a new keyword argument, figsize, to the plot_bloch_multivector() function. This argument can be used to set a size for individual Bloch sphere sub-plots. For example, if there are \(n\) qubits and figsize is set to (w, h), then the overall figure width is set to \(n \cdot w\), while the overall height is set to \(h\).

  • Added a new keyword argument, font_size, to the plot_bloch_multivector() function. This argument can be used to control the font size in the output visualization.

  • Added two new keyword arguments, title_font_size and title_pad, to the plot_bloch_multivector() function. These arguments can be used to control the font size of the overall title and its padding respectively.

Upgrade Notes#

  • The minimum supported Rust version (MSRV) has been increased from 1.56.1 to 1.61.0. If you’re are building Qiskit from source you will now need to ensure that you have at least Rust 1.61.0 installed to be able to build Qiskit. This change was made because several upstream dependencies have increased their MSRVs.

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

Transpiler Upgrade Notes#
  • The maximum number of trials evaluated when searching for the best layout using VF2Layout and VF2PostLayout is now limited in level_1_pass_manager(), level_2_pass_manager(), and level_3_pass_manager() to 2 500, 25 000, and 250 000, respectively. Previously, all found possible layouts were evaluated. This change was made to prevent transpilation from hanging during layout scoring for circuits with many connected components on larger devices, which scales combinatorially since each connected component would be evaluated in all possible positions on the device. To perform a full search as before, manually run VF2PostLayout over the transpiled circuit in strict mode, specifying 0 for max_trials.

  • The previously deprecated condition attribute of the DAGDepNode class has been removed. It was marked as deprecated in the 0.18 release (07-2021). Instead you should use the condition attribute of the op attribute to access the condition of an operation node. For other node types there is no condition to access.

  • The CouplingMap.__eq__`() method has been updated to check that the edge lists of the underlying graphs contain the same elements. Under the assumption that the underlying graphs are connected, this check additionally ensures that the graphs have the same number of nodes with the same labels. Any code using CouplingMap() == CouplingMap() to check object equality should be updated to CouplingMap() is CouplingMap().

  • When running the transpile() function with a BackendV1 based backend or a BackendProperties via the backend_properties keyword argument that has any qubits or gates flagged as faulty the function will no longer try to automatically remap the qubits based on this information. The method by which transpile() attempted to do this remapping was fundamentally flawed and in most cases of such a backend it would result an internal error being raised. In practice very few backends ever set the fields in BackendProperties to flag a qubit or gate as faulty. If you were relying on transpile() to do this re-mapping for you, you will now need to manually do that and pass a mapped input to the coupling_map and backend_properties arguments which has filtered out the faulty qubits and gates and then manually re-map the output.

  • The result of transpilations for fixed seeds may have changed compared to previous versions of Qiskit Terra. This is because of internal tweaks to the routing algorithm used by SabreSwap and SabreLayout, which are the default routing and layout passes respectively, to make them significantly faster for large circuits.

Circuits Upgrade Notes#
  • The QuantumCircuit metadata attribute now always returns a dictionary, and can only be set to a dictionary. Previously, its default value was None, and could be manually set to None or a dictionary.

Algorithms Upgrade Notes#
  • The deprecated modules factorizers and linear_solvers, containing HHL and Shor have been removed from qiskit.algorithms. These functionalities were originally deprecated as part of the 0.22.0 release (released on October 13, 2022). You can access the code through the Qiskit Textbook instead: Linear Solvers (HHL) , Factorizers (Shor)

Pulse Upgrade Notes#
  • Target.update_from_instruction_schedule_map() no longer raises KeyError nor ValueError when qubits are missing in the target instruction or inst_name_map is not provided for the undefined instruction. In the former case, it just ignores the input InstructionScheduleMap's definition for undefined qubits. In the latter case, a gate mapping is pulled from the standard Qiskit gates and finally, a custom opaque Gate object is defined from the schedule name if no mapping is found.

Providers Upgrade Notes#
  • The deprecated max_credits argument to execute(), assemble() and all of the Qobj configurations (e.g. QasmQobjConfig and PulseQobjConfig) has been removed. This argument dates back to early versions of Qiskit which was tied more closely to the IBM Quantum service offering. At that time the max_credits field was part of the “credit system” used by IBM Quantum’s service offering. However, that credit system has not been in use on IBM Quantum backends for nearly three years and also Qiskit is not tied to IBM Quantum’s service offerings anymore (and hasn’t been for a long time). If you were relying on this option in some way for a backend you will need to ensure that your BackendV2 implementation exposes a max_credits field in its Options object.

  • The name attribute on the BackendV2 based fake backend classes in qiskit.providers.fake_provider have changed from earlier releases. Previously, the names had a suffix "_v2" to differentiate the class from the BackendV1 version. This suffix has been removed as having the suffix could lead to inconsistencies with other snapshotted data used to construct the backend object.

Deprecation Notes#

Transpiler Deprecations#
  • The transpiler routing pass, BIPMapping has been deprecated and will be removed in a future release. It has been replaced by an external plugin package: qiskit-bip-mapper. Details for this new package can be found at the package’s github repository:

    https://github.com/qiskit-community/qiskit-bip-mapper

    The pass was made into a separate plugin package for two reasons, first the dependency on CPLEX makes it harder to use and secondly the plugin packge more cleanly integrates with transpile().

  • Misspelled aquire_alignment in the class Target has been replaced by correct spelling acquire_alignment. The old constructor argument aquire_alignment and Target.aquire_alignment are deprecated and will be removed in a future release. Use Target.acquire_alignment instead to get and set the alignment constraint value.

Circuits Deprecations#
  • Setting the QuantumCircuit metadata attribute to None has been deprecated and will no longer be supported in a future release. Instead, users should set it to an empty dictionary if they want it to contain no data.

Algorithms Deprecations#
Quantum Information Deprecations#
  • The PauliTable and StabilizerTable are deprecated and will be removed in a future release. Instead, the PauliList should be used. With this change, table() has been deprecated so that you should operate directly from tableau() without it.

Pulse Deprecations#
  • Assignment of complex values to ParameterExpression in any Qiskit Pulse object now raises a PendingDeprecationWarning. This will align the Pulse module with other modules where such assignment wasn’t possible to begin with. The typical use case for complex parameters in the module was the SymbolicPulse library. As of Qiskit-Terra 0.23.0 all library pulses were converted from complex amplitude representation to real representation using two floats (amp,angle), as used in the ScalableSymbolicPulse class. This eliminated the need for complex parameters. Any use of complex parameters (and particularly custom-built pulses) should be converted in a similar fashion to avoid the use of complex parameters.

Bug Fixes#

  • The AmplitudeEstimation class now correctly warns if an EstimationProblem with a set is_good_state property is passed as input, as it is not supported and ignored. Previously, the algorithm would silently ignore this option leading to unexpected results.

  • QuantumCircuit.append() will now correctly raise an error if given an incorrect number of classical bits to apply to an operation. Fix #9385.

  • The BarrierBeforeFinalMeasurements and MergeAdjacentBarriers transpiler passes previously had a non-deterministic order of their emitted Barrier instructions. This did not change the semantics of circuits but could, in limited cases where there were non-full-width barriers, cause later stochastic transpiler passes to see a different topological ordering of the circuit and consequently have different outputs for fixed seeds. The passes have been made deterministic to avoid this.

  • The return type of run() will now always be the same as that of its first argument. Passing a single circuit returns a single circuit, passing a list of circuits, even of length 1, returns a list of circuits. See #9798.

  • Fixed a bug where PauliOp.adjoint() did not return a correct value for Paulis with complex coefficients, like PauliOp(Pauli("iX")). Fixed #9433.

  • Fixed an issue with the circuit drawer function circuit_drawer() and QuantumCircuit.draw() method when using the text method and the argument vertical_compression="low" where it would use an incorrect character for the top-right corner of boxes used to represent gates in the circuit.

  • Fixed an issue with the Gate.control() method where it previously would incorrectly handle str or None input types for the ctrl_state argument.

  • Fixed an edge case in the construction of Pauli instances; a string with an optional phase and no qubits is now a valid label, making an operator with no qubits (such as Pauli("-i")). This was already possible when using the array forms, or empty slices. Fixed #9720.

  • Fixed an issue when using the pulse macro measure() when working with a BackendV2 based backend. Previously, trying to use qiskit.pulse.macros.measure() with a BackendV2 based backend would have resulted in an error. Fixed #9488

  • Fixed an issue with the marginal_distribution() function where it would incorrectly raise an error when an input counts dictionary was using a numpy integer type instead of the Python int type. The underlying function always would handle the different types correctly, but the input type checking was previously incorrectly raising a TypeError in this case.

  • Fixed the transpiler routing passes StochasticSwap, SabreSwap, LookaheadSwap, and BasicSwap so that they consistently raise a TranspilerError when their respective .run() method is called if the passes were initialized with coupling_map=None. Previously, these passes would raise errors in this case but they were all caused by side effects and the specific exception was not predictable. Fixed #7127

  • Manually setting an item in QuantumCircuit.data will now correctly allow the operation to be any object that implements Operation, not just a circuit.Instruction. Note that any manual mutation of QuantumCircuit.data is discouraged; it is not usually any more efficient than building a new circuit object, as checking the invariants surrounding parametrised objects can be surprisingly expensive.

  • Fixed a bug 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 correclty applied, independent of the number of tensored operators or states. Fixed #9398.

  • Fixed global-phase handling in the UnrollCustomDefinitions transpiler pass if the instruction in question had a global phase, but no instructions in its definition field.

  • Fixed the the type annotations for the transpile() function. The return type is now narrowed correctly depending on whether a single circuit or a list of circuits was passed.

  • A bug has been fixed which had allowed broadcasting when a PauliList is initialized from Paulis or labels. For instance, the code PauliList(["XXX", "Z"]) now raises a ValueError rather than constructing the equivalent of PauliList(["XXX", "ZZZ"]).

  • The OpenQASM 2 exporter (QuantumCircuit.qasm()) will now output definitions for gates used only in other gates’ definitions in a correct order. See #7769 and #7773.

  • Standard gates defined by Qiskit, such as RZXGate, will now have properly parametrised definitions when exported using the OpenQASM 2 exporter (QuantumCircuit.qasm()). See #7172.

  • The OpenQASM 2 exporter will now output gates with no known definition with opaque statements, rather than failing. See #5036.

  • An issue that prevented transpile() from working when passed a list of CouplingMap objects was fixed. Note that passing such a list of coupling maps is deprecated and will not be possible starting with Qiskit Terra 0.25. Fixes #9885.

  • Previous to this release, the figsize argument of plot_bloch_multivector() was not used by the visualization, making it impossible to change its size (e.g. to shrink it for single-qubit states). This release fixes it by introducing a use for the figsize argument.

  • Fixed an issue in transpile() with optimization_level=1 (as well as in the preset pass managers returned by generate_preset_pass_manager() and level_1_pass_manager()) where previously if the routing_method and layout_method arguments were not set and no control flow operations were present in the circuit then in cases where routing was required the VF2PostLayout transpiler pass would not be run. This was the opposite of the expected behavior because VF2PostLayout is intended to find a potentially better performing layout after a heuristic layout pass and routing are run. Fixed #9936

  • Construction of a Statevector from a QuantumCircuit containing zero-qubit operations will no longer raise an error. These operations impart a global phase on the resulting statevector.

  • Fixed an issue in tranpiler passes for padding delays, which did not respect target’s constraints and inserted delays even for qubits not supporting Delay instruction. PadDelay and PadDynamicalDecoupling are fixed so that they do not pad any idle time of qubits such that the target does not support Delay instructions for the qubits. Also legacy scheduling passes ASAPSchedule and ALAPSchedule, which pad delays internally, are fixed in the same way. In addition, transpile() is fixed to call PadDelay with a target object so that it works correctly when called with scheduling_method option. Fixed #9993

  • Fixed the type annotations on the QuantumCircuit.assign_parameters() method to correctly reflect the change in return type depending on the value of the inplace argument.

  • Fixed a performance scaling issue with the VF2Layout and VF2PostLayout passes in the preset pass managers and transpile(), which would occur when transpiling circuits with many connected components on large devices. Now the transpiler passes set upper bounds on the number of potential layouts that will be evaluated.

  • Fixed an issue in the state_to_latex() function where it would potentially produce invalid LaTeX due to unintended coefficient rounding. This could also result in errors when the state_drawer() was called. Fixed #9297.

Aer 0.12.0#

No change

IBM Q Provider 0.20.2#

No change

Qiskit 0.42.1#

Terra 0.23.3#

Prelude#

Qiskit Terra 0.23.3 is a minor bugfix release.

Bug Fixes#

  • Fixes a bug in the Optimize1qGatesDecomposition transformation pass where the score for substitutions was wrongly calculated when the gate errors are zero.

  • The method ECRGate.inverse() now returns another ECRGate instance rather than a custom gate, since it is self inverse.

  • Clip probabilities in the QuantumState.probabilities() and QuantumState.probabilities_dict() methods to the interval [0, 1]. This fixes roundoff errors where probabilities could e.g. be larger than 1, leading to errors in the shot emulation of the sampler. Fixed #9761.

  • Fixed a bug in the BackendSampler where the binary probability bitstrings were truncated to the minimal number of bits required to represent the largest outcome as integer. That means that if e.g. {"0001": 1.0} was measured, the result was truncated to {"1": 1.0}.

  • Fixed an issue with the PassManagerConfig.from_backend() constructor method when it was used with a BackendV1 based simulator backend. For some simulator backends which did not populate some optional fields the constructor would error. Fixed #9265 and #8546

  • Fixed the BackendSampler and BackendEstimator to run successfully with a custom bound_pass_manager. Previously, the execution for single circuits with a bound_pass_manager would raise a ValueError because a list was not returned in one of the steps.

  • The GateDirection transpiler pass will no longer reject gates that have been given explicit calibrations, but do not exist in the generic coupling map or target.

  • Fixed an issue with the CommutationChecker class where it would attempt to internally allocate an array for \(2^{n}\) qubits when it only needed an array to represent \(n\) qubits. This could cause an excessive amount of memory for wide gates, for example a 4 qubit gate would require 32 gigabytes instead of 2 kilobytes. Fixed #9197

  • Getting empty calibration from InstructionProperties raises AttributeError has been fixed. Now it returns None.

  • Fixed qasm() so that it appends ; after reset instruction.

  • Register and parameter names will now be escaped during the OpenQASM 3 export (qasm3.dumps()) if they are not already valid identifiers. Fixed #9658.

  • QPY (using qpy.load()) will now correctly deserialize StatePreparation instructions. Previously, QPY would error when attempting to load a file containing one. Fixed #8297.

  • Fixed a bug in random_circuit() with 64 or more qubits and conditional=True, where the resulting circuit could have an incorrectly typed value in its condition, causing a variety of failures during transpilation or other circuit operations. Fixed #9649.

  • The Qiskit gates CCZGate, CSGate, CSdgGate are not defined in qelib1.inc and, therefore, when dump as OpenQASM 2.0, their definition should be inserted in the file. Fixes #9559, #9721, and #9722.

Aer 0.12.0#

No change

IBM Q Provider 0.20.2#

No change

Qiskit 0.42.0#

Terra 0.23.2#

No change

Aer 0.12.0#

Prelude#

The Qiskit Aer 0.12.0 release highlights are:

  • Added a new GPU tensor network simulator based on cuTensorNet

  • Added a new AerDensityMatrix class to the qiskit_aer.quantum_info module

  • Greatly improving the runtime performance of the AerSimulator and the legacy QasmSimulator, StatevectorSimulator, and UnitarySimulator classes by directly converting the input QuantumCircuit objects to an internal C++ representation instead of first serializing the circuit to a QasmQobj. This improvement will be most noticeable for circuits with a small number of qubits or parameterized circuits using the parameter_binds keyword argument.

New Features#

  • Added a new class method from_backend_properties() to the NoiseModel. This enables constructing a new NoiseModel from a BackendProperties object. Similar functionality used to be present in the NoiseModel.from_backend() constructor, however it was removed since a BackendProperties object alone doesn’t contain sufficient information to create a NoiseModel object.

  • Added a new class, AerDensityMatrix, to the qiskit_aer.quantum_info module. This class is used to provide the same interface to the upstream DensityMatrix class in Qiskit but backed by Qiskit Aer’s simulation.

  • 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 method to the AerJob, circuits(), which returns a list of QuantumCircuit objects. This method returns None if Qobj is used for simulation.

  • AerState and AerStatevector now support applying Kraus operators. In AerStatevector, one of the Kraus operators is applied randomly to the quantum state based on the error probabilities.

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

Upgrade Notes#

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

  • The NoiseModel.from_backend() now has changed not to accept BackendProperties object as a backend argument. Use newly added NoiseModel.from_backend_properties() method instead.

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

  • The previously deprecated qobj argument name of the AerSimulator and PulseSimulator classes’ run() method has now been removed. This argument name was deprecated as part of the Qiskit Aer 0.8.0 release and has been by the circuits and schedules argument name respectively.

  • 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 PulseSimulator backend has been deprecated and will be removed in a future release. If you’re using the PulseSimulator backend to perform pulse level simulation, instead you should use the Qiskit Dynamics library instead to perform the simulation. Qiskit Dynamics provides a more flexible and robust pulse level simulation framework than the PulseSimulator backend.

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

  • Fixed an issue with the Sampler class where it would previously fail if the input QuantumCircuit contained multiple multiple classical registers. Fixed #1679

  • 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 issue with the BackendV2Converter class when wrapping a BackendV1-based simulator. It would error if either the online_date field in the BackendConfiguration for the simulator was not present or if the simulator backend supported ideal implementations of gates that involve more than 1 qubit. Fixed #9562.

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

  • The deprecated Qubit and Clbit properties register and index will now be correctly round-tripped by QPY (qiskit.qpy) in all valid usages of QuantumRegister and ClassicalRegister. In earlier releases in the Terra 0.23 series, this information would be lost. In versions before 0.23.0, this information was partially reconstructed but could be incorrect or produce invalid circuits for certain register configurations.

    The correct way to retrieve the index of a bit within a circuit, and any registers in that circuit the bit is contained within is to call QuantumCircuit.find_bit(). This method will return the correct information in all versions of Terra since its addition in version 0.19.

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

Aer 0.11.2#

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#

  • An edge case of pickle InstructionScheduleMap with non-picklable iterable arguments is now fixed. Previously, using an unpickleable iterable as the arguments parameter to InstructionScheduleMap.add() (such as dict_keys) could cause parallel calls to transpile() to fail. These arguments will now correctly be normalized internally to list.

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

Aer 0.11.2#

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 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.minimum_eigensolvers.adapt_vqe import AdaptVQE
    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
    calc = AdaptVQE(VQE(Estimator(), ansatz, self.optimizer))
    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.

  • Added a new transpiler pass, CollectAndCollapse, to collect and to consolidate blocks of nodes in a circuit. This pass is designed to be a general base class for combined block collection and consolidation. To be completely general, the work of collecting and collapsing the blocks is done via functions provided during instantiating the pass. For example, the CollectLinearFunctions has been updated to inherit from CollectAndCollapse and collects blocks of CXGate and SwapGate gates, and replaces each block with a LinearFunction. The CollectCliffords which is also now based on CollectAndCollapse, collects blocks of “Clifford” gates and replaces each block with a Clifford.

    The interface also supports the option do_commutative_analysis, which allows to exploit commutativity between gates in order to collect larger blocks of nodes. For example, collecting blocks of CX gates in the following circuit:

    qc = QuantumCircuit(2)
    qc.cx(0, 1)
    qc.z(0)
    qc.cx(1, 0)
    

    using do_commutative_analysis enables consolidating the two CX gates, as the first CX gate and the Z gate commute.

  • Added a new class BlockCollector that implements various collection strategies, and a new class BlockCollapser that implements various collapsing strategies. Currently BlockCollector includes the strategy to greedily collect all gates adhering to a given filter function (for example, collecting all Clifford gates), and BlockCollapser includes the strategy to consolidate all gates in a block to a single object (or example, a block of Clifford gates can be consolidated to a single Clifford).

  • Added a new CollectCliffords transpiler pass that collects blocks of Clifford gates and consolidates these blocks into qiskit.quantum_info.Clifford objects. This pass inherits from CollectAndCollapse and in particular supports the option do_commutative_analysis. It also supports two additional options split_blocks and min_block_size. See the release notes for CollectAndCollapse and CollectLinearFunctions for additional details.

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

    • BasicSynthesisPermutation: applies to fully-connected architectures and is based on sorting. This is the previously used algorithm for constructing quantum circuits for permutations.

    • ACGSynthesisPermutation: applies to fully-connected architectures but is based on the Alon, Chung, Graham method. It synthesizes any permutation in depth 2 (measured in terms of SWAPs).

    • KMSSynthesisPermutation: applies to linear nearest-neighbor architectures and corresponds to the recently added Kutin, Moulton, Smithline method.

    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 new classes for Quantum Fisher Information (QFI) and Quantum Geometric Tensor (QGT) algorithms using primitives, qiskit.algorithms.gradients.QFI and qiskit.algorithms.gradients.LinCombQGT, to the gradients module: qiskit.algorithms.gradients. For example:

    from qiskit.circuit import QuantumCircuit, Parameter
    from qiskit.algorithms.gradients import LinCombQGT, QFI
    
    estimator = Estimator()
    a, b = Parameter("a"), Parameter("b")
    qc = QuantumCircuit(1)
    qc.h(0)
    qc.rz(a, 0)
    qc.rx(b, 0)
    
    parameter_value = [[np.pi / 4, 0]]
    
    qgt = LinCombQGT(estimator)
    qgt_result = qgt.run([qc], parameter_value).result()
    
    qfi = QFI(qgt)
    qfi_result = qfi.run([qc], parameter_value).result()
    
  • Added a new keyword argument, derivative_type, to the constructor for the LinCombEstimatorGradient. This argument takes a DerivativeType enum that enables specifying to compute only the real or imaginary parts of the gradient.

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

    (Source code)

    _images/release_notes-3.png
  • 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 to the GateDirection transpiler pass to handle the the symmetric RXXGate, RYYGate, and RZZGate gates. The pass will now correctly handle these gates and simply reverse the qargs order in place without any other modifications.

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

  • Added a new keyword argument, dtype, to the PauliSumOp.from_list() method. When specified this argument can be used to specify the dtype of the numpy array allocated for the SparsePauliOp used internally by the constructed PauliSumOp.

  • 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
    
    circuit = qasm3.loads("""
      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')
    

    (Source code)

    _images/release_notes-4.png
  • 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
    from qiskit.algorithms.gradients import ReverseEstimatorGradient
    
    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)]
    gradient = ReverseEstimatorGradient()
    
    result = gradient.run([circuit], [observable], [values]).result()
    
  • 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)
    error_map.add_error((0, 0), 0.0024)
    error_map.add_error((0, 1), 0.01)
    error_map.add_error((1, 1), 0.0032)
    

    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)
        error_map.add_error((0, 0), 0.0024)
        error_map.add_error((0, 1), 0.01)
        error_map.add_error((1, 1), 0.0032)
        self.property_set["vf2_avg_error_map"] = error_map
    
    
    target = Target(num_qubits=2)
    target.add_instruction(
        UGate(Parameter('theta'), Parameter('phi'), Parameter('lam')),
        {(0,): None, (1,): None}
    )
    target.add_instruction(
        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.

Upgrade Notes#

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

  • The previously deprecated MSBasisDecomposer transpiler pass available via the qiskit.transpiler.passes module has been removed. It was originally deprecated as part of the Qiskit Terra 0.16.0 release (10-16-2020). Instead the BasisTranslator transpiler pass should be used instead to translate a circuit into an appropriate basis with a RXXGate

  • 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)
    original_lib.add_equivalence(XGate(), qc)
    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)
    original_lib.add_equivalence(SXGate(), qc)
    

    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 QuantumCircuit methods u1, u2, u3, and their controlled variants cu1, cu3 and mcu1 have been removed following their deprecation in Qiskit Terra 0.16.0. This was to remove gate names that were usually IBM-specific, in favour of the more general methods p(), u(), cp() and cu(). The gate classes U1Gate, U2Gate and U3Gate are still available for use with QuantumCircuit.append(), so backends can still support bases with these gates explicitly given.

  • The QuantumCircuit methods combine and extend have been removed following their deprecation in Qiskit Terra 0.17.0. This was done because these functions were simply less powerful versions of QuantumCircuit.compose(), which should be used instead.

    The removal of extend also means that the + and += operators are no longer defined for QuantumCircuit. Instead, you can use the & and &= operators respectively, which use QuantumCircuit.compose().

  • The previously deprecated functions: qiskit.circuit.measure.measure() and qiskit.circuit.reset.reset() have been removed. These functions were deprecated in the Qiskit Terra 0.19.0 release (December, 2021). Instead you should use the QuantumCircuit.measure() and QuantumCircuit.reset() methods of the QuantumCircuit object you wish to append a Measure or Reset operation to.

  • 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 previously deprecated label argument for the constructor of the MCMT and MCMTVChain classes has been removed. It was deprecated as of the Qiskit Terra 0.19.0 release (Decemeber, 2021). Using the label argument on these classes was undefined behavior as they are subclasses of QuantumCircuit instead of Instruction. This would result in the assigned label generally being ignored. If you need to assign a label to an instance of MCMT or MCMTVChain you should convert them to an Gate instance with to_gate() and then assign the desired label to label attribute. For example:

    from qiskit.circuit.library import MCMT, XGate
    
    mcmt_circuit = MCMT(XGate(), 3, 2)
    mcmt_gate = mcmt_circuit.to_gate()
    mcmt_gate.label = "Custom MCMT X"
    
  • 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.

  • RZXCalibrationBuilder and RZXCalibrationBuilderNoEcho transpiler pass have been upgraded to generate ScheduleBlock. This change guarantees the transpiled circuits are always QPY compatible. If you are directly using rescale_cr_inst(), method from another program or a pass subclass to rescale cross resonance pulse of the device, now this method is turned into a pulse builder macro, and you need to use this method within the pulse builder context to adopts to new release. The method call injects a play instruction to the context pulse program, instead of returning a Play instruction with the stretched pulse.

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 :class`WaveformDrawer` 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 output from the run() method of the the BackendSampler class now sets the shots and stddev_upper_bound attributes of the returned QuasiDistribution. Previously these attributes were missing which prevent some post-processing using the output. Fixed #9311

  • 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 reject valid qubit or clbit specifiers. This has been fixed so that the method now accepts the same set of qubit and clbit specifiers as other QuantumCircuit methods, such as append(). Fixed #8691.

  • 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 a regression in the construction of Clifford objects from QuantumCircuits that contain other Clifford objects.

  • 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

  • QuantumCircuit.qasm() will now correctly escape gate and register names that collide with reserved OpenQASM 2 keywords. Fixes #5043.

  • Fixed an issue with the pulse_drawer() where in some cases the output visualization would omit some of the channels in a schedule. Fixed #8981.

Aer 0.11.2#

No change

IBM Q Provider 0.19.2#

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 BackendSampler that raised an error if its run() method was called two times sequentially.

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

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

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

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

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

Aer 0.11.2#

No change

IBM Q Provider 0.19.2#

No change

Qiskit 0.39.4#

Terra 0.22.3#

No change

Aer 0.11.2#

New Features#

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

Known Issues#

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

Bug Fixes#

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

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

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

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

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

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

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

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

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

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

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

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

IBM Q Provider 0.19.2#

No change

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.

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

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

Aer 0.11.1#

No change

IBM Q Provider 0.19.2#

No change

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.

Aer 0.11.1#

No change

IBM Q Provider 0.19.2#

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_list``argument. Now, the argument has been restored but will emit a ``DeprecationWarning when used. If used it has no effect because since Qiskit Terra 0.22.0 a PauliList is always returned.

Bug Fixes#

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

  • 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)
    target.add_instruction(CXGate())
    names = target.operation_names_for_qargs((1, 2))
    ops = target.operations_for_qargs((1, 2))
    

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

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

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

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

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

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

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

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

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

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

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

  • 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 transpile() when targeting a Target (either directly via the target argument or via a BackendV2 instance from the backend argument) that contained an ideal Measure instruction (one that does not have any properties defined). Previously this would raise an exception trying to parse the target. Fixed #8969

  • 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

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

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

IBM Q Provider 0.19.2#

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

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

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

    both return True.

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

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

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

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

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

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

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

    from qiskit import QuantumCircuit
    
    circuit = QuantumCircuit(2)
    circuit.h(0)
    circuit.h(1)
    circuit.barrier(label="After H")
    circuit.draw('mpl')
    
  • 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
    
  • The Grover class has a new keyword argument, sampler which is used to run the algorithm using an instance of the BaseSampler interface to calculate the results. This new argument supersedes the the quantum_instance argument and accordingly, quantum_instance is pending deprecation and will be deprecated and subsequently removed in future releases.

    Example:

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

    For example:

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

    from qiskit import QuantumCircuit
    from qiskit.transpiler.passes import ResetAfterMeasureSimplification
    
    qc = QuantumCircuit(1)
    qc.measure_all()
    qc.reset(0)
    qc.draw('mpl')
    
    result = ResetAfterMeasureSimplification()(qc)
    result.draw('mpl')
    
  • Added a new supported value, "reverse_linear" for the entanglement keyword argument to the constructor for the NLocal circuit class. For TwoLocal circuits (which are subclassess of NLocal), if entanglement_blocks="cx" then using entanglement="reverse_linear" provides an equivalent n-qubit circuit as entanglement="full" but with only \(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)