Skip to content

Commit 7b896a6

Browse files
authored
Merge pull request #34 from scaleway/iqm-integration-2
Iqm integration 2
2 parents 948446d + 08bef3d commit 7b896a6

File tree

4 files changed

+81
-4
lines changed

4 files changed

+81
-4
lines changed

qiskit_scaleway/backends/base_job.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,11 @@ def submit(self, session_id: str) -> None:
7272
raise RuntimeError(f"Job already submitted (ID: {self._job_id})")
7373

7474
options = self._config.copy()
75+
shots = options.pop("shots")
7576

7677
run_data = QaaSJobRunData(
7778
options={
78-
"shots": options.pop("shots"),
79+
"shots": shots,
7980
"memory": options.pop("memory", False),
8081
},
8182
circuits=list(
@@ -118,6 +119,7 @@ def submit(self, session_id: str) -> None:
118119
name=self._name,
119120
session_id=session_id,
120121
model_id=model.id,
122+
parameters={"shots": shots},
121123
).id
122124

123125
def result(

qiskit_scaleway/backends/iqm/backend.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from qiskit.providers import Options
1515

1616
from qiskit_scaleway.backends import BaseBackend
17+
from qiskit_scaleway.backends.iqm.move_gate import MoveGate
1718
from qiskit_scaleway.utils import create_target_from_platform
1819

1920
from scaleway_qaas_client.v1alpha1 import QaaSClient, QaaSPlatform
@@ -30,7 +31,9 @@ def __init__(self, provider, client: QaaSClient, platform: QaaSPlatform):
3031
self._options = self._default_options()
3132

3233
self._platform = platform
33-
self._target = create_target_from_platform(self._platform)
34+
self._target = create_target_from_platform(
35+
self._platform, additional_gates={"move": MoveGate()}
36+
)
3437

3538
self._options.max_shots = platform.max_shot_count
3639
self._options.set_validator("shots", (1, platform.max_shot_count))
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright 2024 Qiskit on IQM developers
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""MOVE gate to be used on the IQM Star architecture."""
15+
16+
import numpy as np
17+
import qiskit.quantum_info as qi
18+
19+
from qiskit.circuit import Gate
20+
21+
# MOVE gate has undefined phases, so we pick two arbitrary phases here
22+
_phase_1 = np.exp(0.7j)
23+
_phase_2 = 1.0 # np.exp(1.2j)
24+
MOVE_GATE_UNITARY = [
25+
[1.0, 0.0, 0.0, 0.0],
26+
[0.0, 0.0, _phase_1, 0.0],
27+
[0.0, _phase_1.conj(), 0.0, 0.0],
28+
[0.0, 0.0, 0.0, _phase_2],
29+
]
30+
"""Unitary matrix for simulating the ideal MOVE gate.
31+
32+
This matrix is not a realistic description of MOVE, since it applies a zero phase on the moved
33+
state, and acts as identity in the :math:`|11\rangle` subspace, thus being equal to the SWAP gate."""
34+
35+
36+
class MoveGate(Gate):
37+
r"""The MOVE operation is a unitary population exchange operation between a qubit and a resonator.
38+
Its effect is only defined in the invariant subspace :math:`S = \text{span}\{|00\rangle, |01\rangle, |10\rangle\}`,
39+
where it swaps the populations of the states :math:`|01\rangle` and :math:`|10\rangle`.
40+
Its effect on the orthogonal subspace is undefined.
41+
42+
MOVE has the following presentation in the subspace :math:`S`:
43+
44+
.. math:: \text{MOVE}_S = |00\rangle \langle 00| + a |10\rangle \langle 01| + a^{-1} |01\rangle \langle 10|,
45+
46+
where :math:`a` is an undefined complex phase that is canceled when the MOVE gate is applied a second time.
47+
48+
To ensure that the state of the qubit and resonator has no overlap with :math:`|11\rangle`, it is
49+
recommended that no single qubit gates are applied to the qubit in between a
50+
pair of MOVE operations.
51+
52+
.. note::
53+
The MOVE gate must always be be applied on the qubit and the resonator in the
54+
order ``[qubit, resonator]``, regardless of which component is currently holding the state.
55+
"""
56+
57+
def __init__(self, label=None): # noqa: ANN001
58+
"""Initializes the move gate"""
59+
super().__init__("move", 2, [], label=label)
60+
self.unitary = qi.Operator(MOVE_GATE_UNITARY)
61+
62+
def _define(self): # noqa: ANN202
63+
"""This function is purposefully not defined so that that the Qiskit transpiler cannot accidentally
64+
decompose the MOVE gate into a sequence of other gates, instead it will throw an error.
65+
"""
66+
return

qiskit_scaleway/utils/target.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from dataclasses import dataclass, field
22
from dataclasses_json import dataclass_json
3-
from typing import List, Optional
3+
from typing import List, Optional, Dict
44

55
from qiskit.transpiler import Target
66
from qiskit.circuit.library import get_standard_gate_name_mapping
7+
from qiskit.circuit import Gate
78

89
from scaleway_qaas_client.v1alpha1 import QaaSPlatform
910

@@ -33,7 +34,9 @@ class _PlatformMetadata:
3334
qiskit: _QiskitClientData
3435

3536

36-
def create_target_from_platform(platform: QaaSPlatform) -> Target:
37+
def create_target_from_platform(
38+
platform: QaaSPlatform, additional_gates: Optional[Dict[str, Gate]] = None
39+
) -> Target:
3740
target = Target(num_qubits=platform.max_qubit_count)
3841

3942
if not platform.metadata:
@@ -54,6 +57,9 @@ def create_target_from_platform(platform: QaaSPlatform) -> Target:
5457
for instruction in instructions:
5558
qiskit_instruction = qiskit_gate_mapping.get(instruction.name)
5659

60+
if not qiskit_instruction and additional_gates:
61+
qiskit_instruction = additional_gates.get(instruction.name)
62+
5763
if not qiskit_instruction:
5864
raise Exception("could not find instruction:", instruction.name)
5965

0 commit comments

Comments
 (0)