Qiskit SDK 1.3 release notes
1.3.3
Prelude
Qiskit 1.3.3 is a minor bugfix release for the 1.3 series.
Bug Fixes
-
Fixed a bug where the barrier labels were incorrectly positioned when using the
reverse_bits = Trueparameter in theQuantumCircuit.draw()method. The bug caused the labels on barrier operations to be misaligned, leading to potential confusion in circuit visualizations. Fixed #13609. -
Applied a small regularisation factor against ill-conditioned Hermitian matrices in super-operator representations.
-
Comparisons of
Delayinstructions, including those within circuits, now require both the units and the duration value to be equal. Fixes #13812. -
Fixed a bug in the
CommutationCheckerwhich could fail when checking the commutation relation of a two-qubit Pauli rotation with a gate that is not in the commutation cache. For example:import numpy as np from qiskit.circuit.library import RXXGate, RGate from qiskit.circuit.commutation_library import SessionCommutationChecker as scc res = scc.commute(RGate(2, 2), [1], [], RXXGate(np.pi / 2), [0, 1], [])This behavior is now resolved and the commutation relation correctly computed. Fixed #13742.
-
Fixed a bug where
QuantumCircuit.qubit_stop_time()andQuantumCircuit.qubit_duration()returned incorrect time (duration). The issue was triggered when some qubits have instructions but other qubits are idle. Fixes #8729. -
Fixed a bug in the
RemoveIdentityEquivalenttranspiler pass, where gates close to identity up to a global phase were removed from the circuit, but the global phase of the circuit was not updated. In particular,RemoveIdentityEquivalentnow removes non-parameterizedGlobalPhaseGategates. Fixes #13778. -
Fixed a bug in
random_clifford()that stopped it from sampling the full Clifford group. Fixes #13606. -
When
SabreLayoutis used to do both layout and routing simultaneously (as is the case for the default options totranspile()andgenerate_preset_pass_manager()) on aTargetorCouplingMapwith disjoint connectivity, and the input circuit fits into a single component of the coupling map, the routing permutation will now be tracked correctly.Previously, any qubits in the coupling map that were not connected, even indirectly, to a qubit used by the routed circuit would not be included in the final routing permutation. This could cause surprising behaviour a long way from the point of failure, even if compilation appeared to succeed, such as calls to
TranspileLayout.final_index_layout()raisingKeyError.This bug did not affect backends that were fully connected, as most are. Fixes #13732.
1.3.2
Prelude
Qiskit 1.3.2 is a minor bugfix release for the 1.3 series.
Synthesis Upgrade Notes
- The high-level synthesis plugins for
LinearFunctionno longer raise an error when an object other thanLinearFunctionis passed into therunmethod. Instead, they now returnNone, which is consistent with other plugins. If you relied on this error being raised, you can manually perform an instance-check.
Bug Fixes
-
Previously, the
CommutationCheckereagerly cached the commutation relations ofInstructions with float-onlyparamsas key to query the relation. This could lead to incorrect results if the instruction’s definition depended on additional information beyond just theparamsattribute, as, for example, in the case ofPauliEvolutionGate. This behavior is now fixed, and the commutation checker eagerly caches commutations only for Qiskit-native standard gates. For custom gates, this change might incur a performance cost; however, guarantees correct results by avoiding unsafe caching. -
Fixed a bug in the
CommutationChecker, where checking commutation relations of an instruction with non-numeric values in theparamsattribute (as in the case ofPauliGate) could raise an error. Fixed #13570. -
The
CommutationCheckerdid not correctly handle commutations of theCRXGate,CRYGateandCRZGatefor rotation angles of the form , with . In these cases, these gates were incorrectly assumed to commute with any gate. This behavior is now fixed, and these gates correctly commute with any gate only when the rotation angle is a multiple of . -
Fixed a bug that caused the following circuit library functions to produce errors when called with
num_qubits=1:efficient_su2(),real_amplitudes(),excitation_preserving()andpauli_two_design()(for a single qubit, these circuits do not contain any 2-qubit gates). Fixed #13480. -
Fixed a bug where any instruction named
"mcmt"was incorrectly passed to the high-level synthesis routine for aMCMTGate, leading to a failure or an invalid result. This issue could happen, for example, when handling theMCMTcircuit, named"mcmt", and implicitly converting it into an instruction (e.g., when appending it to another circuit). Fixed #13563. -
Fixed a bug where the default product formula synthesis for
PauliEvolutionGatedid not correctly handle all-identity terms in the operator. The all-identity term should introduce a global phase equal to-evolution_time, but was off by a factor of 2 and could break for parameterized times. Fixed #13625. Fixed #13675. Fixed #13644. -
Fixed an inconsistency in the circuit generated by Pauli evolution synthesis using
SuzukiTrotterorLieTrotter(the default) method. For parameterized evolution times, the resulting circuits contained parameters with a spurious zero complex part, which affected the output ofParameterExpression.sympify(). The output now correctly contains only real values. Fixed #13642. -
Fixed a bug that caused
PauliList.insert()withqubit=Trueto produce a phase attribute with the wrong shape when the original object was of length 1. Fixed #13623. -
Fixed a bug in
qasm3.Exporterthat caused the exporter to crash when handling a unitary gate due to an incorrect processing of itsparamsfield. Fixed #13362. -
Fixed a bug in the
Target.instruction_supported()method where targets withself.num_qubits==Nonewould always returnFalseindependently of the supported basis set. -
Fixed a bug in the
UnitarySynthesistranspiler pass, where blocks ofUnitaryGates on 3 qubits or more were not correctly synthesized. This led, e.g., to the circuit being overwritten with the last processed block or to internal panics when encountering measurements after such a block. Fixed #13586. -
Fixed a bug in the
UnitarySynthesistranspiler pass where non-2-qubit gates would be included in the available 2 qubit basis, causing theTwoQubitWeylDecompositionto panic because of the dimension mismatch. -
Fixed a bug where initializing
SparsePauliOpwith a large number of Pauli-Yterms (typically ) and no explicitcoeffswould result in a coefficient close to 1 but with a floating point error. The coefficient is now correctly 1 per default. Fixed #13522.
1.3.1
Prelude
Qiskit 1.3.1 is a minor bugfix release for the 1.3 series.
Circuits Upgrade Notes
- The generic control method for gates now avoids attempting to translate gates into a supported basis when the gate is already supported. This may slightly change the synthesis of the controlled gate, but it should not increase the two-qubit gate count.
Bug Fixes
-
Fixed a bug where calling
QuantumCircuit.decompose()on an instruction that had no definition inside ac_ifblock would raise an error. Fixed #13493. -
Operations inside a control flow operation (e.g.
QuantumCircuit.for_loop()) were not correctly decomposed when callingQuantumCircuit.decompose(). Fixed #13544. -
Added default definitions for
FullAdderGate,HalfAdderGate,ModularAdderGateandMultiplierGategates, allowingOperators to be constructed from quantum circuits containing these gates. -
Corrected the number of clean ancilla qubits required by
FullAdderSynthesisV95,HalfAdderSynthesisV95, andModularAdderSynthesisV95plugins. -
Added missing
FullAdderSynthesisDefaultplugin that chooses the best decomposition forFullAdderGatebased on the number of clean ancilla qubits available. -
Fixed
HalfAdderSynthesisDefaultandModularAdderSynthesisDefaultplugins, forHalfAdderGateandModularAdderGaterespectively, to choose the best decomposition based on the number of clean ancilla qubits available. -
Fixed an incorrect caching behavior during parameter assignment that could result in definitions within the
EquivalenceLibrarybecoming corrupted. This resolves unexpected issues when running basis translation in parallel. Fixed #13504. -
Fixed a series of bugs when processing circuits with parameterized global phases in which the global phase was not properly assigned during parameter assignment. Known cases this affected include:
- assigning parameters after calling
QuantumCircuit.decompose()on a circuit, where the decomposition introduces a global phase - assigning parameters on a circuit constructed from a DAG via
dag_to_circuit() - assigning parameters on circuits created with
pauli_twirl_2q_gates(), where the circuit to be twirled had a parameterized global phase
Fixed #13534.
- assigning parameters after calling
-
Fixed a bug in
RZGate.control()for more than 1 control qubit, which used an unnecessarily expensive decomposition. Fixed #13473.
1.3.0
Prelude
Qiskit version 1.3.0 brings in major performance and quality improvements for the transpiler. There have been many new features, fixes and improvements introduced in this new version of Qiskit, the highlights are:
The core data structures for transpilation in Qiskit have been ported to Rust internally. This includes components such as the
DAGCircuit,Target,EquivalenceLibrary, and others. The public APIs for all of these data structures remains unchanged but the performance after the rewrites has improved.The majority of the transpiler passes used by the preset pass manager have been ported into Rust, resulting in an average 6x overall runtime improvement compared to Qiskit 1.2.4 when running the benchpress benchmarks. Some of the particularly impactful passes that greatly benefited from the rewrites were the
BasisTranslator,CommutationAnalysis,ConsolidateBlocks, andUnitarySynthesis. You can refer to the feature release notes for a full list of the ported passes.Improvements to the circuit library that increase compilation quality and circuit construction speed. Operations are now distinguished into:
- Structural operations, that have a unique decomposition, and are represented as functions that return a
QuantumCircuit(for example:real_amplitudes()). Most of these functions are built in Rust, resulting in significantly faster circuit construction runtime.- Abstract operations, that can be implemented using different decompositions, are represented as
GateorInstruction(for example:PauliEvolutionGate). This allows building an abstract quantum circuit and letting the compiler choose the optimal decomposition.Using an abstract circuit description is especially powerful in combination with improvements to the
HighLevelSynthesistranspiler pass, which can now take into account idle auxiliary qubits to find the best available decomposition for a given gate.The minimum supported Python version is now 3.9 as Python 3.8 went end of life in 2024-10. Official support for Python 3.13 support was also added in this release.
Circuits Features
-
Improved the functionality of
CommutationCheckerto include support for the following parameterized gates with free parameters:RXXGate,RYYGate,RZZGate,RZXGate,RXGate,RYGate,RZGate,PhaseGate,U1Gate,CRXGate,CRYGate,CRZGate,CPhaseGate. Before, these were only supported with bound parameters. -
Added a new function
quantum_volume()for generating a quantum volumeQuantumCircuitobject as defined in A. Cross et al. Validating quantum computers using randomized model circuits, Phys. Rev. A 100, 032328 (2019). This new function differs from the existingQuantumVolumeclass in that it returns aQuantumCircuitobject instead of building a subclass object. The second is that this new function is multithreaded and implemented in rust so it generates the output circuit ~10x faster than theQuantumVolumeclass. -
Improved the runtime performance of constructing the
QuantumVolumeclass with theclassical_permutationargument set toTrue. Internally it now calls thequantum_volume()function which is written in Rust and is ~10x faster when generating a quantum volume circuit. -
Added a new circuit manipulation function
pauli_twirl_2q_gates()that can be used to apply Pauli twirling to a given circuit. This only works for twirling a fixed set of two-qubit gates, currentlyCXGate,ECRGate,CZGate,iSwapGate. For example:from qiskit.circuit import QuantumCircuit, pauli_twirl_2q_gates qc = QuantumCircuit(2) qc.cx(0, 1) twirled_circuit = pauli_twirl_2q_gates(qc, seed=123456) twirled_circuit.draw("mpl")
-
Added binary arithmetic gates for inplace addition of two -qubit registers, that is . The
ModularAdderGateimplements addition modulo , theHalfAdderGateincludes a carry-out qubit, and theFullAdderGateincludes both a carry-in and a carry-out qubit. See the respective documentation for details and examples.In contrast to the existing library circuits, such as
CDKMRippleCarryAdder, handling the abstract gate allows the compiler (or user) to select the optimal gate synthesis, depending on the circuit’s context. -
Added the
MultiplierGatefor multiplication of two -qubit registers, that is . See the class documentation for details and examples. -
The boolean logic quantum circuits in
qiskit.circuit.librarynow have equivalent representations asGateobjects enabling their use withHighLevelSynthesistranspiler pass and plugin infrastructure.AndGate, representingAND,OrGate, representingOR,BitwiseXorGate, representingXOR,InnerProductGate, representingInnerProduct.
-
Specialized implementations of
__eq__()have been added for all standard-library circuit gates. Most of the standard gates already specialized this method, but a few did not, and could cause significant slowdowns in unexpected places. -
Added
evolved_operator_ansatz(),hamiltonian_variational_ansatz(), andqaoa_ansatz()into the circuit library to implement variational circuits based on operator evolutions.evolved_operator_ansatz()andqaoa_ansatz()are functionally equivalent toEvolvedOperatorAnsatzandQAOAAnsatz, but generally more performant.The
hamiltonian_variational_ansatz()is designed to take a single Hamiltonian and automatically split it into commuting terms to implement a Hamiltonian variational ansatz. This could already be achieved manually by using theEvolvedOperatorAnsatz, but is now more convenient to use. -
Added
grover_operator()to construct a Grover operator circuit, used in Grover’s algorithm and amplitude estimation/amplification, for example. This function is similar toGroverOperator, but does not require you to choose the implementation of the multi-controlled X gate, but instead lets the compiler determine the optimal decomposition. Additionally, it does not wrap the circuit into an opaque gate and is faster because fewer decompositions are required for transpilation.from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import grover_operator oracle = QuantumCircuit(2) oracle.z(0) # good state = first qubit is |1> grover_op = grover_operator(oracle, insert_barriers=True) grover_op.draw('mpl')
-
A new data attribute,
qiskit.circuit.CONTROL_FLOW_OP_NAMES, is available to easily find and check whether a givenInstructionis a control-flow operation by name. -
The standard equivalence library (
SessionEquivalenceLibrary) now has rules that can directly convert between Qiskit’s standard-library 2q continuous Ising-type interactions (e.g.CPhaseGate,RZZGate,RZXGate, and so on) using local equivalence relations. Previously, several of these conversions would go via a 2-CX form, which resulted in less efficient circuit generation.NoteIn general, the
BasisTranslatoris not guaranteed to find the “best” equivalence relation for a givenTarget, but will always find an equivalence if one exists. We rely on more expensive resynthesis and gate-optimization passes in the transpiler to improve the output. These passes are currently not as effective for basis sets with a continuously parametrized two-qubit interaction as they are for discrete super-controlled two-qubit interactions. -
Added a new argument
"apply_synthesis"toDecompose, which allows the transpiler pass to apply high-level synthesis to decompose objects that are only defined by a synthesis routine. For example:from qiskit import QuantumCircuit from qiskit.quantum_info import Clifford from qiskit.transpiler.passes import Decompose cliff = Clifford(HGate()) circuit = QuantumCircuit(1) circuit.append(cliff, [0]) # Clifford has no .definition, it is only defined by synthesis nothing_happened = Decompose()(circuit) # this internally runs the HighLevelSynthesis pass to decompose the Clifford decomposed = Decompose(apply_synthesis=True)(circuit) -
Added the
iqp()function to construct Instantaneous Quantum Polynomial time (IQP) circuits. In addition to the existingIQPclass, the function also allows construction of random IQP circuits:from qiskit.circuit.library import random_iqp random_iqp = random_iqp(num_qubits=4) random_iqp.draw('mpl')
-
Added the
MCMTGateto represent a multi-control multi-target operation as a gate. This gate representation of the existingMCMTcircuit allows the compiler to select the best available implementation according to the number and the state of auxiliary qubits present in the circuit.The desired implementation can be chosen by specifying the high-level synthesis plugin:
from qiskit import QuantumCircuit, transpile from qiskit.circuit.library import MCMTGate, HGate from qiskit.transpiler.passes import HLSConfig # used for the synthesis config mcmt = MCMTGate(HGate(), num_ctrl_qubits=5, num_target_qubits=3) circuit = QuantumCircuit(20) circuit.append(mcmt, range(mcmt.num_qubits)) config = HLSConfig(mcmt=["vchain"]) # alternatively use the "noaux" method synthesized = transpile(circuit, hls_config=config)Additionally, the
MCMTGatealso supports custom (that is, open) control states of the control qubits. -
As a part of circuit library modernization, each of the following quantum circuits is either also represented as a
Gateobject or can be constructed using a synthesis method:GraphStateis represented byGraphStateGate,FourierCheckingcan be constructed usingfourier_checking(),UnitaryOverlapcan be constructed usingunitary_overlap(),HiddenLinearFunctioncan be constructed usinghidden_linear_function(),PhaseEstimationcan be constructed usingphase_estimation().
-
The
CommutationCheckerclass has been rewritten in Rust. This class retains the same functionality and public API as before but is now significantly faster in most cases. -
PauliFeatureMapandZZFeatureMapnow support specifying the entanglement as a dictionary where the keys represent the number of qubits, and the values are lists of integer tuples that define which qubits are entangled with one another. This allows for more flexibility in constructing feature maps tailored to specific quantum algorithms. Example usage:from qiskit.circuit.library import PauliFeatureMap entanglement = { 1: [(0,), (2,)], 2: [(0, 1), (1, 2)], 3: [(0, 1, 2)], } qc = PauliFeatureMap(3, reps=2, paulis=['Z', 'ZZ', 'ZZZ'], entanglement=entanglement, insert_barriers=True) qc.decompose().draw('mpl') -
The
count_ops()method inQuantumCircuithas been re-written in Rust. It now runs between 3 and 9 times faster. -
Added circuit library functions
pauli_feature_map(),z_feature_map(),zz_feature_map()to construct Pauli feature map circuits. These functions are approximately 8x faster than the current circuit library objects,PauliFeatureMap,ZFeatureMap, andZZFeatureMap, and will replace them in the future.The functions can be used as drop-in replacement:
from qiskit.circuit.library import pauli_feature_map, PauliFeatureMap fm = pauli_feature_map(20, paulis=["z", "xx", "yyy"]) also_fm = PauliFeatureMap(20, paulis=["z", "xx", "yyy"]).decompose()
Primitives Features
-
Support for level 1 data was added to
BackendSamplerV2, as was support for passing options through to therun()method of the wrappedBackendV2. The run options can be specified by using a"run_options"entry inside theoptionsdictionary passed toBackendSamplerV2. The"run_options"entry should be a dictionary that maps argument names to values to be passed to the backend’srun()method. When a"meas_level = 1 "is set in the run options, the results from the backend will be treated as level 1 results instead of bit arrays (the level 2 format). -
EstimatorandStatevectorEstimatorreturn expectation values in a stochastic way if the input circuit includes a reset for some subsystems. The result was previously not reproducible, but now it can be reproduced if a random seed is set. For example:from qiskit.primitives import StatevectorEstimator estimator = StatevectorEstimator(seed=123)or:
from qiskit.primitives import Estimator estimator = Estimator(options={"seed":123})
OpenQASM Features
- The class
qasm3.CustomGateis now inspectable programmatically. Itsconstructor,name,num_paramsandnum_qubitscan now be viewed from Python after the object has been constructed. This allows you to inspect the contents of provided data attributes likeSTDGATES_INC_GATES.
QPY Features
- Added a new QPY format version 13 that adds a Qiskit native representation of
ParameterExpressionobjects.
Quantum Information Features
-
The performance of
SparsePauliOp.from_operator()has been optimized on top of the algorithm improvements methods introduced in Qiskit 1.0. It is now approximately five times faster than before for fully dense matrices, taking approximately 40ms to decompose a 10q operator involving all Pauli terms. -
Added a new argument
assume_unitarytoqiskit.quantum_info.Operator.power(). WhenTrue, we use a faster method based on Schur’s decomposition to raise anOperatorto a fractional power. -
Added
SparsePauliOp.to_sparse_list()to convert an operator into a sparse list format. This works inversely toSparsePauliOp.from_sparse_list(). For example:from qiskit.quantum_info import SparsePauliOp op = SparsePauliOp(["XIII", "IZZI"], coeffs=[1, 2]) sparse = op.to_sparse_list() # [("X", [3], 1), ("ZZ", [1, 2], 2)] other = SparsePauliOp.from_sparse_list(sparse, op.num_qubits) print(other == op) # True -
The performance of
Pauli.to_label()has significantly improved for large Paulis. -
The method
Operator.power()has a new parameterbranch_cut_rotation. This can be used to shift the branch-cut point of the root around, which can affect which matrix is chosen as the principal root. By default, it is set to a small positive rotation to make roots of operators with a real-negative eigenvalue (like Pauli operators) more stable against numerical precision differences. -
A new observable class has been added.
SparseObservablerepresents observables as a sum of terms, similar toSparsePauliOp, but with two core differences:- Each complete term is stored as (effectively) a series of
(qubit, bit_term)pairs, without storing qubits that undergo the identity for that term. This significantly improves the memory usage of observables such as the weighted sum of Paulis . - The single-qubit term alphabet is overcomplete for the operator space; it can represent Pauli operators (like
SparsePauliOp), but also projectors onto the eigenstates of the Pauli operators, like . Such projectors can be measured on hardware equally as efficiently as their corresponding Pauli operator, butSparsePauliOpwould require an exponential number of terms to represent over qubits, whileSparseObservableneeds only a single term.
You can construct and manipulate
SparseObservableusing an interface familiar to users ofSparsePauliOp:from qiskit.quantum_info import SparseObservable obs = SparseObservable.from_sparse_list([ ("XZY", (2, 1, 0), 1.5j), ("+-", (100, 99), 0.5j), ("01", (50, 49), 0.5), ])SparseObservableis not currently supported as an input format to the primitives (qiskit.primitives), but we expect to expand these interfaces to include them in the future. - Each complete term is stored as (effectively) a series of
Synthesis Features
-
Added synthesis functions
synth_mcx_gray_code()andsynth_mcx_noaux_v24()that synthesize multi-controlled X gates. These functions do not require additional ancilla qubits. -
Added synthesis functions
synth_c3x()andsynth_c4x()that synthesize 3-controlled and 4-controlled X-gates respectively. -
Add a synthesis function
synth_mcx_n_dirty_i15()that synthesizes a multi-controlled X gate with controls using dirty ancillary qubits producing a circuit with at most CX gates, by Iten et. al. (arXiv:1501.06911). -
Add a synthesis function
synth_mcx_n_clean_m15()that synthesizes a multi-controlled X gate with controls using clean ancillary qubits producing a circuit with at most CX gates, by Maslov (arXiv:1508.03273). -
Add a synthesis function
synth_mcx_1_clean_b95()that synthesizes a multi-controlled X gate with controls using a single clean ancillary qubit producing a circuit with at most CX gates, by Barenco et al. (arXiv:quant-ph/9503016). -
Added
adder_qft_d00(),adder_ripple_c04(), andadder_ripple_v95()to synthesize the adder gates,ModularAdderGate,HalfAdderGate, andFullAdderGate. -
Added
multiplier_cumulative_h18()andmultiplier_qft_r17()to synthesize theMultiplierGate. -
Added
synth_mcmt_vchain()to synthesize the multi-control multi-target gate with a linear number of Toffoli gates and k-1 auxiliary qubits for k control qubits, along with the high-level synthesis pluginMCMTSynthesisVChain. -
Added a high-level synthesis plugin structure for the
MCMTGate, including theMCMTSynthesisNoAux(for no auxiliary qubits), the aforementionedMCMTSynthesisVChain(usingnum_control - 1auxiliary qubits), and theMCMTSynthesisDefaultto let the compiler choose the optimal decomposition. -
The function
random_clifford()was ported to Rust, improving the runtime by a factor of 3. -
Added
ProductFormula.expand(), which lets you view the expansion of a product formula in a sparse Pauli format. For example, we can query the format of a second-order Trotter expansion of a Hamiltonian as:from qiskit.quantum_info import SparsePauliOp from qiskit.circuit.library import PauliEvolutionGate from qiskit.synthesis.evolution import SuzukiTrotter hamiltonian = SparsePauliOp(["IX", "XI", "ZZ"], coeffs=[-1, -1, 1]) evo = PauliEvolutionGate(hamiltonian, time=3.14) trotter = SuzukiTrotter(order=2) print(trotter.expand(evo))which will print
[('X', [0], -3.14), ('X', [1], -3.14), ('ZZ', [0, 1], 6.28), ('X', [1], -3.14), ('X', [0], -3.14)] -
Added the plugin structure for the
PauliEvolutionGate. The default plugin,PauliEvolutionSynthesisDefault, constructs circuit as before, but faster, as it internally uses Rust. The larger the circuit (for example. by the Hamiltonian size, the number of timesteps, or the Suzuki-Trotter order), the greater the speedup. For example, a 100-qubit Heisenberg Hamiltonian with 10 timesteps and a 4th-order Trotter formula is now constructed ~9.4x faster. The new plugin,PauliEvolutionSynthesisRustiq, uses the synthesis algorithm that is described in the paper “Faster and shorter synthesis of Hamiltonian simulation circuits” by (de) Brugière and Martiel” and is implemented in Rustiq. For example:from qiskit.circuit import QuantumCircuit from qiskit.quantum_info import SparsePauliOp from qiskit.circuit.library import PauliEvolutionGate from qiskit.compiler import transpile from qiskit.transpiler.passes import HLSConfig op = SparsePauliOp(["XXX", "YYY", "IZZ"]) qc = QuantumCircuit(4) qc.append(PauliEvolutionGate(op), [0, 1, 3]) config = HLSConfig(PauliEvolution=[("rustiq", {"upto_phase": False})]) tqc = transpile(qc, basis_gates=["cx", "u"], hls_config=config) tqc.draw(output='mpl')
This code snippet uses the Rustiq plugin to synthesize
PauliEvolutionGateobjects in the quantum circuit qc. The plugin is called with the additional optionupto_phase = False, allowing you to obtain smaller circuits at the expense of possibly not preserving the global phase. For the full list of supported options, see the documentation forPauliEvolutionSynthesisRustiq. -
Port
synth_cz_depth_line_mr()to Rust. This function synthesizes a CZ circuit for linear nearest neighbor (LNN) connectivity, based on the Maslov and Roetteler method. On a 350x350 binary matrix, the Rust implementation yields a speedup of about 30x. -
Port
synth_permutation_reverse_lnn_kms()to Rust, which synthesizes a reverse permutation for LNN architecture using the Kutin, Moulton, Smithline method. -
Added a new argument
preserve_ordertoProductFormula, which allows re-ordering the Pauli terms in the Hamiltonian before the product formula expansion, to compress the final circuit depth. By setting this toFalse, a term of form
will be re-ordered to
which will lead to the RZZ and RYY rotations being applied in parallel, instead of three sequential rotations in the first part.
This option can be set via the plugin interface:
from qiskit import QuantumCircuit, transpile
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.quantum_info import SparsePauliOp
from qiskit.synthesis.evolution import SuzukiTrotter
from qiskit.transpiler.passes import HLSConfig
op = SparsePauliOp(["XXII", "IYYI", "IIZZ"])
time, reps = 0.1, 1
synthesis = SuzukiTrotter(order=2, reps=reps)
hls_config = HLSConfig(PauliEvolution=[("default", {"preserve_order": False})])
circuit = QuantumCircuit(op.num_qubits)
circuit.append(PauliEvolutionGate(op, time), circuit.qubits)
tqc = transpile(circuit, basis_gates=["u", "cx"], hls_config=hls_config)
tqc.draw('mpl')
Transpiler Features
-
Add argument
matrix_basedto theCollectCliffordstranspiler pass. If the new parametermatrix_based=True, theCollectCliffordstranspiler pass can collect unitary gates that are Clifford gates for certain parameters, for exampleRZGategates with angles that are multiples of . -
The
RemoveIdentityEquivalenttranspiler pass is now run as part of the preset pass managers at optimization levels 2 and 3. The pass runs during theinitandoptimizationstages, because the optimizations it applies are valid in both stages and the pass is fast to execute. -
Added multiple high-level-synthesis plugins for synthesizing an
MCXGate:MCXSynthesisNCleanM15, based onsynth_mcx_n_clean_m15().MCXSynthesisNDirtyI15, based onsynth_mcx_n_dirty_i15().MCXSynthesis1CleanB95, based onsynth_mcx_1_clean_b95().MCXSynthesisNoAuxV24, based onsynth_mcx_noaux_v24().MCXSynthesisGrayCode, based onsynth_mcx_gray_code().
As well as:
MCXSynthesisDefault, for choosing the most efficient synthesis method based on the number of clean and dirty ancilla qubits available.
As an example, consider the transpilation of the following circuit:
from qiskit.circuit import QuantumCircuit from qiskit.compiler import transpile qc = QuantumCircuit(7) qc.x(0) qc.mcx([0, 1, 2, 3], [4]) qc.mcx([0, 1, 2, 3, 4], [5]) qc.mcx([0, 1, 2, 3, 4, 5], [6]) transpile(qc).draw('mpl', fold=-1)
For the first MCX gate, qubits
5and6can be used as clean ancillas, and the best available synthesis methodsynth_mcx_n_clean_m15will get chosen. For the second MCX gate, qubit6can be used as a clean ancilla, the methodsynth_mcx_n_clean_m15no longer applies, so the methodsynth_mcx_1_clean_b95will get chosen. For the third MCX gate, there are no ancilla qubits, and the methodsynth_mcx_noaux_v24will get chosen. -
The
SabreLayouttranspiler pass has been updated to run an additional two or three layout trials by default, independently from thelayout_trialskeyword argument’s value. A trivial layout and its reverse are included for all backends, just like theDenseLayouttrial that was added in 1.2.0. In addition to this, the largest rings on an IBM backend heavy hex connectivity graph are added if the backends are 127, 133, or 156 qubits. This can provide a good starting point for some circuits on these commonly run backends, while for all others it’s just an additional “random trial”. -
The
DAGCircuithas been reimplemented in Rust. This rewrite of the Python class should be fully API compatible with the previous Python implementation. While the class was previously implemented using rustworkx, for which the underlying data graph structure exists in Rust, the implementation of the class and all the data was lived in Python. This new version ofDAGCircuitstores Rust native representations for all its data and is more memory-efficient due to the compressed qubit and clbit representation designed for instructions at rest. It also enables transpiler passes to fully manipulate aDAGCircuitfrom Rust, enabling improvements in performance. -
A new argument
qubits_initially_zerohas been added toqiskit.compiler.transpile(),generate_preset_pass_manager(), and toPassManagerConfig. If set to the default value ofTrue, the qubits are assumed to be initially in the state , potentially allowing additional optimization opportunities for individual transpiler passes. In particular, theHighLevelSynthesistranspiler pass will choose a better decomposition for eachMCXGategate in a circuit when an idle auxiliary qubit in the state is available.However, there are cases when
qubits_initially_zeroshould be set toFalse, such as when transpiling for backends that do not properly initialize qubits, or when manually calling transpiler passes on subcircuits of a larger quantum circuit. -
The constructor for the
HighLevelSynthesistranspiler pass now accepts an additional argument:qubits_initially_zero. If set toTrue, the pass assumes that the qubits are initially in the state . In addition, the pass keeps track of clean and dirty auxiliary qubits throughout the run, and passes this information to plugins by using kwargsnum_clean_ancillasandnum_dirty_ancillas. -
Improved handling of ancilla qubits in the
HighLevelSynthesistranspiler pass. For example, a circuit may have custom gates whose definitions includeMCXGates. Now the synthesis algorithms for the innerMCXGates can use the ancilla qubits available on the global circuit but outside the custom gates’ definitions. -
Added a new method
DAGCircuit.control_flow_op_nodes()which provides a fast path to get all theDAGOpNodein aDAGCircuitthat contain aControlFlowOp. This was possible before using theDAGCircuit.op_nodes()method and passing theControlFlowOpclass as a filter, but this new function will perform the operation faster. -
The majority of the transpiler passes used in the preset pass managers returned by
generate_preset_pass_manager()and used internally bytranspile()were ported into Rust. This has significantly improved the runtime performance of each pass which has led to a significant improvement in the overall operational efficiency of the transpiler. The list of passes ported to Rust in this release are:ConsolidateBlocksBasisTranslatorCommutationAnalysisCommutativeCancellationElidePermutationsOptimize1qGatesDecompositionUnitarySynthesisGateDirectionCheckGateDirectionRemoveDiagonalGatesBeforeMeasureCheckMapSplit2QUnitariesFilterOpNodesDepthSizeGatesInBasisInverseCancellationBarrierBeforeFinalMeasurements
-
Added a new transpiler pass,
RemoveIdentityEquivalentthat is used to remove gates that are equivalent to an identity up to some tolerance. For example if you had a circuit like:
running the pass would eliminate the
CPhaseGate:from qiskit.circuit import QuantumCircuit from qiskit.transpiler.passes import RemoveIdentityEquivalent qc = QuantumCircuit(2) qc.cp(1e-20, 0, 1) removal_pass = RemoveIdentityEquivalent() result = removal_pass(qc) result.draw("mpl")
-
The
ConsolidateBlockspass will now run the equivalent of theCollect2qBlockspass internally if it was not run in a pass manager prior to the pass. Previously,Collect2qBlocksorCollect1qRunshad to be run beforeConsolidateBlocksforConsolidateBlocksto do anything. By doing the collection internally, the overhead from the pass is reduced. IfCollect2qBlocksorCollect1qRunsare run prior toConsolidateBlocks, the collected runs by those passes from the property set are used and there is no change in behavior for the pass. -
The
RemoveDiagonalGatesBeforeMeasuretranspiler pass has been upgraded to include more diagonal gates:PhaseGate,CPhaseGate,CSGate,CSdgGateandCCZGate. In addition, the code of theRemoveDiagonalGatesBeforeMeasurewas ported to Rust, and is now x20 faster for a 20 qubit circuit.
Visualization Features
- The
timeline_drawer()visualization function has a new argumenttarget, used to specify aTargetobject for the visualization. By default the function used theInstruction.durationto get the duration of a given instruction, but specifying the target will leverage the timing details inside the target instead.
Known Issues
- When using QPY formats 10, 11, or 12 with circuits that contain
ParameterExpressions, if the version of thesymenginepackage installed in the environment that generated the payload (qpy.dump()) does not match the version ofsymengineinstalled in the enviroment where the payload is loaded (qpy.load()), you will get an error. If you encounter this error, install thesymengineversion from the error message before callingqpy.load(). QPY format versions 13 or later (or prior to 10) will not have this issue. Therefore, if you’re serializingParameterExpressionobjects as part of your circuit or anyScheduleBlockobjects, it is recommended that you use version 13 to avoid this issue in the future.
Upgrade Notes
-
The following classes now use the operation to diagonalize the Pauli-Y operator:
PauliEvolutionGate,EvolvedOperatorAnsatz, andPauliFeatureMap. Previously, these classes used either or as basis transformation. Using the operation, represented by theSXGateis more efficient as it uses only a single gate implemented as singleton.If you were relying on the previous gate usage, we recommend building the circuits with Qiskit 1.2 and exporting them with
qpy.dump(), or to write a customTransformationPass, which performs the translation to your desired basis change gate. -
The minimum supported version of Python is now 3.9, this has been raised from the previous minimum support version of 3.8. This change was necessary because the upstream cPython project no longer supports Python 3.8.
Circuits Upgrade Notes
- The
QuantumVolumeclass will generate circuits with different unitary matrices and permutations for a given seed value from the previous Qiskit release. This is due to using a new internal random number generator for the circuit generation that will generate the circuit more quickly. If you need an exact circuit with the same seed you can use the previous release of Qiskit and generate the circuit with theflatten=Trueargument and export the circuit withqpy.dump()and then load it with this release.
Primitives Upgrade Notes
- When using
BackendSamplerV2, circuit metadata is no longer cleared before passing circuits to therun()method of the wrappedBackendV2instance. If you were previously relying on this behavior you can manually clear the metadata before callingBackendSamplerV2.run()by callingcircuit.metadata.clear()
QPY Upgrade Notes
- The
qpy.dump()function now emits format version 13 by default. This means payloads generated with this function by default are only compatible with Qiskit 1.3.0 or later. If the payload needs to be loaded by an earlier version of Qiskit, use theversionflag onqpy.dump()to emit the appropriate version. Refer to QPY Compatibility for more details.
Transpiler Upgrade Notes
-
DAGNodeobjects (and its subclassesDAGInNode,DAGOutNode, andDAGOpNode) no longer return references to the same underlying object fromDAGCircuitmethods. This was never a guarantee before that all returned nodes would be shared reference to the same object. However, with the migration of theDAGCircuitto Rust, a newDAGNodeinstance is generated on the fly when a node is returned to Python. These objects will evaluate as equal using==or similar checks that rely on__eq__but will no longer identify as the same object. -
The
DAGOpNodeinstances returned from theDAGCircuitare no longer shared references to the underlying data stored on the DAG. In previous release it was possible to do something like:for node in dag.op_nodes(): node.op = new_ophowever this type of mutation was always unsound as it could break the DAG’s internal caching and cause corruption of the data structure. Instead you should use the API provided by
DAGCircuitfor mutation such asDAGCircuit.substitute_node()orDAGCircuit.substitute_node_with_dag(). For example the above code block would become:for node in dag.op_nodes(): dag.substitute_node(node, new_op)This is similar to an upgrade note from 1.2.0 where this was noted on for mutation of the
DAGOpNode.opattribute, not theDAGOpNodeitself. However in 1.3 this extends to the entire object, not just it’s inneropattribute. In general this type of mutation was always unsound and not supported, but could previously have potentially worked in some cases. -
The
transpile()now assumes that the qubits are initially in the state . To avoid this assumption, one can set the argumentqubits_initially_zerotoFalse.
Deprecation Notes
-
The
qiskit.pulsemodule and all it’s associated features is now deprecated and will be removed in Qiskit 2.0.0. This is because primary backend provider with pulse support is IBM and pulse-level access is currently only supported on a subset of IBM’s backends is not supported on their newer architectures. Similarly they have announced that pulse level access will be removed in 2025 Without the largest provider using the feature supporting pulse access anymore the importance of the feature to Qiskit is significantly dimished and weighed against the continued maintanence overhead of the package it is beign removed.The deprecation includes all pulse code in
qiskit.pulseas well as functionality dependent on or related to pulse, such as pulse visualization, serialization, and custom calibration support. For more details see the deprecation sections below.The Pulse package as a whole, along with directly related components in Qiskit, will be moved to the Qiskit Dynamics repository to further enable pulse and low-level control simulation. Qiskit 1.x will continue to support the
qiskit.pulseuntil it goes end-of-life.
Circuits Deprecations
-
Deprecated the
Instruction.conditionattribute and theInstruction.c_if()method. They will be removed in Qiskit 2.0, along with any uses in the Qiskit data model. This functionality has been superseded by theIfElseOpclass which can be used to describe a classical condition in a circuit. For example, a circuit usingInstruction.c_if()like:from qiskit.circuit import QuantumCircuit qc = QuantumCircuit(2, 2) qc.h(0) qc.x(0).c_if(0, 1) qc.z(1.c_if(1, 0) qc.measure(0, 0) qc.measure(1, 1)can be rewritten as:
qc = QuantumCircuit(2, 2) qc.h(0) with qc.if_test((qc.clbits[0], True)): qc.x(0) with qc.if_test((qc.clbits[1], False)): qc.z(1) qc.measure(0, 0) qc.measure(1, 1)The now deprecated
ConvertConditionsToIfOpstranspiler pass can be used to automate this conversion for existing circuits. -
As part of the Qiskit Pulse package deprecation, the following dependencies are deprecated as well:
qiskit.circuit.QuantumCircuit.calibrationsqiskit.circuit.QuantumCircuit.has_calibration_for()qiskit.circuit.QuantumCircuit.add_calibration()qiskit.dagcircuit.DAGCircuit.calibrationsqiskit.dagcircuit.DAGCircuit.has_calibration_for()qiskit.dagcircuit.DAGCircuit.add_calibration()qiskit.dagcircuit.DAGDependency.calibrations
-
The
QuantumCircuit.unitandQuantumCircuit.durationattributes have been deprecated and will be removed in Qiskit 2.0.0. These attributes were used to track the estimated duration and unit of that duration to execute on the circuit. However, the values of these attributes were always limited, as they would only be properly populated if the transpiler were run with the correct settings. The duration was also only a guess based on the longest path on the sum of the duration ofDAGCircuitand wouldn’t ever correctly account for control flow or conditionals in the circuit. -
The
DAGCircuit.unitandDAGCircuit.durationattributes have been deprecated and will be removed in Qiskit 2.0.0. These attributes were used to track the estimated duration and unit of that duration to execute on the circuit. However, the values of these attributes were always limited, as they would only be properly populated if the transpiler were run with the correct settings. The duration was also only a guess based on the longest path on the sum of the duration ofDAGCircuitand wouldn’t ever correctly account for control flow or conditionals in the circuit. -
The
Instruction.durationandInstruction.unitattributes have been deprecated and will be removed in Qiskit 2.0.0. This includes setting theunitordurationarguments for anyqiskit.circuit.Instructionor subclass. These attributes were used to attach a custom execution duration and unit for that duration to an individual instruction. However, the source of truth of the duration of a gate is theBackendV2Targetwhich contains the duration for each instruction supported on the backend. The duration of an instruction is not something that’s typically user adjustable and is an immutable property of the backend. If you were previously using this capability to experiment with different durations for gates you can mutate theInstructionProperties.durationfield in a givenTargetto set a custom duration for an instruction on a backend (the unit is always in seconds in theTarget).
Providers Deprecations
-
The
BasicSimulator.configuration()method is deprecated and will be removed in 2.0.0. This method returned a legacyproviders.models.BackendConfigurationinstance which is part of the deprecatedBackendV1model. This model has been replaced withBackendV2, where the constraints are stored directly in the backend instance or the underlyingTarget(backend.target).Here is a quick guide for accessing the most common
BackendConfigurationattributes in theBackendV2model:BackendV1 model (deprecated) ------------> BackendV2 model ---------------------------- --------------- backend.configuration().backend_name backend.name backend.configuration().backend_version backend.backend_version backend.configuration().n_qubits backend.num_qubits backend.configuration().num_qubits backend.num_qubits backend.configuration().basis_gates backend.target.operation_names (*) backend.configuration().coupling_map backend.target.build_coupling_map() backend.configuration().local No representation backend.configuration().simulator No representation backend.configuration().conditional No representation backend.configuration().open_pulse No representation backend.configuration().memory No representation backend.configuration().max_shots No representation(*) Note that
Backend.target.operation_namesincludesbasis_gatesand additional non-gate instructions, in some implementations it might be necessary to filter the output.See this guide for more information on migrating to the
BackendV2model. -
As part of the Qiskit Pulse package deprecation, all pulse-related functionality in
qiskit.providers.BackendV2class is being deprecated. This includes the following methods:Consequently, the corresponding channel methods in the
qiskit.providers.BackendV2Converterandqiskit.providers.fake_provider.GenericBackendV2classes are being deprecated as well.In addition, the
pulse_channelsandcalibrate_instructionsarguments in theBackendV2initializer method are being deprecated. -
The
defaultsargument is being deprecated from theqiskit.providers.convert_to_target()function.
QPY Deprecations
- As part of the Qiskit Pulse package deprecation, serializing
qiskit.pulse.ScheduleBlock-based payloads is also being deprecated. Particularly the passing ofqiskit.pulse.ScheduleBlockobjects to the programs argument in theqiskit.qpy.dump().
Transpiler Deprecations
-
Deprecated
StochasticSwapwhich has been superseded bySabreSwap. If the class is called from the transpile function, the change would be, for example:from qiskit import transpile from qiskit.circuit import QuantumCircuit from qiskit.transpiler import CouplingMap from qiskit.providers.fake_provider import GenericBackendV2 qc = QuantumCircuit(4) qc.h(0) qc.cx(0, range(1, 4)) qc.measure_all() cmap = CouplingMap.from_heavy_hex(3) backend = GenericBackendV2(num_qubits=cmap.size(), coupling_map=cmap) tqc = transpile( qc, routing_method="stochastic", layout_method="dense", seed_transpiler=12342, target=backend.target )to:
tqc = transpile( qc, routing_method="sabre", layout_method="sabre", seed_transpiler=12342, target=backend.target )While for a pass manager, the change would be:
passmanager = PassManager(StochasticSwap(coupling, 20, 13)) new_qc = passmanager.run(qc)to:
passmanager = PassManager(SabreSwap(backend.target, "basic")) new_qc = passmanager.run(qc) -
The transpiler pass
ConvertConditionsToIfOpshas been deprecated and will be removed in Qiskit 2.0.0. This class is now deprecated because the underlying data model forInstruction.conditionwhich this pass is converting from has been deprecated and will be removed in 2.0.0. -
Providing custom gates through the
basis_gatesargument is deprecated for bothtranspile()andgenerate_preset_pass_manager(). This functionality will be removed in Qiskit 2.0. Custom gates are still supported in theTargetmodel, and can be provided through thetargetargument. One can build aTargetinstance from scratch or use theTarget.from_configuration()method with thecustom_name_mappingargument. For example:from qiskit.circuit.library import XGate from qiskit.transpiler.target import Target basis_gates = ["my_x", "cx"] custom_name_mapping = {"my_x": XGate()} target = Target.from_configuration( basis_gates=basis_gates, num_qubits=2, custom_name_mapping=custom_name_mapping ) -
As part of the Qiskit Pulse package deprecation, pulse-related aspects in the
qiskit.transpiler.Targetclass are being deprecated. These include:update_from_instruction_schedule_map()has_calibration()get_calibration()instruction_schedule_map()
In addition, the following transpiler passes are also being deprecated:
-
The
inst_mapargument ingenerate_preset_pass_manager(),from_configuration(),PassManagerConfiginitializer andgenerate_scheduling()is being deprecated. -
The
calibrationargument inInstructionProperties()initializer methods is being deprecated. -
The following
transpile()andgenerate_preset_pass_manager()arguments are deprecated in favor of defining a customTarget:instruction_durations,timing_constraints, andbackend_properties. These arguments can be used to build a target withTarget.from_configuration():Target.from_configuration( ... backend_properties = backend_properties, instruction_durations = instruction_durations, timing_constraints = timing_constraints ) -
The method
PassManagerConfig.from_backend()will stop supporting inputs of typeBackendV1in the backend parameter in a future release no earlier than 2.0.BackendV1is deprecated and implementations should move toBackendV2.
Misc. Deprecations
-
The
qiskit.result.mitigationmodule has been deprecated and will be removed in Qiskit 2.0. The deprecation includes theLocalReadoutMitigatorandCorrelatedReadoutMitigatorclasses as well as the associated utility functions. Their functionality has been superseded by the mthree package, found in https://github.com/Qiskit/qiskit-addon-mthree. -
As part of the Qiskit Pulse package deprecation, the following functions and class are being deprecated as well:
Bug Fixes
-
Fixed a performance regression in
QuantumCircuit.assign_parameters()introduced in Qiskit 1.2.0 when calling the method in a tight loop, that caused only a small number of parameters from a heavily parametric circuit to be bound on each iteration. If possible, it is still more performant to callassign_parameters()only once, with all assignments at the same time, as this reduces the proportion of time spent on input normalization and error-checking overhead. -
For
BasicSimulator, thebasis_gatesentry in the configuration instance returned by theconfiguration()method is now a list instead of adict_keysinstance, matching the expected type and allowing for configuration instance to be deep copied. -
Fixed an issue with
DAGCircuit.apply_operation_back()andDAGCircuit.apply_operation_front()where previously if you set aClbitobject to the input for theqargsargument it would silently be accepted. This has been fixed so the type mismatch is correctly identified and an exception is raised. -
Fixed a missing decorator in
C3SXGatethat made it fail ifGate.to_matrix()was called. The gate matrix is now return as expected. -
Fixed a bug in
QuantumCircuit.assign_parameters(), occurring when assigning parameters to standard gates whose definition has already been triggered. In this case, the new values were not properly propagated to the gate instances. While the circuit itself was still compiled as expected, inspecting the individual operations would still show the old parameter.For example:
from qiskit.circuit.library import EfficientSU2 circuit = EfficientSU2(2, flatten=True) circuit.assign_parameters([1.25] * circuit.num_parameters, inplace=True) print(circuit.data[0].operation.params) # would print θ[0] instead of 1.25Fixed #13478.
-
Fixed a bug with the
"circular"and"sca"entanglement forNLocalcircuits and its derivatives. For entanglement blocks of more than 2 qubits, the circular entanglement was previously missing some connections. For example, for 4 qubits and a block size of 3 the code previously used:[(2, 3, 0), (0, 1, 2), (1, 2, 3)]but now is correctly adding the
(3, 0, 1)connections, that is:[(2, 3, 0), (3, 0, 1), (0, 1, 2), (1, 2, 3)]As such, the
"circular"and"sca"entanglements usenum_qubitsentangling blocks per layer. -
Add more Clifford gates to the
CollectCliffordstranspiler pass. In particular, we have added the gatesECRGate,DCXGate,iSwapGate,SXGateandSXdgGateto this transpiler pass. -
Fixed a bug in
QuantumCircuit.decompose()where objects that could be synthesized withHighLevelSynthesiswere first synthesized and then decomposed immediately (i.e., they were decomposed twice instead of once). This affected gates such asMCXGateorClifford, among others. -
Fixed a bug in
QuantumCircuit.decompose(), where high-level objects without a definition were not decomposed if they were explicitly set via the"gates_to_decompose"argument. For example, previously the following did not perform a decomposition but now works as expected:from qiskit import QuantumCircuit from qiskit.quantum_info import Clifford from qiskit.transpiler.passes import Decompose cliff = Clifford(HGate()) circuit = QuantumCircuit(1) circuit.append(cliff, [0]) decomposed = Decompose(gates_to_decompose=["clifford"])(circuit) -
Previously the
HighLevelSynthesistranspiler pass synthesized an instruction for which a synthesis plugin is available, regardless of whether the instruction is already supported by the target or a part of the explicitly passedbasis_gates. This behavior is now fixed, so that such already supported instructions are no longer synthesized. -
The transpilation pass
InverseCancellationnow will recurse intoControlFlowOpoperations present in aQuantumCircuit. Previously, the pass would ignore inverse gate pairs inside control flow blocks that could have been cancelled. Refer to #13437 for more details. -
Fix a bug in
Isometrydue to an unnecessary assertion, that led to an error inUnitaryGate.control()whenUnitaryGatehad more that two qubits. -
The
QuantumCircuit.parametersattribute will now correctly be empty when usingQuantumCircuit.copy_empty_like()on a parametric circuit. Previously, an internal cache would be copied over without invalidation. Fix #12617. -
QuantumCircuit.depth()will now correctly handle operations that do not have operands, such asGlobalPhaseGate. -
QuantumCircuit.depth()will now count the variables and clbits used in real-time expressions as part of the depth calculation. -
Fix the
SolovayKitaevtranspiler pass when loading basic approximations from an exising.npyfile. Previously, loading a stored approximation which allowed for further reductions (e.g. due to gate cancellations) could cause a runtime failure. Additionally, the global phase difference of the U(2) gate product and SO(3) representation was lost during a save-reload procedure. Fixes Qiskit/qiskit#12576. -
Fixed a bug when
SparsePauliOp.paulisis set to be aPauliListwith nonzero phase, where subsequent calls to severalSparsePauliOpmethods would produce incorrect results. Now whenSparsePauliOp.paulisis set to aPauliListwith nonzero phase, the phase is absorbed intoSparsePauliOp.coeffs, and the phase of the inputPauliListis set to zero. -
Fixed a bug in
qiskit.visualization.pulse_v2.interface.drawthat didn’t draw pulse schedules when the draw function was called with aBackendV2argument. Because the V2 backend doesn’t report hardware channel frequencies, the generated drawing will show ‘no freq.’ below each channel label. -
Fixed an issue with
dag_drawer()andDAGCircuit.draw()when attempting to visualize aDAGCircuitinstance that containedVarwires, for which the visualizer would raise an exception. This behavior has been fixed and the expected visualization will be generated. -
The
VF2Layoutpass would raise an exception when provided with aTargetinstance without connectivity constraints. This would be the case with targets from Aer 0.13. The issue is now fixed. -
Fixes an error when calling the method
Gate.repeat(). Refer to #11990 for more details. -
Fixed a bug that caused
Statevector.expectation_value()to yield incorrect results for the identity operator when the statevector was not normalized. -
The constructor
GenericBackendV2was allowing you to create malformed backends because it accepted basis gates that couldn’t be allocated in the specified backend size. That is, a backend with a single qubit should not accept a basis with two-qubit gates. -
ParameterExpressionwas updated so that fully bound instances that compare equal to instances of Python’s built-in numeric types (likefloatandint) also have hash values that match those of the other instances. This change ensures that these types can be used interchangeably as dictionary keys. See #12488. -
The OpenQASM 2 parser (
qiskit.qasm2) can now handle conditionals with integers that do not fit within a 64-bit integer. Fixed #12773. -
Custom gates (those stemming from a
gatestatement) in imported OpenQASM 2 programs will now have anGate.to_matrix()implementation. Previously they would have no matrix definition, meaning that roundtrips through OpenQASM 2 could needlessly lose the ability to derive the gate matrix. Note, though, that the matrix is calculated by recursively finding the matrices of the inner gate definitions, asOperatordoes, which might be less performant than before the round-trip. -
Previously,
DAGCircuit.replace_block_with_op()allowed to place ann-qubit operation onto a block ofmqubits, leaving the DAG in an invalid state. This behavior has been fixed, and the attempt will raise aDAGCircuitError. -
Fixed
Operator.power()when called with non-integer powers on a matrix whose Schur form is not diagonal (for example, most non-unitary matrices). -
Operator.power()will now more reliably return the expected principal value from a fractional matrix power of a unitary matrix with a eigenvalue. This is tricky in general, because floating-point rounding effects can cause a matrix to _truly_ have an eigenvalue on the negative side of the branch cut (even if its exact mathematical relation would not), and imprecision in various BLAS calls can falsely find the wrong side of the branch cut.Operator.power()now shifts the branch-cut location for matrix powers to be a small complex rotation away from . This does not solve the problem, it just shifts it to a place where it is far less likely to be noticeable for the types of operators that usually appear. Use the newbranch_cut_rotationparameter to have more control over this.See #13305.
-
Fixed a per-process based non-determinism in
SparsePauliOp.to_matrix(). The exact order of the floating-point operations in the summation would previously vary per process, but will now be identical between different invocations of the same script. See #13413. -
Target.has_calibration()has been updated so that it does not raise an exception for an instruction that has been added to the target withNonefor its instruction properties. Fixes #12525.