Qiskit 0.35 release notes
0.35.0
Terra 0.20.0
Prelude
The Qiskit Terra 0.20.0 release highlights are:
- The introduction of multithreaded modules written in Rust to accelerate the performance of certain portions of Qiskit Terra and improve scaling with larger numbers of qubits. However, when building Qiskit from source a Rust compiler is now required.
- More native support for working with a
Target
in the transpiler. Several passes now support working directly with aTarget
object which makes the transpiler robust in the types of backends it can target. - The introduction of the
qiskit.primitives
module. These APIs provide different abstraction levels for computing outputs of interest fromQuantumCircuit
and using backends. For example, theBaseEstimator
defines an abstract interface for estimating an expectation value of an observable. This can then be used to construct higher level algorithms and applications that are built using the estimation of expectation values without having to worry about the implementation of computing the expectation value. This decoupling allows the implementation to improve in speed and quality while adhering to the defined abstract interface. Likewise, theBaseSampler
computes quasi-probability distributions from circuit measurements. Other primitives will be introduced in the future.
This release no longer has support for Python 3.6. With this release, Python 3.7 through Python 3.10 are required.
New Features
-
Added a new constructor method for the
Operator
class,Operator.from_circuit()
for creating a newOperator
object from aQuantumCircuit
. While this was possible normally using the default constructor, theOperator.from_circuit()
method provides additional options to adjust how the operator is created. Primarily this lets you permute the qubit order based on a setLayout
. For, example:from qiskit.circuit import QuantumCircuit from qiskit import transpile from qiskit.transpiler import CouplingMap from qiskit.quantum_info import Operator circuit = QuantumCircuit(3) circuit.h(0) circuit.cx(0, 1) circuit.cx(1, 2) cmap = CouplingMap.from_line(3) out_circuit = transpile(circuit, initial_layout=[2, 1, 0], coupling_map=cmap) operator = Operator.from_circuit(out_circuit)
the
operator
variable will have the qubits permuted based on the layout so that it is identical to what is returned byOperator(circuit)
before transpilation. -
Added a new method
DAGCircuit.copy_empty_like()
to theDAGCircuit
class. This method is used to create a new copy of an existingDAGCircuit
object with the same structure but empty of any instructions. This method is the same as the private method_copy_circuit_metadata()
, but instead is now part of the public API of the class. -
The fake backend and fake provider classes which were previously available in
qiskit.test.mock
are now also accessible in a new module:qiskit.providers.fake_provider
. This new module supersedes the previous moduleqiskit.test.mock
which will be deprecated in Qiskit 0.21.0. -
Added a new gate class,
LinearFunction
, that efficiently encodes a linear function (i.e. a function that can be represented by a sequence ofCXGate
andSwapGate
gates). -
Added a new transpiler pass
CollectLinearFunctions
that collects blocks of consecutiveCXGate
andSwapGate
gates in a circuit, and replaces each block with aLinearFunction
gate. -
Added a new transpiler pass
LinearFunctionsSynthesis
that synthesizes anyLinearFunction
gates in using the Patel-Markov-Hayes algorithm. When combined with theCollectLinearFunctions
transpiler pass this enables to collect blocks of consecutiveCXGate
andSwapGate
gates in a circuit, and re-synthesize them using the Patel-Markov-Hayes algorithm. -
Added a new transpiler pass
LinearFunctionsToPermutations
that replaces aLinearFunction
gate by aPermutation
circuit whenever possible. -
FlowController
classes (such asConditionalController
) can now be nested inside aPassManager
instance when using thePassManager.append()
method. This enables the use of nested logic to control the execution of passes in thePassManager
. For example:from qiskit.transpiler import ConditionalController, PassManager from qiskit.transpiler.passes import ( BasisTranslator, GatesInBasis, Optimize1qGatesDecomposition, FixedPoint, Depth ) from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel pm = PassManager() def opt_control(property_set): return not property_set["depth_fixed_point"] def unroll_condition(property_set): return not property_set["all_gates_in_basis"] depth_check = [Depth(), FixedPoint("depth")] opt = [Optimize1qGatesDecomposition(['rx', 'ry', 'rz', 'rxx'])] unroll = [BasisTranslator(sel, ['rx', 'ry', 'rz', 'rxx'])] unroll_check = [GatesInBasis(['rx', 'ry', 'rz', 'rxx'])] flow_unroll = [ConditionalController(unroll, condition=unroll_condition)] pm.append(depth_check + opt + unroll_check + flow_unroll, do_while=opt_control)
The
pm
PassManager
object will only execute theBasisTranslator
pass (in theunroll
step) in each loop iteration if theunroll_condition
is met. -
The constructors for the
ZFeatureMap
andZZFeatureMap
classes have a new keyword argumentparameter_prefix
. This new argument is used to set the prefix of parameters of the data encoding circuit. For example:from qiskit.circuit.library import ZFeatureMap feature_map = ZFeatureMap(feature_dimension=4, parameter_prefix="my_prefix") feature_map.decompose().draw('mpl')
the generated
ZFeatureMap
circuit has prefixed all its internal parameters with the prefix"my_prefix"
. -
The
TemplateOptimization
transpiler pass can now work withGate
objects that haveParameterExpression
parameters. An illustrative example of usingParameter
s withTemplateOptimization
is the following:from qiskit import QuantumCircuit, transpile, schedule from qiskit.circuit import Parameter from qiskit.transpiler import PassManager from qiskit.transpiler.passes import TemplateOptimization # New contributions to the template optimization from qiskit.transpiler.passes.calibration import RZXCalibrationBuilder, rzx_templates from qiskit.test.mock import FakeCasablanca backend = FakeCasablanca() phi = Parameter('φ') qc = QuantumCircuit(2) qc.cx(0,1) qc.p(2*phi, 1) qc.cx(0,1) print('Original circuit:') print(qc) pass_ = TemplateOptimization(**rzx_templates.rzx_templates(['zz2'])) qc_cz = PassManager(pass_).run(qc) print('ZX based circuit:') print(qc_cz) # Add the calibrations pass_ = RZXCalibrationBuilder(backend) cal_qc = PassManager(pass_).run(qc_cz.bind_parameters({phi: 0.12})) # Transpile to the backend basis gates cal_qct = transpile(cal_qc, backend) qct = transpile(qc.bind_parameters({phi: 0.12}), backend) # Compare the schedule durations print('Duration of schedule with the calibration:') print(schedule(cal_qct, backend).duration) print('Duration of standard with two CNOT gates:') print(schedule(qct, backend).duration)
outputs
Original circuit: q_0: ──■──────────────■── ┌─┴─┐┌────────┐┌─┴─┐ q_1: ┤ X ├┤ P(2*φ) ├┤ X ├ └───┘└────────┘└───┘ ZX based circuit: ┌─────────────┐ » q_0: ────────────────────────────────────┤0 ├────────────» ┌──────────┐┌──────────┐┌──────────┐│ Rzx(2.0*φ) │┌──────────┐» q_1: ┤ Rz(-π/2) ├┤ Rx(-π/2) ├┤ Rz(-π/2) ├┤1 ├┤ Rx(-2*φ) ├» └──────────┘└──────────┘└──────────┘└─────────────┘└──────────┘» « «q_0: ──────────────────────────────────────────────── « ┌──────────┐┌──────────┐┌──────────┐┌──────────┐ «q_1: ┤ Rz(-π/2) ├┤ Rx(-π/2) ├┤ Rz(-π/2) ├┤ P(2.0*φ) ├ « └──────────┘└──────────┘└──────────┘└──────────┘ Duration of schedule with the calibration: 1600 Duration of standard with two CNOT gates: 6848
-
The
DAGOpNode
,DAGInNode
andDAGOutNode
classes now define a custom__repr__
method which outputs a representation. Per the Python documentation the output is a string representation that is roughly equivalent to the Python string used to create an equivalent object. -
The performance of the
SparsePauliOp.simplify()
method has greatly improved by replacing the use ofnumpy.unique
to compute unique elements of an array by a new similar function implemented in Rust that doesn’t pre-sort the array. -
Added a new method
equiv()
to theSparsePauliOp
class for testing the equivalence of aSparsePauliOp
with anotherSparsePauliOp
object. Unlike the==
operator which compares operators element-wise,equiv()
compares whether two operators are equivalent or not. For example:op = SparsePauliOp.from_list([("X", 1), ("Y", 1)]) op2 = SparsePauliOp.from_list([("X", 1), ("Y", 1), ("Z", 0)]) op3 = SparsePauliOp.from_list([("Y", 1), ("X", 1)]) print(op == op2) # False print(op == op3) # False print(op.equiv(op2)) # True print(op.equiv(op3)) # True
-
Added new fake backend classes from snapshots of the IBM Quantum systems based on the
BackendV2
interface and provided aTarget
for each backend.BackendV2
based versions of all the existing backends are added except for three old backendsFakeRueschlikon
,FakeTenerife
andFakeTokyo
as they do not have snapshots files available which are required for creating a new fake backend class based onBackendV2
.These new V2 fake backends will enable testing and development of new features introduced by
BackendV2
andTarget
such as improving the transpiler. -
Added a new gate class
XXMinusYYGate
to the circuit library (qiskit.circuit.library
) for the XX-YY interaction. This gate can be used to implement the bSwap gate and its powers. It also arises in the simulation of superconducting fermionic models. -
Added new gate class,
XXPlusYYGate
, to the circuit library (qiskit.circuit.library
). This gate is a 2-qubit parameterized XX+YY interaction, also known as an XY gate, and is based on the gate described in https://arxiv.org/abs/1912.04424. -
The
FakeBogota
,FakeManila
,FakeRome
, andFakeSantiago
fake backends which can be found in theqiskit.providers.fake_provider
module can now be used as backends in Pulse experiments as they now include aPulseDefaults
created from a snapshot of the equivalent IBM Quantum machine’s properties. -
The
ConsolidateBlocks
pass has a new keyword argument on its constructor,target
. This argument is used to specify aTarget
object representing the compilation target for the pass. If it is specified it supersedes thebasis_gates
kwarg. If a target is specified, the pass will respect the gates and qubits for the instructions defined in theTarget
when deciding which gates to consolidate into a unitary. -
The
Target
class has a new method,instruction_supported()
which is used to query the target to see if an instruction (the combination of an operation and the qubit(s) it is executed on) is supported on the backend modelled by theTarget
. -
Added a new kwarg,
metadata_serializer
, to theqpy.dump()
function for specifying a customJSONEncoder
subclass for use when serializing theQuantumCircuit.metadata
attribute and a dual kwargmetadata_deserializer
to theqpy.load()
function for specifying aJSONDecoder
subclass. By default thedump()
andload()
functions will attempt to JSON serialize and deserialize with the stdlib default json encoder and decoder. SinceQuantumCircuit.metadata
can contain any Python dictionary, even those with contents not JSON serializable by the default encoder, will lead to circuits that can’t be serialized. The newmetadata_serializer
argument fordump()
enables users to specify a customJSONEncoder
that will be used with the internaljson.dump()
call for serializing theQuantumCircuit.metadata
dictionary. This can then be paired with the newmetadata_deserializer
argument of theqpy.load()
function to decode those custom JSON encodings. Ifmetadata_serializer
is specified ondump()
butmetadata_deserializer
is not specified onload()
calls the QPY will be loaded, but the circuit metadata may not be reconstructed fully.For example if you wanted to define a custom serialization for metadata and then load it you can do something like:
from qiskit.qpy import dump, load from qiskit.circuit import QuantumCircuit, Parameter import json import io class CustomObject: """Custom string container object.""" def __init__(self, string): self.string = string def __eq__(self, other): return self.string == other.string class CustomSerializer(json.JSONEncoder): """Custom json encoder to handle CustomObject.""" def default(self, o): if isinstance(o, CustomObject): return {"__type__": "Custom", "value": o.string} return json.JSONEncoder.default(self, o) class CustomDeserializer(json.JSONDecoder): """Custom json decoder to handle CustomObject.""" def __init__(self, *args, **kwargs): super().__init__(*args, object_hook=self.object_hook, **kwargs) def object_hook(self, o): """Hook to override default decoder.""" if "__type__" in o: obj_type = o["__type__"] if obj_type == "Custom": return CustomObject(o["value"]) return o theta = Parameter("theta") qc = QuantumCircuit(2, global_phase=theta) qc.h(0) qc.cx(0, 1) qc.measure_all() circuits = [qc, qc.copy()] circuits[0].metadata = {"key": CustomObject("Circuit 1")} circuits[1].metadata = {"key": CustomObject("Circuit 2")} with io.BytesIO() as qpy_buf: dump(circuits, qpy_buf, metadata_serializer=CustomSerializer) qpy_buf.seek(0) new_circuits = load(qpy_buf, metadata_deserializer=CustomDeserializer)
-
The
DenseLayout
pass has a new keyword argument on its constructor,target
. This argument is used to specify aTarget
object representing the compilation target for the pass. If it is specified it supersedes the other arguments on the constructor,coupling_map
andbackend_prop
. -
The
Target
class has a new method,operation_names_for_qargs()
. This method is used to get the operation names (i.e. lookup key in the target) for the operations on a givenqargs
tuple. -
A new pass
DynamicalDecouplingPadding
has been added to theqiskit.transpiler.passes
module. This new pass supersedes the existingDynamicalDecoupling
pass to work with the new scheduling workflow in the transpiler. It is a subclass of theBasePadding
pass and depends on having scheduling and alignment analysis passes run prior to it in aPassManager
. This new pass can take apulse_alignment
argument which represents a hardware constraint for waveform start timing. The spacing between gates comprising a dynamical decoupling sequence is now adjusted to satisfy this constraint so that the circuit can be executed on hardware with the constraint. This value is usually found inBackendConfiguration.timing_constraints
. Additionally the pass also has anextra_slack_distribution
option has been to control how to distribute the extra slack when the duration of the created dynamical decoupling sequence is shorter than the idle time of your circuit that you want to fill with the sequence. This defaults tomiddle
which is identical to conventional behavior. The new strategysplit_edges
evenly divide the extra slack into the beginning and end of the sequence, rather than adding it to the interval in the middle of the sequence. This might result in better noise cancellation especially whenpulse_alignment
> 1. -
The
Z2Symmetries
class now exposes the threshold tolerances used to chop small real and imaginary parts of coefficients. With this one can control how the coefficients of the tapered operator are simplified. For example:from qiskit.opflow import Z2Symmetries from qiskit.quantum_info import Pauli z2_symmetries = Z2Symmetries( symmetries=[Pauli("IIZI"), Pauli("IZIZ"), Pauli("ZIII")], sq_paulis=[Pauli("IIXI"), Pauli("IIIX"), Pauli("XIII")], sq_list=[1, 0, 3], tapering_values=[1, -1, -1], tol=1e-10, )
By default, coefficients are chopped with a tolerance of
tol=1e-14
. -
Added a
chop()
method to theSparsePauliOp
class that truncates real and imaginary parts of coefficients individually. This is different from theSparsePauliOp.simplify()
method which removes a coefficient only if the absolute value is close to 0. For example:>>> from qiskit.quantum_info import SparsePauliOp >>> op = SparsePauliOp(["X", "Y", "Z"], coeffs=[1+1e-17j, 1e-17+1j, 1e-17]) >>> op.simplify() SparsePauliOp(['X', 'Y'], coeffs=[1.e+00+1.e-17j, 1.e-17+1.e+00j]) >>> op.chop() SparsePauliOp(['X', 'Y'], coeffs=[1.+0.j, 0.+1.j])
Note that the chop method does not accumulate the coefficents of the same Paulis, e.g.
>>> op = SparsePauliOp(["X", "X"], coeffs=[1+1e-17j, 1e-17+1j) >>> op.chop() SparsePauliOp(['X', 'X'], coeffs=[1.+0.j, 0.+1.j])
-
Added a new kwarg,
target
, to the constructor for theGatesInBasis
transpiler pass. This new argument can be used to optionally specify aTarget
object that represents the backend. When set thisTarget
will be used for determining whether aDAGCircuit
contains gates outside the basis set and thebasis_gates
argument will not be used. -
Added partial support for running on ppc64le and s390x Linux platforms. This release will start publishing pre-compiled binaries for ppc64le and s390x Linux platforms on all Python versions. However, unlike other supported platforms not all of Qiskit’s upstream dependencies support these platforms yet. So a C/C++ compiler may be required to build and install these dependencies and a simple
pip install qiskit-terra
with just a working Python environment will not be sufficient to install Qiskit. Additionally, these same constraints prevent us from testing the pre-compiled wheels before publishing them, so the same guarantees around platform support that exist for the other platforms don’t apply here. -
The
Gradient
andQFI
classes can now calculate the imaginary part of expectation value gradients. When using a different measurement basis, i.e.-Y
instead ofZ
, we can measure the imaginary part of gradients The measurement basis can be set with theaux_meas_op
argument.For the gradients,
aux_meas_op = Z
computes0.5Re[(⟨ψ(ω)|)O(θ)|dωψ(ω)〉]
andaux_meas_op = -Y
computes0.5Im[(⟨ψ(ω)|)O(θ)|dωψ(ω)〉]
. For the QFIs,aux_meas_op = Z
computes4Re[(dω⟨<ψ(ω)|)(dω|ψ(ω)〉)]
andaux_meas_op = -Y
computes4Im[(dω⟨<ψ(ω)|)(dω|ψ(ω)〉)]
. For example:from qiskit import QuantumRegister, QuantumCircuit from qiskit.opflow import CircuitStateFn, Y from qiskit.opflow.gradients.circuit_gradients import LinComb from qiskit.circuit import Parameter a = Parameter("a") b = Parameter("b") params = [a, b] q = QuantumRegister(1) qc = QuantumCircuit(q) qc.h(q) qc.rz(params[0], q[0]) qc.rx(params[1], q[0]) op = CircuitStateFn(primitive=qc, coeff=1.0) aux_meas_op = -Y prob_grad = LinComb(aux_meas_op=aux_meas_op).convert(operator=op, params=params)
-
The
InstructionDurations
class now has support for working with parameters of an instruction. Each entry in anInstructionDurations
object now consists of a tuple of(inst_name, qubits, duration, parameters, unit)
. This enables anInstructionDurations
to define durations for an instruction given a certain parameter value to account for different durations with different parameter values on an instruction that takes a numeric parameter. -
Added a new value for the
style
keyword argument on the circuit drawer functioncircuit_drawer()
andQuantumCircuit.draw()
method,iqx_dark
. Whenstyle
is set toiqx_dark
with thempl
drawer backend, the output visualization will use a color scheme similar to the the dark mode color scheme used by the IBM Quantum composer. For example:from qiskit.circuit import QuantumCircuit from matplotlib.pyplot import show circuit = QuantumCircuit(2) circuit.h(0) circuit.cx(0, 1) circuit.p(0.2, 1) circuit.draw("mpl", style="iqx-dark")
-
Several lazy dependency checkers have been added to the new module
qiskit.utils.optionals
, which can be used to query if certain Qiskit functionality is available. For example, you can ask if Qiskit has detected the presence ofmatplotlib
by askingif qiskit.utils.optionals.HAS_MATPLOTLIB
. These objects only attempt to import their dependencies when they are queried, so you can use them in runtime code without affecting import time. -
Import time for
qiskit
has been significantly improved, especially for those with many of Qiskit Terra’s optional dependencies installed. -
The
marginal_counts()
function now supports marginalizing thememory
field of an inputResult
object. For example, if the inputresult
argument is a qiskitResult
object obtained from a 4-qubit measurement we can marginalize onto the first qubit with:print(result.results[0].data.memory) marginal_result = marginal_counts(result, [0]) print(marginal_result.results[0].data.memory)
The output is:
['0x0', '0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7'] ['0x0', '0x1', '0x0', '0x1', '0x0', '0x1', '0x0', '0x1']
-
The internals of the
StochasticSwap
algorithm have been reimplemented to be multithreaded and are now written in the Rust programming language instead of Cython. This significantly increases the run time performance of the compiler pass and by extensiontranspile()
when run withoptimization_level
0, 1, and 2. By default the pass will use up to the number of logical CPUs on your local system but you can control the number of threads used by the pass by setting theRAYON_NUM_THREADS
environment variable to an integer value. For example, settingRAYON_NUM_THREADS=4
will run theStochasticSwap
with 4 threads. -
A new environment variable
QISKIT_FORCE_THREADS
is available for users to directly control whether potentially multithreaded portions of Qiskit’s code will run in multiple threads. Currently this is only used by theStochasticSwap
transpiler pass but it likely will be used other parts of Qiskit in the future. When this env variable is set toTRUE
any multithreaded code in Qiskit Terra will always use multiple threads regardless of any other runtime conditions that might have otherwise caused the function to use a single threaded variant. For example, inStochasticSwap
if the pass is being run as part of atranspile()
call with > 1 circuit that is being executed in parallel withmultiprocessing
viaparallel_map()
theStochasticSwap
will not use multiple threads to avoid potentially oversubscribing CPU resources. However, if you’d like to use multiple threads in the pass along with multiple processes you can setQISKIT_FORCE_THREADS=TRUE
. -
New fake backend classes are available under
qiskit.providers.fake_provider
. These include mocked versions ofibm_cairo
,ibm_hanoi
,ibmq_kolkata
,ibm_nairobi
, andibm_washington
. As with the other fake backends, these include snapshots of calibration and error data taken from the real system, and can be used for local testing, compilation and simulation. -
Introduced a new class
StatePreparation
. This class allows users to prepare a desired state in the same fashion asInitialize
without the reset being automatically applied.For example, to prepare a qubit in the state :
import numpy as np from qiskit import QuantumCircuit circuit = QuantumCircuit(1) circuit.prepare_state([1/np.sqrt(2), -1/np.sqrt(2)], 0) circuit.draw()
The output is as:
┌─────────────────────────────────────┐ q_0: ┤ State Preparation(0.70711,-0.70711) ├ └─────────────────────────────────────┘
-
The
Optimize1qGates
transpiler pass now has support for optimizingU1Gate
,U2Gate
, andPhaseGate
gates with unbound parameters in a circuit. Previously, if these gates had unbound parameters the pass would not use them. For example:from qiskit import QuantumCircuit from qiskit.circuit import Parameter from qiskit.transpiler import PassManager from qiskit.transpiler.passes import Optimize1qGates, Unroller phi = Parameter('φ') alpha = Parameter('α') qc = QuantumCircuit(1) qc.u1(2*phi, 0) qc.u1(alpha, 0) qc.u1(0.1, 0) qc.u1(0.2, 0) pm = PassManager([Unroller(['u1', 'cx']), Optimize1qGates()]) nqc = pm.run(qc)
will be combined to the circuit with only one single-qubit gate:
qc = QuantumCircuit(1) qc.u1(2*phi + alpha + 0.3, 0)
-
The methods
Pauli.evolve()
andPauliList.evolve()
now have a new keyword argument,frame
, which is used to perform an evolution of a Pauli by a Clifford. Ifframe='h'
(default) then it does the Heisenberg picture evolution of a Pauli by a Clifford (), and ifframe='s'
then it does the Schrödinger picture evolution of a Pauli by a Clifford (). The latter option yields a faster calculation, and is also useful in certain cases. This new option makes the calculation of the greedy Clifford decomposition method indecompose_clifford
significantly faster. -
Added a new module to Qiskit:
qiskit.primitives
. The primitives module is where APIs are defined which provide different abstractions around computing certain common functions fromQuantumCircuit
which abstracts away the details of the underlying execution on aBackend
. This enables higher level algorithms and applications to concentrate on performing the computation and not need to worry about the execution and processing of results and have a standardized interface for common computations. For example, estimating an expectation value of a quantum circuit and observable can be performed by any class implementing theBaseEstimator
class and consumed in a standardized manner regardless of the underlying implementation. Applications can then be written using the primitive interface directly.To start the module contains two types of primitives, the
Sampler
(seeBaseSampler
for the abstract class definition) andEstimator
(seeBaseEstimator
for the abstract class definition). Reference implementations are included in theqiskit.primitives
module and are built using theqiskit.quantum_info
module which perform ideal simulation of primitive operation. The expectation is that provider packages will offer their own implementations of these interfaces for providers which can efficiently implement the protocol natively (typically using a classical runtime). Additionally, in the future for providers which do not offer a native implementation of the primitives a method will be provided which will enable constructing primitive objects from aBackend
. -
Added a new module,
qiskit.qpy
, which contains the functionality previously exposed inqiskit.circuit.qpy_serialization
. The public functions previously exposed atqiskit.circuit.qpy_serialization
,dump()
andload()
are now available from this new module (although they are still accessible fromqiskit.circuit.qpy_serialization
but this will be deprecated in a future release). This new module was added in the interest of the future direction of the QPY file format, which in future versions will support representingpulse
Schedule
andScheduleBlock
objects in addition to theQuantumCircuit
objects it supports today. -
Added a new attribute,
qubit_properties
to theTarget
class. This attribute contains a list ofQubitProperties
objects for each qubit in the target. For example:target.qubit_properties[2]
will contain the
QubitProperties
for qubit number 2 in the target.For
BackendV2
authors, if you were previously definingQubitProperties
directly on yourBackendV2
implementation by overridingBackendV2.qubit_properties()
this will still work fine. However, if you do move the definition to the underlyingTarget
object and remove the specializedBackendV2.qubit_properties()
implementation which will enable using qubit properties in the transpiler and also maintain API compatibility with your previous implementation. -
Added a new function,
qiskit.algorithms.eval_observables()
, which is used to evaluate observables given a boundQuantumCircuit
. It originates from a private method,_eval_aux_ops()
, of theqiskit.algorithms.VQE
class but the neweval_observables()
function is now more general so that it can be used in other algorithms, for example time evolution algorithms. -
The basis search strategy in
BasisTranslator
transpiler pass has been modified into a variant of Dijkstra search which greatly improves the runtime performance of the pass when attempting to target an unreachable basis. -
The
DenseLayout
transpiler pass is now multithreaded, which greatly improves the runtime performance of the pass. By default, it will use the number of logical CPUs on your local system, but you can control the number of threads used by the pass by setting theRAYON_NUM_THREADS
environment variable to an integer value. For example, settingRAYON_NUM_THREADS=4
will run theDenseLayout
pass with 4 threads. -
The internal computations of
Statevector.expectation_value()
andDensityMatrix.expectation_value()
methods have been reimplemented in the Rust programming language. This new implementation is multithreaded and by default for aStatevector
orDensityMatrix
>= 19 qubits will spawn a thread pool with the number of logical CPUs available on the local system. You can you can control the number of threads used by setting theRAYON_NUM_THREADS
environment variable to an integer value. For example, settingRAYON_NUM_THREADS=4
will only use 4 threads in the thread pool. -
Added a new
SparsePauliOp.from_sparse_list()
constructor that takes an iterable, where the elements represent Pauli terms that are themselves sparse, so that"XIIIIIIIIIIIIIIIX"
can now be written as("XX", [0, 16])
. For example, the operatorcan now be constructed as
op = SparsePauliOp.from_sparse_list([("XZ", [0, 3], 1), ("YY", [1, 4], 2)], num_qubits=5) # or equivalently, as previously op = SparsePauliOp.from_list([("IZIIX", 1), ("YIIYI", 2)])
This facilitates the construction of very sparse operators on many qubits, as is often the case for Ising Hamiltonians.
-
The
UnitarySynthesis
transpiler pass has a new keyword argument on its constructor,target
. This can be used to optionally specify aTarget
object which represents the compilation target for the pass. When it’s specified it will supersede the values set forbasis_gates
,coupling_map
, andbackend_props
. -
The
UnitarySynthesisPlugin
abstract plugin class has a new optional attribute implementations can add,supports_target
. If a plugin has this attribute set toTrue
aTarget
object will be passed in theoptions
payload under thetarget
field. The expectation is that thisTarget
object will be used in place ofcoupling_map
,gate_lengths
,basis_gates
, andgate_errors
. -
Introduced a new transpiler pass workflow for building
PassManager
objects for schedulingQuantumCircuit
objects in the transpiler. In the new workflow scheduling and alignment passes are allAnalysisPass
objects that only update the property set of the pass manager, specifically new property set itemnode_start_time
, which holds the absolute start time of each opnode. A separateTransformationPass
such asPadDelay
is subsequently used to apply scheduling to the DAG. This new workflow is both more efficient and can correct for additional timing constraints exposed by a backend.Previously, the pass chain would have been implemented as
scheduling -> alignment
which were both transform passes thus there were multipleDAGCircuit
instances recreated during each pass. In addition, scheduling occured in each pass to obtain instruction start time. Now the required pass chain becomesscheduling -> alignment -> padding
where theDAGCircuit
update only occurs at the end with thepadding
pass.For those who are creating custom
PassManager
objects that involve circuit scheduling you will need to adjust yourPassManager
to insert one of theBasePadding
passes (currently eitherPadDelay
orPadDynamicalDecoupling
can be used) at the end of the scheduling pass chain. Without the padding pass the scheduling passes will not be reflected in the output circuit of therun()
method of your customPassManager
.For example, if you were previously building your
PassManager
with something like:from qiskit.transpiler import PassManager from qiskit.transpiler.passes import TimeUnitConversion, ALAPSchedule, ValidatePulseGates, AlignMeasures pm = PassManager() scheduling = [ ALAPSchedule(instruction_durations), PadDelay()), ValidatePulseGates(granularity=timing_constraints.granularity, min_length=timing_constraints.min_length), AlignMeasures(alignment=timing_constraints.acquire_alignment), ] pm.append(scheduling)
you can instead use:
from qiskit.transpiler import PassManager from qiskit.transpiler.passes import TimeUnitConversion, ALAPScheduleAnalysis, ValidatePulseGates, AlignMeasures, PadDelay pm = PassManager() scheduling = [ ALAPScheduleAnalysis(instruction_durations), PadDelay()), ConstrainedReschedule(acquire_alignment=timing_constraints.acquire_alignment, pulse_alignment=timing_constraints.pulse_alignment), ValidatePulseGates(granularity=timing_constraints.granularity, min_length=timing_constraints.min_length), PadDelay() ] pm.append(scheduling)
which will both be more efficient and also align instructions based on any hardware constraints.
-
Added a new transpiler pass
ConstrainedReschedule
pass. TheConstrainedReschedule
pass considers both hardware alignment constraints that can be definied in aBackendConfiguration
object,pulse_alignment
andacquire_alignment
. This new class supersedes the previosuly existingAlignMeasures
as it performs the same alignment (via the property set) for measurement instructions in addition to general instruction alignment. By setting theacquire_alignment
constraint argument for theConstrainedReschedule
pass it is a drop-in replacement ofAlignMeasures
when paired with a newBasePadding
pass. -
Added two new transpiler passes
ALAPScheduleAnalysis
andASAPScheduleAnalysis
which superscede theALAPSchedule
andASAPSchedule
as part of the reworked transpiler workflow for schedling. The new passes perform the same scheduling but in the property set and relying on aBasePadding
pass to adjust the circuit based on all the scheduling alignment analysis.The standard behavior of these passes also aligns timing ordering with the topological ordering of the DAG nodes. This change may affect the scheduling outcome if it includes conditional operations, or simultaneously measuring two qubits with the same classical register (edge-case). To reproduce conventional behavior, set
clbit_write_latency
identical to the measurement instruction length.For example, consider scheduling an input circuit like:
┌───┐┌─┐ q_0: ┤ X ├┤M├────────────── └───┘└╥┘ ┌───┐ q_1: ──────╫────┤ X ├────── ║ └─╥─┘ ┌─┐ q_2: ──────╫──────╫─────┤M├ ║ ┌────╨────┐└╥┘ c: 1/══════╩═╡ c_0=0x1 ╞═╩═ 0 └─────────┘ 0
from qiskit import QuantumCircuit from qiskit.transpiler import InstructionDurations, PassManager from qiskit.transpiler.passes import ALAPScheduleAnalysis, PadDelay, SetIOLatency from qiskit.visualization.timeline import draw circuit = QuantumCircuit(3, 1) circuit.x(0) circuit.measure(0, 0) circuit.x(1).c_if(0, 1) circuit.measure(2, 0) durations = InstructionDurations([("x", None, 160), ("measure", None, 800)]) pm = PassManager( [ SetIOLatency(clbit_write_latency=800, conditional_latency=0), ALAPScheduleAnalysis(durations), PadDelay(), ] ) draw(pm.run(circuit))
As you can see in the timeline view, the measurement on
q_2
starts before the conditional X gate on theq_1
, which seems to be opposite to the topological ordering of the node. This is also expected behavior because clbit write-access happens at the end edge of the measure instruction, and the read-access of the conditional gate happens the begin edge of the instruction. Thus topological ordering is preserved on the timeslot of the classical register, which is not captured by the timeline view. However, this assumes a paticular microarchitecture design, and the circuit is not necessary scheduled like this.By using the default configuration of passes, the circuit is schedule like below.
from qiskit import QuantumCircuit from qiskit.transpiler import InstructionDurations, PassManager from qiskit.transpiler.passes import ALAPScheduleAnalysis, PadDelay from qiskit.visualization.timeline import draw circuit = QuantumCircuit(3, 1) circuit.x(0) circuit.measure(0, 0) circuit.x(1).c_if(0, 1) circuit.measure(2, 0) durations = InstructionDurations([("x", None, 160), ("measure", None, 800)]) pm = PassManager([ALAPScheduleAnalysis(durations), PadDelay()]) draw(pm.run(circuit))
Note that clbit is locked throughout the measurement instruction interval. This behavior is designed based on the Qiskit Pulse, in which the acquire instruction takes
AcquireChannel
andMemorySlot
which are not allowed to overlap with other instructions, i.e. simultaneous memory access from the different instructions is prohibited. This also always aligns the timing ordering with the topological node ordering. -
Added a new transpiler pass
PadDynamicalDecoupling
which supersedes theDynamicalDecoupling
pass as part of the reworked transpiler workflow for scheduling. This new pass will insert dynamical decoupling sequences into the circuit per any scheduling and alignment analysis that occured in earlier passes. -
The
plot_gate_map()
visualization function and the functions built on top of it,plot_error_map()
andplot_circuit_layout()
, have a new keyword argument,qubit_coordinates
. This argument takes a sequence of 2D coordinates to use for plotting each qubit in the backend being visualized. If specified this sequence must have a length equal to the number of qubits on the backend and it will be used instead of the default behavior. -
The
plot_gate_map()
visualization function and the functions built on top of it,plot_error_map()
andplot_circuit_layout()
, now are able to plot any backend not just those with the number of qubits equal to one of the IBM backends. This relies on the retworkxspring_layout()
function to generate the layout for the visualization. If the default layout doesn’t work with a backend’s particular coupling graph you can use thequbit_coordinates
function to set a custom layout. -
The
plot_gate_map()
visualization function and the functions built on top of it,plot_error_map()
andplot_circuit_layout()
, are now able to function with aBackendV2
based backend. Previously, these functions only worked withBaseBackend
orBackendV1
based backends. -
Added a new transpiler pass,
SetIOLatency
. This pass takes two argumentsclbit_write_latency
andconditional_latency
to define the I/O latency for classical bits and classical conditions on a backend. This pass will then define these values on the pass manager’s property set to enable subsequent scheduling and alignment passes to correct for these latencies and provide a more presice scheduling output of a dynamic circuit. -
A new transpiler pass
PadDelay
has been added. This pass fills idle time on the qubit wires withDelay
instructions. This pass is part of the new workflow for scheduling passes in the transpiler and depends on a scheduling analysis pass (such asALAPScheduleAnalysis
orASAPScheduleAnalysis
) and any alignment passes (such asConstrainedReschedule
) to be run prior toPadDelay
. -
The
VF2Layout
transpiler pass has a new keyword argument,target
which is used to provide aTarget
object for the pass. When specified, theTarget
will be used by the pass for all information about the target device. If it is specified, thetarget
option will take priority over thecoupling_map
andproperties
arguments. -
Allow callables as optimizers in
VQE
andQAOA
. Now, the optimizer can either be one of Qiskit’s optimizers, such asSPSA
or a callable with the following signature:from qiskit.algorithms.optimizers import OptimizerResult def my_optimizer(fun, x0, jac=None, bounds=None) -> OptimizerResult: # Args: # fun (callable): the function to minimize # x0 (np.ndarray): the initial point for the optimization # jac (callable, optional): the gradient of the objective function # bounds (list, optional): a list of tuples specifying the parameter bounds result = OptimizerResult() result.x = # optimal parameters result.fun = # optimal function value return result
The above signature also allows to directly pass any SciPy minimizer, for instance as
from functools import partial from scipy.optimize import minimize optimizer = partial(minimize, method="L-BFGS-B")
Known Issues
- When running
parallel_map()
(which is done internally by performance sensitive functions such astranspile()
andassemble()
) in a subprocess launched outside ofparallel_map()
, it is possible that the parallel dispatch performed insideparallel_map()
will hang and never return. This is due to upstream issues in CPython around the default method to launch subprocesses on Linux and macOS with Python 3.7 (see https://bugs.python.org/issue40379 for more details). If you encounter this, you have two options: you can either remove the nested parallel processes, as callingparallel_map()
from a main process should work fine; or you can manually call the CPython standard librarymultiprocessing
module to perform similar parallel dispatch from a subprocess, but use the"spawn"
or"forkserver"
launch methods to avoid the potential to have things get stuck and never return.
Upgrade Notes
-
The classes
Qubit
,Clbit
andAncillaQubit
now have the__slots__
attribute. This is to reduce their memory usage. As a side effect, they can no longer have arbitrary data attached as attributes to them. This is very unlikely to have any effect on downstream code other than performance benefits. -
The core dependency
retworkx
had its version requirement bumped to 0.11.0, up from 0.10.1. This improves the performance of transpilation passConsolidateBlocks
. -
The minimum supported version of
symengine
is now 0.9.0. This was necessary to improve compatibility with Python’spickle
module which is used internally as part of parallel dispatch withparallel_map()
. -
The default value of
QISKIT_PARALLEL
when running with Python 3.9 on Linux is now set toTRUE
. This means when runningparallel_map()
or functions that call it internally, such astranspile()
andassemble()
, the function will be executed in multiple processes and should have better run time performance. This change was made because the issues with reliability of parallel dispatch appear to have been resolved (see #6188 for more details). If you still encounter issues because of this you can disable multiprocessing and revert to the previous default behavior by setting theQISKIT_PARALLEL
environment variable toFALSE
, or setting theparallel
option toFalse
in your user config file (also please file an issue so we can track any issues related to multiprocessing). -
The previously deprecated
MSGate
gate class previously found inqiskit.circuit.library
has been removed. It was originally deprecated in the 0.16.0 release. Instead theGMS
class should be used, as this allows you to create an equivalent 2 qubit MS gate in addition to anMSGate
for any number of qubits. -
The previously deprecated
mirror()
method of theInstruction
class has been removed. It was originally deprecated in 0.15.0 release. Instead you should useInstruction.reverse_ops()
. -
The previously deprecated
num_ancilla_qubits()
method of theqiskit.circuit.library.PiecewiseLinearPauliRotations
andqiskit.circuit.library.WeightedAdder
classes has been removed. It was originally deprecated in the 0.16.0 release. Instead thePiecewiseLinearPauliRotations.num_ancillas()
andWeightedAdder.num_ancillas()
methods should be used. -
The previously deprecated
reverse
argument on the constructor for thePolynomialPauliRotations
class has been removed. It was originally deprecated in the 0.15.0 release. Instead you should use theQuantumCircuit.reverse_bits()
method to reverse thePolynomialPauliRotations
circuit if needed. -
The previously deprecated
angle
argument on the constructors for theC3SXGate
andC3XGate
gate classes has been removed. It was originally deprecated in the 0.17.0 release. Instead for fractional 3-controlled X gates you can use theC3XGate.power()
method. -
Support for using
np.ndarray
objects as part of theparams
attribute of aGate
object has been removed. This has been deprecated since Qiskit Terra 0.16.0 and now will no longer work. Instead one should create a new subclass ofGate
and explicitly allow anp.ndarray
input by overloading thevalidate_parameter()
method. -
A new extra
csp-layout-pass
has been added to the install target forpip install qiskit-terra
, and is also included in theall
extra. This has no effect in Qiskit Terra 0.20, but starting from Qiskit Terra 0.21, the dependencies needed only for theCSPLayout
transpiler pass will be downgraded from requirements to optionals, and installed by this extra. You can prepare a package that depends on this pass by setting its requirements (orpip install
command) to targetqiskit-terra[csp-layout-pass]
. -
Support for running with Python 3.6 has been removed. To run Qiskit you need a minimum Python version of 3.7.
-
The
AmplitudeEstimator
now inherits from theABC
class from the Python standard library. This requires any subclass to implement theestimate()
method when previously it wasn’t required. This was done because the original intent of the class was to always be a child class ofABC
, as theestimate()
is required for the operation of anAmplitudeEstimator
object. However, if you were previously defining anAmplitudeEstimator
subclass that didn’t implementestimate()
this will now result in an error. -
The error raised by
HoareOptimizer
if the optional dependencyz3
is not available has changed fromTranspilerError
toMissingOptionalLibraryError
(which is both aQiskitError
and anImportError
). This was done to be consistent with the other optional dependencies. -
On Linux, the minimum library support has been raised from the manylinux2010 VM to manylinux2014. This mirrors similar changes in Numpy and Scipy. There should be no meaningful effect for most users, unless your system still contains a very old version of
glibc
. -
The
marginal_counts()
function when called with aResult
object input, will now marginalize thememory
field of experiment data if it’s set in the inputResult
. Previously, thememory
field in the the input was not marginalized. This change was made because the previous behavior would result in thecounts
field not matching thememory
field aftermarginal_counts()
was called. If the previous behavior is desired it can be restored by settingmarginalize_memory=None
as an argument tomarginal_counts()
which will not marginalize thememory
field. -
The
StochasticSwap
transpiler pass may return different results with the same seed value set. This is due to the internal rewrite of the transpiler pass to improve runtime performance. However, this means that if you rantranspile()
withoptimization_level
0, 1 (the default), or 2 with a value set forseed_transpiler
you may get an output with different swap mapping present after upgrading to Qiskit Terra 0.20.0. -
To build Qiskit Terra from source a Rust compiler is now needed. This is due to the internal rewrite of the
StochasticSwap
transpiler pass which greatly improves the runtime performance of the transpiler. The rust compiler can easily be installed using rustup, which can be found here: https://rustup.rs/ -
The
name
attribute of thePauliEvolutionGate
class has been changed to always be"PauliEvolution"
. This change was made to be consistent with other gates in Qiskit and enables other parts of Qiskit to quickly identify when a particular operation in a circuit is aPauliEvolutionGate
. For example, it enables the unrolling to Pauli evolution gates.Previously, the name contained the operators which are evolved, which is now available via the
PauliEvolutionGate.label
attribute. If a circuit with aPauliEvolutionGate
is drawn, the gate will still show the same information, which gates are being evolved. -
The previously deprecated methods:
qiskit.algorithms.VQE.get_optimal_cost
qiskit.algorithms.VQE.get_optimal_circuit
qiskit.algorithms.VQE.get_optimal_vector
qiskit.algorithms.VQE.optimal_params
qiskit.algorithms.HamiltonianPhaseEstimationResult.most_likely_phase
qiskit.algorithms.PhaseEstimationResult.most_likely_phase
which were originally deprecated in the Qiskit Terra 0.18.0 release have been removed and will no longer work.
-
The
qiskit.algorithms.VariationalAlgorithm
class is now defined as an abstract base class (ABC
) which will require classes that inherit from it to define both aVariationalAlgorithm.initial_point
getter and setter method. -
The
pass_manager
kwarg for thetranspile()
function has been removed. It was originally deprecated in the 0.13.0 release. The preferred way to transpile a circuit with a customPassManager
object is to use therun()
method of thePassManager
object. -
The previously deprecated
ParametrizedSchedule
class has been removed and no longer exists. This class was deprecated as a part of the 0.17.0 release. Instead of using this class you can directly parametrizeSchedule
orScheduleBlock
objects by specifying aParameter
object to the parametric pulse argument. -
The module
qiskit.circuit.library.probability_distributions
has been removed and no longer exists as per the deprecation notice from qiskit-terra 0.17.0 (released Apr 1, 2021). The affected classes areUniformDistribution
,NormalDistribution
, andLogNormalDistribution
. They are all moved to the qiskit-finance library, into its circuit library module:qiskit_finance.circuit.library.probability_distributions
. -
The previous
qiskit.test.mock.fake_mumbai_v2.FakeMumbaiV2
class has been renamed toFakeMumbaiFractionalCX
to differentiate it from theBackendV2
based fake backend for the IBM Mumbai device,qiskit.test.mock.backends.FakeMumbaiV2
. If you were previously relying on theFakeMumbaiV2
class to get a fake backend that had fractional applications ofCXGate
defined in its target you need to useFakeMumbaiFractionalCX
class as theFakeMumbaiV2
will no longer have those extra gate definitions in itsTarget
. -
The resolver used by
QuantumCircuit.append()
(and consequently all methods that add an instruction onto aQuantumCircuit
) to convert bit specifiers has changed to make it faster and more reliable. Certain constructs like:import numpy as np from qiskit import QuantumCircuit qc = QuantumCircuit(1, 1) qc.measure(np.array([0]), np.array([0]))
will now work where they previously would incorrectly raise an error, but certain pathological inputs such as:
from sympy import E, I, pi qc.x(E ** (I * pi))
will now raise errors where they may have occasionally (erroneously) succeeded before. For almost all correct uses, there should be no noticeable change except for a general speed-up.
-
The semi-public internal method
QuantumCircuit._append()
no longer checks the types of its inputs, and assumes that there are no invalid duplicates in its argument lists. This function is used by certain internal parts of Qiskit and other libraries to build upQuantumCircuit
instances as quickly as possible by skipping the error checking when the data is already known to be correct. In general, users or functions taking in user data should use the publicQuantumCircuit.append()
method, which resolves integer bit specifiers, broadcasts its arguments and checks the inputs for correctness. -
Cython is no longer a build dependency of Qiskit Terra and is no longer required to be installed when building Qiskit Terra from source.
-
The preset passmanagers in
qiskit.transpiler.preset_passmanagers
for all optimization levels 2 and 3 as generated bylevel_2_pass_manager()
andlevel_3_pass_manager()
have been changed to run theVF2Layout
by default prior to the layout pass. TheVF2Layout
pass will quickly check if a perfect layout can be found and supersedes what was previously done for optimization levels 2 and 3 which were using a combination ofTrivialLayout
andCSPLayout
to try and find a perfect layout. This will result in potentially different behavior whentranspile()
is called by default as it removes a default path for all optimization levels >=2 of using a trivial layout (wherecircuit.qubits[0]
is mapped to physical qubit 0,circuit.qubits[1]
is mapped to physical qubit 1, etc) assuming the trivial layout is perfect. If your use case was dependent on the trivial layout you can explictly request it when transpiling by specifyinglayout_method="trivial"
when callingtranspile()
. -
The preset pass manager for optimization level 1 (when calling
transpile()
withoptimization_level=1
or when nooptimization_level
argument is set) as generated bylevel_1_pass_manager()
has been changed so thatVF2Layout
is called by default to quickly check if a a perfect layout can be found prior to theDenseLayout
. However, unlike with optimization level 2 and 3 a trivial layout is still attempted prior to runningVF2Layout
and if it’s a perfect mapping the output fromVF2Layout
will be used.
Deprecation Notes
-
The
max_credits
argument toexecute()
, and all of theQobj
configurations (e.g.QasmQobjConfig
andPulseQobjConfig
), is deprecated and will be removed in a future release. The credit system has not been in use on IBM Quantum backends for two years, and the option has no effect. No alternative is necessary. For example, if you were callingexecute()
as:job = execute(qc, backend, shots=4321, max_credits=10)
you can simply omit the
max_credits
argument:job = execute(qc, backend, shots=4321)
-
Using an odd integer for the
order
argument on the constructor of theSuzukiTrotter
class is deprecated and will no longer work in a future release. The product formulae used by theSuzukiTrotter
are only defined when the order is even as the Suzuki product formulae is symmetric. -
The
qregs
,cregs
,layout
, andglobal_phase
kwargs to theMatplotlibDrawer
,TextDrawing
, andQCircuitImage
classes, and thecalibrations
kwarg to theMatplotlibDrawer
class, are now deprecated and will be removed in a subsequent release.
Bug Fixes
-
Fixed an error in the circuit conversion functions
circuit_to_gate()
andcircuit_to_instruction()
(and their associated circuit methodsQuantumCircuit.to_gate()
andQuantumCircuit.to_instruction()
) when acting on a circuit with registerless bits, or bits in more than one register. -
Fixed an issue where calling
QuantumCircuit.copy()
on the “body” circuits of a control-flow operation created with the builder interface would raise an error. For example, this was previously an error, but will now return successfully:from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister qreg = QuantumRegister(4) creg = ClassicalRegister(1) circ = QuantumCircuit(qreg, creg) with circ.if_test((creg, 0)): circ.h(0) if_else_instruction, _, _ = circ.data[0] true_body = if_else_instruction.params[0] true_body.copy()
-
Added a missing entry from the standard session equivalence library between
CXGate
andCPhaseGate
as well as betweenCXGate
andCRZGate
. -
Fixed an issue where running the
==
operator between twoSparsePauliOp
objects would raise an error when the two operators had different numbers of coefficients. For example:op = SparsePauliOp.from_list([("X", 1), ("Y", 1)]) op2 = SparsePauliOp.from_list([("X", 1), ("Y", 1), ("Z", 0)]) print(op == op2)
This would previously raise a
ValueError
instead of returningFalse
. -
Fixed support in
transpile()
for passing aInstructionScheduleMap
object to the underlyingPassManager
based on theTarget
forBackendV2
based backends. Previously, thetranspile()
function would not do this processing and any transpiler passes which do not support working with aTarget
object yet would not have access to the default pulse calibrations for the instructions from aBackendV2
backend. -
The
AmplitudeAmplifier
is now correctly available from the rootqiskit.algorithms
module directly. Previously it was not included in the re-exported classes off the root module and was only accessible fromqiskit.algorithms.amplitude_amplifiers
. Fixed #7751. -
Fixed an issue with the
mpl
backend for the circuit drawer functioncircuit_drawer()
and theQuantumCircuit.draw()
method where gates with conditions would not display properly when a sufficient number of gates caused the drawer to fold over to a second row. Fixed: #7752. -
Fixed an issue where the
HHL.construct_circuit()
method under certain conditions would not return a correctQuantumCircuit
. Previously, the function had a rounding error in calculating how many qubits were necessary to represent the eigenvalues which would cause an incorrect circuit output. -
Fixed an endianness bug in
BaseReadoutMitigator.expectation_value()
when a stringdiagonal
was passed. It will now correctly be interpreted as little endian in the same manner as the rest of Qiskit Terra, instead of big endian. -
Fixed an issue with the
quantum_info.partial_trace()
when the function was asked to trace out no subsystems, it will now correctly return theDensityMatrix
of the input state with all dimensions remaining rather than throwing an error. Fixed #7613 -
Fixed an issue with the
text
backend for the circuit drawer functioncircuit_drawer()
and theQuantumCircuit.draw()
method when gates that use side text, such as theCPhaseGate
andRZZGate
gate classes, with classical conditions set would not display properly. Fixed #7532. -
Fixed an issue with the
circuit_drawer()
function anddraw()
method ofQuantumCircuit
. When using thereverse_bits
option with thempl
,latex
, ortext
options, bits without registers did not display in the correct order. Fixed #7303. -
Fixed an issue in the
LocalReadoutMitigator.assignment_matrix()
method where it would previously reject an input value for thequbits
argument that wasn’t a trivial sequence of qubits in the form:[0, 1, 2, ..., n-1]
. This has been corrected so that now any list of qubit indices to be measured are accepted by the method. -
Fixed an issue in the
StabilizerState.expectation_value()
method’s expectation value calculation, where the output expectation value would be incorrect if the inputPauli
operator for theoper
argument had a non-trivial phase. Fixed #7441. -
An opflow expression containing the Pauli identity
opflow.I
no longer produces anIGate
when converted to a circuit. This change fixes a difference in expectation; the identity gate in the circuit indicates a delay however in opflow we expect a mathematical identity – meaning no operation at all. -
The
PauliGate
no longer inserts anIGate
for Paulis with the label"I"
. -
PauliSumOp
equality tests now handle the case when one of the compared items is a singlePauliOp
. For example,0 * X + I == I
now evaluates to True, whereas it was False prior to this release. -
Fixed an issue with the
ALAPSchedule
andASAPSchedule
transpiler passes when working with instructions that had custom pulse calibrations (i.e. pulse gates) set. Previously, the scheduling passes would not use the duration from the custom pulse calibration for thse instructions which would result in the an incorrect scheduling being generated for the circuit. This has been fixed so that now the scheduling passes will use the duration of the custom pulse calibration for any instruction in the circuit which has a custom calibration. -
Fixed support for using
ParameterExpression
instruction paramaters in theRZXCalibrationBuilder
transpiler pass. Previously, if an instruction parameter included a boundParameterExpression
the pass would not be able to handle this correctly. -
Stopped the parser in
QuantumCircuit.from_qasm_str()
andfrom_qasm_file()
from accepting OpenQASM programs that identified themselves as being from a language version other than 2.0. This parser is only for OpenQASM 2.0; support for imported circuits from OpenQASM 3.0 will be added in an upcoming release. -
The OpenQASM 3 exporter,
qasm3.Exporter
, will now escape register and parameter names that clash with reserved OpenQASM 3 keywords by generating a new unique name. Registers and parameters with the same name will no longer have naming clashes in the code output from the OpenQASM 3 exporter. Fixed #7742.
Aer 0.10.3
No change
Ignis 0.7.0
No change
IBM Q Provider 0.18.3
No change