260 lines
15 KiB
Plaintext
260 lines
15 KiB
Plaintext
---
|
|
title: Qiskit v2.0 migration guide
|
|
description: How to update your project so that it works with Qiskit v2.0.
|
|
---
|
|
|
|
{/* cspell:ignore nbqa, ipynb, tqdm */}
|
|
|
|
# Qiskit v2.0 migration guide
|
|
|
|
Qiskit v2.0 is the next step within the Qiskit SDK's newly stabilized life cycle.
|
|
This major version does break compatibility with previous versions of Qiskit, but,
|
|
in contrast to the v1.0 release, doesn't involve any changes in the packaging structure.
|
|
|
|
This guide describes migration paths for the most important feature changes in Qiskit v2.0, organized by module.
|
|
Use the table of contents on the right side to navigate to the module you are interested in.
|
|
|
|
Read more about the benefits of Qiskit v2.0 on the [IBM® blog](https://www.ibm.com/quantum/blog/qiskit-1-0-release-summary).
|
|
|
|
<span id="qiskit.circuit"></span>
|
|
## qiskit.circuit
|
|
|
|
<span id="c_if"></span>
|
|
### Removal of legacy `c_if` conditions
|
|
|
|
Classical conditions in Qiskit have been preferentially represented by the instruction [`IfElseOp`](/api/qiskit/qiskit.circuit.IfElseOp) since before Qiskit v1.0.
|
|
These operations are typically added to a [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit) by using the [`if_test`](/api/qiskit/qiskit.circuit.QuantumCircuit#qiskit.circuit.QuantumCircuit.if_test) method as a context manager.
|
|
|
|
This also means that the [`Instruction`](/api/qiskit/qiskit.circuit.Instruction) no longer has a `condition` attribute, and that you cannot chain `c_if` calls on the output of a [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit) gate-creating method call.
|
|
|
|
The only instructions that might have a condition now are [`IfElseOp`](/api/qiskit/qiskit.circuit.IfElseOp) and [`WhileLoopOp`](/api/qiskit/qiskit.circuit.WhileLoopOp).
|
|
The most correct way to test for a condition is to use an `isinstance` check to validate that you have the correct class.
|
|
If you want to support the legacy `Instruction.condition` attribute during your library's transition to Qiskit v2.0 and later, you can use `getattr(operation, "condition", None)`, which will typically cause `Instruction` instances to behave as they did in Qiskit v1.x and earlier.
|
|
|
|
The original, legacy method of supporting simple register-equality conditions in Qiskit was to use the `c_if` method on individual instructions or instruction sets.
|
|
This was strictly less featureful than the full control-flow form, and was never well-supported on hardware.
|
|
This legacy method has been removed in Qiskit v2.0; you should use the [`if_test`](/api/qiskit/qiskit.circuit.QuantumCircuit#qiskit.circuit.QuantumCircuit.if_test) method with a proper condition.
|
|
You can continue to use the 2-tuple form of `(register, integer)` to represent a register equality, or you can use the more expressive [classical computation subsystem](/api/qiskit/circuit_classical) to represent more complex conditions.
|
|
|
|
For example, you might have written:
|
|
|
|
```python
|
|
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
|
|
|
qr = QuantumRegister(2, "q")
|
|
cr = ClassicalRegister(2, "c")
|
|
qc = QuantumCircuit(qr, cr)
|
|
qc.h(0)
|
|
qc.h(1)
|
|
qc.measure(qr, cr)
|
|
|
|
# Apply an X to qubit 0 if both measurements were 1.
|
|
qc.x(0).c_if(cr, 3)
|
|
```
|
|
|
|
The most direct translation of this is to use the 2-tuple form with the [`if_test`](/api/qiskit/qiskit.circuit.QuantumCircuit#qiskit.circuit.QuantumCircuit.if_test) context manager:
|
|
|
|
```python
|
|
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
|
|
|
qr = QuantumRegister(2, "q")
|
|
cr = ClassicalRegister(2, "c")
|
|
qc = QuantumCircuit(qr, cr)
|
|
qc.h(0)
|
|
qc.h(1)
|
|
qc.measure(qr, cr)
|
|
|
|
# Apply an X to qubit 0 if both measurements were 1.
|
|
with qc.if_test((cr, 3)):
|
|
qc.x(0)
|
|
```
|
|
|
|
Note that in this form, you can also have the conditional gate access to multiple operations (simply add more into the indented block) without re-evaluating the conditions.
|
|
You can also provide an ``else`` statement, and use more complex conditional logic:
|
|
|
|
```python
|
|
from qiskit.circuit import QuantumCircuit
|
|
from qiskit.circuit.classical import expr
|
|
|
|
qc = QuantumCircuit(2, 2)
|
|
qc.h(0)
|
|
qc.h(1)
|
|
qc.measure(qc.qubits, qc.clbits)
|
|
|
|
# Apply an X to qubit 0 if both measurements were the same:
|
|
with qc.if_test(expr.equal(qc.clbits[0], qc.clbits[1])) as else_:
|
|
qc.x(0)
|
|
# ... or apply a Y to both qubits otherwise:
|
|
with else_:
|
|
qc.y(0)
|
|
qc.y(1)
|
|
```
|
|
|
|
|
|
<span id="instruction_durations"></span>
|
|
### Removal of `Instruction.duration` and `Instruction.unit`
|
|
|
|
Circuit [`Instruction`](/api/qiskit/qiskit.circuit.Instruction) objects previously had attributes called `duration` and `unit`.
|
|
These no longer exist in Qiskit v2.0.
|
|
This is because the field generally only duplicated information that was a fixed property of hardware, and was stored explicitly in the [`Target`](/api/qiskit/qiskit.transpiler.Target).
|
|
Storing the information separately for each individual instruction significantly increased the memory demands of Qiskit and slowed down even circuit operations that did not directly need to touch the information.
|
|
|
|
The [`Delay`](/api/qiskit/circuit#delay) instruction still contains these fields, as does the new-in-v2.0 [`BoxOp`](/api/qiskit/qiskit.circuit.QuantumCircuit#box), because these instructions have a _variable_ delay.
|
|
|
|
You can retrieve the hardware-specified duration of a particular hardware-supported [`Instruction`](/api/qiskit/qiskit.circuit.Instruction) by querying the [`Target`](/api/qiskit/qiskit.transpiler.Target).
|
|
To do this, index the [`Target`](/api/qiskit/qiskit.transpiler.Target) first with the operation's name, and then the indices of the hardware qubits as a tuple.
|
|
This will return either `None` (if the instruction is supported, but no specific properties were assigned to it), or an [`InstructionProperties`](/api/qiskit/qiskit.transpiler.InstructionProperties) instance, from which the [`duration`](/api/qiskit/qiskit.transpiler.InstructionProperties#qiskit.transpiler.InstructionProperties.duration) field may provide the duration in seconds (or `None`, if not supplied).
|
|
|
|
```python
|
|
target = "<some Target from a hardware vendor>"
|
|
|
|
# Query the duration of a CX instruction on hardware qubits (2, 4),
|
|
# returning `None` if the duration is not specified.
|
|
properties = target["cx"][2, 4]
|
|
duration = None if properties is None else properties.duration
|
|
|
|
# You can also do this in one step, using `getattr`:
|
|
duration = getattr(target["cx"][2, 4], "duration", None)
|
|
```
|
|
|
|
In general, as classical control-flow becomes more common within circuit executions, the "duration" of a circuit will become less and less well defined.
|
|
While Qiskit v2.x still includes the [`QuantumCircuit.duration`](/api/qiskit/qiskit.circuit.QuantumCircuit#qiskit.circuit.QuantumCircuit.duration) attribute, it is recommended to move away from it, as it will likely be removed in the future; the assumptions under which it is valid will be violated more and more frequently.
|
|
Instead, you can use the new [`QuantumCircuit.estimate_duration`](/api/qiskit/qiskit.circuit.QuantumCircuit#qiskit.circuit.QuantumCircuit.estimate_duration) method, which is safer and clearer about the necessary assumptions.
|
|
|
|
|
|
<span id="qiskit.transpiler"></span>
|
|
## qiskit.transpiler
|
|
|
|
<span id="generate_preset_pass_manager"></span>
|
|
### Changes to `generate_preset_pass_manager` interface
|
|
|
|
Qiskit v2.0.0 includes a series of updates to the preset pass manager interface (that is, the
|
|
[`generate_preset_pass_manager`](/api/qiskit/qiskit.transpiler.generate_preset_pass_manager) and
|
|
[`transpile`](/api/qiskit/compiler#transpile) functions) that affect the
|
|
handling of loose constraint inputs, such as `coupling_map` or `basis_gates`. The number of
|
|
transpilation use cases where loose constraints are accepted has been reduced in favor of the
|
|
`target` and `backend` inputs (where `backend` is a [`BackendV2`](/api/qiskit/qiskit.providers.BackendV2) that
|
|
contains a [`Target`](/api/qiskit/qiskit.transpiler.Target) instance),
|
|
which allow for a more expressive communication of these constraints.
|
|
|
|
The following examples show the main changes and suggested alternatives for migrating. Note that all
|
|
of the migration tips below apply to both `transpile` and `generate_preset_pass_manager`:
|
|
|
|
1. The `backend_properties` input argument is no longer supported, and the `BackendProperties` class has
|
|
been removed. You should use the `target` or `backend` arguments instead to communicate
|
|
gate durations and errors. There are multiple paths for constructing a custom [`Target`](/api/qiskit/qiskit.transpiler.Target):
|
|
|
|
a. Build a target from scratch and add the relevant errors and durations to the corresponding gates:
|
|
|
|
```python
|
|
from qiskit.transpiler import Target, InstructionProperties, generate_preset_pass_manager
|
|
from qiskit.circuit.library import XGate, CXGate
|
|
|
|
target = Target(num_qubits=2)
|
|
target.add_instruction(CXGate(), {(0, 1): InstructionProperties(error=.0001, duration=5e-7)})
|
|
target.add_instruction(
|
|
XGate(),
|
|
{
|
|
(0,): InstructionProperties(error=.00001, duration=5e-8),
|
|
(1,): InstructionProperties(error=.00002, duration=6e-8)
|
|
}
|
|
)
|
|
|
|
pm = generate_preset_pass_manager(target=target)
|
|
```
|
|
|
|
b. Use [`GenericBackendV2`](/api/qiskit/qiskit.providers.fake_provider.GenericBackendV2) to quickly build a
|
|
generic target with pre-filled errors and durations. These can also be updated post-construction:
|
|
|
|
```python
|
|
from qiskit.providers.fake_provider import GenericBackendV2
|
|
from qiskit.transpiler import generate_preset_pass_manager
|
|
|
|
target = GenericBackendV2(num_qubits=2, basis_gates=["x", "cx"]).target
|
|
target.update_instruction_properties("x", (0,), InstructionProperties(0.00001))
|
|
target.update_instruction_properties("x", (1,), InstructionProperties(0.00002))
|
|
target.update_instruction_properties("cx", (0, 1), InstructionProperties(0.0001))
|
|
|
|
pm = generate_preset_pass_manager(target=target)
|
|
```
|
|
|
|
2. The `instruction_durations` and `timing_constraints` input arguments are no longer supported. You should use the
|
|
`target` or `backend` arguments instead. The alternatives are constructing a custom [`Target`](/api/qiskit/qiskit.transpiler.Target) from
|
|
scratch, constructing a generic backend, and, in addition to these, it is possible to build a custom target with
|
|
`instruction_durations` and/or `timing_constraints` using the `Target.from_configuration` method:
|
|
|
|
```python
|
|
from qiskit.transpiler import Target, generate_preset_pass_manager
|
|
from qiskit.transpiler.timing_constraints import TimingConstraints
|
|
from qiskit.transpiler.instruction_durations import InstructionDurations
|
|
|
|
instruction_durations = InstructionDurations([("x", None, 200), ("cx", None, 1000)], dt=1e-7)
|
|
|
|
timing_constraints = TimingConstraints(
|
|
granularity=1, min_length=1, pulse_alignment=1, acquire_alignment=1
|
|
)
|
|
|
|
target = Target.from_configuration(num_qubits=2,
|
|
basis_gates=["x", "cx"],
|
|
instruction_durations=instruction_durations,
|
|
timing_constraints=timing_constraints)
|
|
|
|
pm = generate_preset_pass_manager(target=target)
|
|
```
|
|
|
|
3. Providing `coupling_map` and/or `basis_gates` along with a `backend` is discouraged, and from
|
|
v2.0 a `UserWarning` will be raised. In these cases there are multiple sources of truth,
|
|
and information such as gate errors and durations from the backend cannot be resolved based on the
|
|
information given.
|
|
The suggested alternative is to define a custom target that combines the chosen constraints either
|
|
from scratch, using [`Target.from_configuration`](/api/qiskit/qiskit.transpiler.Target#from_configuration) or [`GenericBackendV2`](/api/qiskit/qiskit.providers.fake_provider.GenericBackendV2).
|
|
|
|
4. The `basis_gates` argument no longer accepts custom basis gates. The suggested alternative
|
|
is the `target` argument, which can be built from scratch or through [`Target.from_configuration`](/api/qiskit/qiskit.transpiler.Target#from_configuration)
|
|
such as:
|
|
|
|
```python
|
|
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
|
|
)
|
|
pm = generate_preset_pass_manager(target=target)
|
|
```
|
|
|
|
5. The input combination where a custom `coupling_map` is provided with either a `backend` or `basis_gates`
|
|
that contain gates with three or more qubits is no longer allowed. The coupling map
|
|
does not provide the necessary connectivity details to be able to determine the action of the gate.
|
|
In these cases, the recommended migration path is the creation of a custom target from scratch.
|
|
|
|
6. The `inst_map` argument has been removed without alternative. It was used to provide pulse information
|
|
to the transpiler, and the full `qiskit.pulse` module has been removed.
|
|
|
|
|
|
<span id="qiskit.pulse"></span>
|
|
## qiskit.pulse
|
|
|
|
The module `qiskit.pulse` has been completely removed from Qiskit, without replacement.
|
|
This includes the related items:
|
|
|
|
- the [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit), [`DAGCircuit`](/api/qiskit/qiskit.dagcircuit.DAGCircuit) and [`DAGDependency`](/api/qiskit/qiskit.dagcircuit.DAGDependency) property `calibrations`.
|
|
- the [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit) methods `has_calibration_for` and `add_calibration`.
|
|
- the [`DAGCircuit`](/api/qiskit/qiskit.dagcircuit.DAGCircuit) method `has_calibration_for`.
|
|
- the transpiler passes `PulseGates`, `RXCalibrationBuilder`, `RZXCalibrationBuilder`, `EchoRZXWeylDecomposition`, `ValidatePulseGates`.
|
|
- the module `qiskit.scheduler` and all its contents.
|
|
- the [`BackendV2`](/api/qiskit/qiskit.providers.BackendV2) methods `instruction_schedule_map`, `drive_channel`, `measure_channel`, `acquire_channel` and `control_channel`.
|
|
- the [`Target`](/api/qiskit/qiskit.transpiler.Target) methods `has_calibration`, `get_calibration`, `instruction_schedule_map` and `update_from_instruction_schedule_map`.
|
|
- the `inst_map` argument of [`generate_preset_pass_manager`](/api/qiskit/qiskit.transpiler.generate_preset_pass_manager), [`transpile`](/api/qiskit/compiler#transpile), and [`Target.from_configuration`](/api/qiskit/qiskit.transpiler.Target#qiskit.transpiler.Target.from_configuration).
|
|
- the `calibration` field of [`InstructionProperties`](/api/qiskit/qiskit.transpiler.InstructionProperties).
|
|
|
|
This happened because IBM Quantum® QPUs ceased to offer pulse-level access, and the Qiskit team no longer had resources to maintain the little-used package.
|
|
You can continue to use the `qiskit.pulse` module while using the v1.x series of Qiskit, which has bug-fix support until September 2024 and security support until March 2025, but the module is removed from the v2.x series.
|
|
|
|
Most uses of `qiskit.pulse` can be replaced with direct access to fractional gates on IBM Quantum Heron QPUs (and later generations, if applicable).
|
|
You can read more in [the migration guide for converted pulse usage to fractional gates](/migration-guides/pulse-migration).
|
|
|
|
You can no longer load QPY files that contain `ScheduleBlock` objects in Qiskit v2.0 because of the removal of Qiskit Pulse.
|
|
You can continue to load these files in the Qiskit v1.x series. |