Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transpiler integration refactor and qiskit v1.2 support #116

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
675533e
Minimal changes to support qiskit v1.2 - layout preservation of trans…
Sep 5, 2024
9fb91ee
Update version
Sep 5, 2024
1dd4b29
removed unused import
Sep 5, 2024
d481364
Merge https://github.com/iqm-finland/qiskit-on-iqm into qiskit-v1.2
Nov 1, 2024
a22d8db
typo
Nov 1, 2024
5ece8fa
pylint
Nov 1, 2024
5ab12d8
Fixed DQA integration. Transpiler still broken
Nov 1, 2024
6be92bb
Merge https://github.com/iqm-finland/qiskit-on-iqm into qiskit-v1.2
Nov 1, 2024
422eb93
formatting
Nov 1, 2024
1460a20
Buggy Implementation of the foundation of the transpiler integration.
Nov 1, 2024
5bb86c0
Native qiskit tranpsiler integration.
Nov 28, 2024
a0ad923
Qiskit transpiler refactor
Dec 10, 2024
6955de6
Merge https://github.com/iqm-finland/qiskit-on-iqm into qiskit-v1.2
Dec 10, 2024
eb275f2
change the fidelity number to error
Oct 30, 2024
92a5641
Deneb fix changelog update
Dec 10, 2024
99b8ed7
Updated user guide with new transpiler information
Dec 10, 2024
33296c1
Updated documentation
Dec 10, 2024
547f0ea
Removed Brittish spelling
Dec 10, 2024
b5e9e04
fixed docs
Dec 10, 2024
ea4d1bc
Fixes.
Dec 11, 2024
0f5cbe5
Changes to reflect supported CZ directions as calibrated in the hardware
Dec 12, 2024
82fc6a3
Update changelog
Dec 12, 2024
5fd22e3
fix typo
Dec 12, 2024
c56d86c
fix pylint
Dec 12, 2024
4206c1a
Delete accidental files
Dec 12, 2024
75ef5e3
fix new error message test
Dec 12, 2024
f333454
Update doc string
Dec 12, 2024
836c26f
Drop qiskit 0.45 support
Dec 12, 2024
8fadfca
Update iqmtarget docstring
Dec 12, 2024
bf46609
Removed the measure gate as a special case gate when converting a sqa…
Dec 12, 2024
be65521
Added a section of transpiler plugins
Dec 12, 2024
177fb05
Added directional CZs
Dec 12, 2024
e2e52a4
Merge branch 'directionalCZs' of https://github.com/iqm-finland/qiski…
Dec 12, 2024
0d4add2
Removed flaky duplicated assert
Dec 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,53 @@
Changelog
=========

Version 16.0
=============

* Added support for ``qiskit == 1.2`` and ``qiskit-aer == 0.15``.
* Drop support for ``qiskit < 0.45``.
* :meth:`IQMBackendBase.qubit_name_to_index` and :meth:`IQMBackendBase.index_to_qubit_name` now
raises an error when using an invalid qubit name or index, rather than returning None.
* Refactored :meth:`IQMBackend.create_run_request` to improve user experience when using IQM
specific run options.
* Updated the documentation for using additional run options with IQM backends.
* Introduced :attr:`IQMBackendBase.physical_target` and :attr:`IQMBackendBase.fake_target` to
represent the physical quantum architectures and a Qiskit-compatible version, respectively.
* Moved the circuit serialization logic from :class:`IQMProvider` to :mod:`iqm.qiskit_iqm.qiskit_to_iqm`.
* Using the Qiskit transpiler with :class:`IQMBackend`:

* You can now use the native Qiskit :func:`transpile` function to transpile a circuit to the IQM
Star architecture as long as your initial circuit does not use any resonators.
* The Qiskit transpiler now automatically uses the :class:`IQMOptimizeSingleQubitGates` pass to
optimize single-qubit gates if ``optimization_level >= 0``.
* There are many new transpiler plugins available that you can use as the ``scheduling_method``
argument in Qiskit's :func:`transpile` function. You can find them in the
`Qiskit documentation <https://docs.quantum.ibm.com/guides/transpiler-plugins>`_.
* If your circuit contains resonators, and optionally :class:`MoveGate` operations, you can use
the :func:`transpile_to_IQM` function to transpile your circuit for the IQM Star architecture.
* :func:`transpile_to_IQM` can now restrict itself to use a subset of the qubits by specifying
the ``restrict_to_qubits`` argument. You will need to additionally provide a qubit mapping to the
:meth:`backend.run` method to ensure that the correct qubits are used.
* Bugfix where the :func:`transpile_to_IQM` did not retain the circuit layout after transpiling.

* Fixed :func:`IQMFakeDeneb` readout errors. Fidelities were reported as errors. `#125 <https://github.com/iqm-finland/qiskit-on-iqm/pull/125>`_
* Deprecated features:

* :func:`optimize_single_qubit_gates` has been deprecated in favor of using the new transpiler
plugins or :func:`transpile_to_IQM`. Additionally, this is now incorporated into the Qiskit
transpiler as documented above.
* In :meth:`IQMBackend.create_run_request`, and as a result in :meth:`IQMBackend.run`, the
``max_circuit_duration_over_t2`` and ``heralding_mode`` options have been deprecated in favor of
using the :class:`CircuitCompilationOptions` class from :mod:`iqm.iqm_client`.
* The :class:`IQMBackend` no longer uses Qiskit's ``options`` attribute to give run options in
favor of using the arguments of the :meth:`IQMBackend.run` method directly.


Version 15.6
============

* Qiskit Target now contains CZ with the directions are calibrated on the hardwared. `#140 <https://github.com/iqm-finland/qiskit-on-iqm/pull/140>`_

Version 15.5
============

Expand Down
226 changes: 144 additions & 82 deletions docs/user_guide.rst

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ classifiers = [
requires-python = ">=3.9, <3.12"
dependencies = [
"numpy",
"qiskit >= 0.45, < 1.2",
"qiskit-aer >= 0.13.1, < 0.15",
"qiskit >= 0.46, < 1.3",
"qiskit-aer >= 0.13.1, < 0.16",
"iqm-client >= 20.0, < 21.0"
]

Expand Down Expand Up @@ -158,3 +158,21 @@ ignore-imports = true

[tool.pylint.string]
check-quote-consistency = true

# Expose the different custom transpiler passes to the Qiskit transpiler using their plugin system.
[project.entry-points."qiskit.transpiler.scheduling"]
move_routing = "iqm.qiskit_iqm:MoveGateRoutingPlugin"
move_routing_keep = "iqm.qiskit_iqm:MoveGateRoutingKeepExistingMovesPlugin"
move_routing_remove = "iqm.qiskit_iqm:MoveGateRoutingRemoveExistingMovesPlugin"
move_routing_trust = "iqm.qiskit_iqm:MoveGateRoutingTrustExistingMovesPlugin"
only_move_routing = "iqm.qiskit_iqm:MoveGateRoutingOnlyPlugin"
only_move_routing_keep = "iqm.qiskit_iqm:MoveGateRoutingOnlyKeepExistingMovesPlugin"
only_move_routing_remove = "iqm.qiskit_iqm:MoveGateRoutingOnlyRemoveExistingMovesPlugin"
only_move_routing_trust = "iqm.qiskit_iqm:MoveGateRoutingOnlyTrustExistingMovesPlugin"
move_routing_exact_global_phase = "iqm.qiskit_iqm:MoveGateRoutingWithExactRzPlugin"
move_routing_Rz_optimization_ignores_barriers = "iqm.qiskit_iqm:MoveGateRoutingWithRzOptimizationIgnoreBarriersPlugin"
only_Rz_optimization = "iqm.qiskit_iqm:OnlyRzOptimizationPlugin"
only_Rz_optimization_exact_global_phase = "iqm.qiskit_iqm:OnlyRzOptimizationExactPlugin"
only_Rz_optimization_ignore_barriers = "iqm.qiskit_iqm:OnlyRzOptimizationIgnoreBarriersPlugin"
iqm_default_scheduling = "iqm.qiskit_iqm:IQMDefaultSchedulingPlugin"

3 changes: 2 additions & 1 deletion src/iqm/qiskit_iqm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2022 Qiskit on IQM developers
# Copyright 2022-2024 Qiskit on IQM developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -26,6 +26,7 @@
from iqm.qiskit_iqm.iqm_provider import IQMBackend, IQMProvider, __version__
from iqm.qiskit_iqm.iqm_transpilation import IQMOptimizeSingleQubitGates, optimize_single_qubit_gates
from iqm.qiskit_iqm.move_gate import MoveGate
from iqm.qiskit_iqm.transpiler_plugins import *

if qiskit_version < "1.0.0":
warn(
Expand Down
12 changes: 6 additions & 6 deletions src/iqm/qiskit_iqm/fake_backends/fake_deneb.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ def IQMFakeDeneb() -> IQMFakeBackend:
two_qubit_gate_durations={"cz": 120.0, "move": 96.0},
readout_errors={
"COMP_R": {"0": 0.0, "1": 0.0},
"QB1": {"0": 0.977, "1": 0.977},
"QB2": {"0": 0.977, "1": 0.977},
"QB3": {"0": 0.977, "1": 0.977},
"QB4": {"0": 0.977, "1": 0.977},
"QB5": {"0": 0.977, "1": 0.977},
"QB6": {"0": 0.977, "1": 0.977},
"QB1": {"0": 0.02, "1": 0.02},
"QB2": {"0": 0.02, "1": 0.02},
"QB3": {"0": 0.02, "1": 0.02},
"QB4": {"0": 0.02, "1": 0.02},
"QB5": {"0": 0.02, "1": 0.02},
"QB6": {"0": 0.02, "1": 0.02},
},
name="sample-chip",
)
Expand Down
75 changes: 16 additions & 59 deletions src/iqm/qiskit_iqm/fake_backends/iqm_fake_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,19 @@

from qiskit import QuantumCircuit
from qiskit.providers import JobV1, Options
from qiskit.transpiler import TransformationPass
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel
from qiskit_aer.noise.errors import depolarizing_error, thermal_relaxation_error

from iqm.iqm_client import DynamicQuantumArchitecture, QuantumArchitectureSpecification
from iqm.qiskit_iqm.iqm_backend import IQM_TO_QISKIT_GATE_NAME, IQMBackendBase
from iqm.qiskit_iqm.iqm_circuit import IQMCircuit
from iqm.qiskit_iqm.iqm_circuit_validation import validate_circuit
from iqm.qiskit_iqm.iqm_transpilation import IQMReplaceGateWithUnitaryPass
from iqm.qiskit_iqm.move_gate import MOVE_GATE_UNITARY

GATE_TO_UNITARY = {
"move": MOVE_GATE_UNITARY,
}


# pylint: disable=too-many-instance-attributes
Expand Down Expand Up @@ -281,18 +286,15 @@ def _default_options(cls) -> Options:
def max_circuits(self) -> Optional[int]:
return None

def run(
self, run_input: Union[QuantumCircuit, list[QuantumCircuit], IQMCircuit, list[IQMCircuit]], **options
) -> JobV1:
def run(self, run_input: Union[QuantumCircuit, list[QuantumCircuit]], **options) -> JobV1:
"""
Run `run_input` on the fake backend using a simulator.
Run ``run_input`` on the fake backend using a simulator.

This method runs circuit jobs (an individual or a list of QuantumCircuit or IQMCircuit )
and returns a :class:`~qiskit.providers.JobV1` object.

It will run the simulation with a noise model of the fake backend (e.g. Adonis, Deneb).
Validity of move gates is also checked. The method also transpiles circuit
to the native gates so that moves are implemented as unitaries.
Validity of MOVE gates is also checked.

Args:
run_input: One or more quantum circuits to simulate on the backend.
Expand All @@ -302,65 +304,20 @@ def run(
Raises:
ValueError: If empty list of circuits is provided.
"""
circuits_aux = [run_input] if isinstance(run_input, (QuantumCircuit, IQMCircuit)) else run_input
circuits_aux = [run_input] if isinstance(run_input, QuantumCircuit) else run_input

if len(circuits_aux) == 0:
raise ValueError("Empty list of circuits submitted for execution.")

this = self

class check_move_validity(TransformationPass):
"""Checks that the placement of move gates is valid in the circuit."""

def run(self, dag):
qubits_involved_in_last_move = None # Store which qubit was last used for MOVE IN
for node in dag.op_nodes():
if node.op.name not in this.noise_model.basis_gates + ["id", "barrier", "measure"]:
raise ValueError("Operation '" + node.op.name + "' is not supported by the backend.")
if qubits_involved_in_last_move is not None:
# Verify that no single qubit gate is performed on the qubit between MOVE IN and MOVE OUT
if (
node.op.name not in ["move", "barrier", "measure"]
and len(node.qargs) == 1
and node.qargs[0] == qubits_involved_in_last_move[0]
):
raise ValueError(
f"Operations to qubits {node.qargs[0]} while their states are moved to a resonator."
)
if node.op.name == "move":
if qubits_involved_in_last_move is None:
# MOVE IN was performed
qubits_involved_in_last_move = node.qargs
elif qubits_involved_in_last_move != node.qargs:
raise ValueError(
f"Cannot apply MOVE on {node.qargs[0]} because COMP_R already holds the state of "
+ f"{qubits_involved_in_last_move[0]}."
)
else:
# MOVE OUT was performed
qubits_involved_in_last_move = None

if qubits_involved_in_last_move is not None:
raise ValueError(
"The following resonators are still holding qubit states at the end of the circuit: "
+ f"{qubits_involved_in_last_move[0]}."
)

return dag

circuits = []

for circ in circuits_aux:
circ_to_add = circ

if "move" in self.noise_model.basis_gates:
check_move_validity()(circ)
validate_circuit(circ, self)

for iqm_gate in [
g for g in self.noise_model.basis_gates if g not in list(IQM_TO_QISKIT_GATE_NAME.values())
]:
circ_to_add = circ.decompose(gates_to_decompose=iqm_gate)
circuits.append(circ_to_add)
for g in self.noise_model.basis_gates:
if g not in IQM_TO_QISKIT_GATE_NAME.values():
circ = IQMReplaceGateWithUnitaryPass(g, GATE_TO_UNITARY[g])(circ)
circuits.append(circ)

shots = options.get("shots", self.options.shots)

Expand Down
Loading
Loading