iqm-client 32.0.0__py3-none-any.whl → 33.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iqm/cirq_iqm/devices/iqm_device_metadata.py +2 -1
- iqm/cirq_iqm/examples/demo_common.py +1 -1
- iqm/cirq_iqm/examples/demo_iqm_execution.py +3 -3
- iqm/cirq_iqm/iqm_sampler.py +47 -29
- iqm/cirq_iqm/serialize.py +1 -1
- iqm/cirq_iqm/transpiler.py +3 -1
- iqm/iqm_client/__init__.py +0 -2
- iqm/iqm_client/errors.py +6 -17
- iqm/iqm_client/iqm_client.py +199 -602
- iqm/iqm_client/models.py +20 -611
- iqm/iqm_client/transpile.py +11 -8
- iqm/iqm_client/validation.py +18 -9
- iqm/iqm_server_client/__init__.py +14 -0
- iqm/iqm_server_client/errors.py +6 -0
- iqm/iqm_server_client/iqm_server_client.py +755 -0
- iqm/iqm_server_client/models.py +179 -0
- iqm/iqm_server_client/py.typed +0 -0
- iqm/qiskit_iqm/__init__.py +8 -0
- iqm/qiskit_iqm/examples/bell_measure.py +2 -2
- iqm/qiskit_iqm/examples/transpile_example.py +9 -4
- iqm/qiskit_iqm/fake_backends/fake_adonis.py +2 -1
- iqm/qiskit_iqm/fake_backends/fake_aphrodite.py +2 -1
- iqm/qiskit_iqm/fake_backends/fake_apollo.py +2 -1
- iqm/qiskit_iqm/fake_backends/fake_deneb.py +2 -1
- iqm/qiskit_iqm/fake_backends/iqm_fake_backend.py +8 -7
- iqm/qiskit_iqm/iqm_backend.py +3 -4
- iqm/qiskit_iqm/iqm_circuit_validation.py +8 -7
- iqm/qiskit_iqm/iqm_job.py +106 -88
- iqm/qiskit_iqm/iqm_move_layout.py +2 -1
- iqm/qiskit_iqm/iqm_naive_move_pass.py +115 -56
- iqm/qiskit_iqm/iqm_provider.py +49 -36
- iqm/qiskit_iqm/iqm_target.py +12 -8
- iqm/qiskit_iqm/iqm_transpilation.py +219 -26
- iqm/qiskit_iqm/qiskit_to_iqm.py +150 -41
- iqm/qiskit_iqm/transpiler_plugins.py +11 -8
- {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/METADATA +4 -14
- iqm_client-33.0.0.dist-info/RECORD +63 -0
- iqm/iqm_client/api.py +0 -90
- iqm/iqm_client/authentication.py +0 -206
- iqm_client-32.0.0.dist-info/RECORD +0 -60
- {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/AUTHORS.rst +0 -0
- {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/LICENSE.txt +0 -0
- {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/WHEEL +0 -0
- {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/entry_points.txt +0 -0
- {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/top_level.txt +0 -0
iqm/qiskit_iqm/qiskit_to_iqm.py
CHANGED
|
@@ -15,21 +15,24 @@
|
|
|
15
15
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
-
from collections.abc import Collection
|
|
18
|
+
from collections.abc import Collection, Iterable
|
|
19
19
|
from dataclasses import dataclass
|
|
20
20
|
from math import pi
|
|
21
21
|
import re
|
|
22
|
+
import warnings
|
|
22
23
|
|
|
23
24
|
from iqm.qiskit_iqm.move_gate import MoveGate
|
|
25
|
+
from packaging.version import Version
|
|
24
26
|
from qiskit import QuantumCircuit as QiskitQuantumCircuit
|
|
25
|
-
from qiskit
|
|
27
|
+
from qiskit import __version__ as qiskit_version
|
|
28
|
+
from qiskit.circuit import ClassicalRegister, Clbit, Operation, QuantumRegister, Qubit
|
|
26
29
|
from qiskit.transpiler.layout import Layout
|
|
27
30
|
|
|
28
31
|
from iqm.pulse import CircuitOperation
|
|
29
32
|
|
|
30
33
|
|
|
31
34
|
class InstructionNotSupportedError(RuntimeError):
|
|
32
|
-
"""Raised when a given instruction is not supported by the IQM
|
|
35
|
+
"""Raised when a given instruction is not supported by the IQM Server."""
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
@dataclass(frozen=True)
|
|
@@ -52,7 +55,7 @@ class MeasurementKey:
|
|
|
52
55
|
``IQMJob``, since otherwise users will not be able to retrieve results from a detached Python
|
|
53
56
|
environment solely based on the job id. Another option is to use measurement key strings to
|
|
54
57
|
store the required info. Qiskit does not use measurement keys, so we are free to use them
|
|
55
|
-
internally in the communication with the IQM
|
|
58
|
+
internally in the communication with the IQM Server, and can encode the necessary information in
|
|
56
59
|
them.
|
|
57
60
|
|
|
58
61
|
This class encapsulates the necessary info, and provides methods to transform between this
|
|
@@ -93,8 +96,107 @@ class MeasurementKey:
|
|
|
93
96
|
return cls(creg.name, len(creg), creg_idx, clbit_idx)
|
|
94
97
|
|
|
95
98
|
|
|
99
|
+
def _apply_condition(
|
|
100
|
+
operation: Operation,
|
|
101
|
+
native_instructions: Iterable[CircuitOperation],
|
|
102
|
+
clbit_to_measure: dict[Clbit, CircuitOperation],
|
|
103
|
+
) -> None:
|
|
104
|
+
"""Apply a classical condition to circuit instructions.
|
|
105
|
+
|
|
106
|
+
Modifies the instructions in place.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
operation: Operation containing the classical condition.
|
|
110
|
+
native_instructions: Instructions to apply the condition to.
|
|
111
|
+
clbit_to_measure: Maps bits in the classical register to the measurement operation that
|
|
112
|
+
last wrote something into them.
|
|
113
|
+
|
|
114
|
+
"""
|
|
115
|
+
# check that the condition is supported
|
|
116
|
+
creg, value = operation.condition
|
|
117
|
+
if isinstance(creg, ClassicalRegister):
|
|
118
|
+
if len(creg) != 1:
|
|
119
|
+
raise ValueError(f"{operation.name} is conditioned on multiple bits, this is not supported.")
|
|
120
|
+
clbit = creg[0]
|
|
121
|
+
else:
|
|
122
|
+
clbit = creg # it is a Clbit
|
|
123
|
+
if value != 1:
|
|
124
|
+
raise ValueError(f"{operation.name} is conditioned on integer value {value}, only value 1 is supported.")
|
|
125
|
+
|
|
126
|
+
# Set up feedback routing.
|
|
127
|
+
# The latest "measure" instruction to write to that classical bit is modified, it is
|
|
128
|
+
# given an explicit feedback_key equal to its measurement key.
|
|
129
|
+
# The same feedback_key is given to the controlled instruction, along with the feedback qubit.
|
|
130
|
+
if (measure_inst := clbit_to_measure.get(clbit)) is None:
|
|
131
|
+
raise ValueError(f"{operation.name} conditioned on {clbit}, which does not contain a measurement result yet.")
|
|
132
|
+
feedback_key = measure_inst.args["key"]
|
|
133
|
+
measure_inst.args["feedback_key"] = feedback_key # this measure is used to provide feedback
|
|
134
|
+
physical_qubit_name = measure_inst.locus[0] # single-qubit measurement
|
|
135
|
+
|
|
136
|
+
for inst in native_instructions:
|
|
137
|
+
# TODO we do not check anywhere if cc_prx is available for this locus!
|
|
138
|
+
if inst.name != "prx":
|
|
139
|
+
raise ValueError(f"This backend only supports conditionals on r, x, y, rx and ry gates, not on {inst.name}")
|
|
140
|
+
inst.name = "cc_prx"
|
|
141
|
+
inst.args["feedback_key"] = feedback_key
|
|
142
|
+
inst.args["feedback_qubit"] = physical_qubit_name
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _calculate_ifblock_idx2name_mapping(
|
|
146
|
+
circuit: QiskitQuantumCircuit,
|
|
147
|
+
if_block_qubits: list[Qubit],
|
|
148
|
+
overwrite_layout: Layout | None,
|
|
149
|
+
qubit_index_to_name: dict[int, str],
|
|
150
|
+
) -> dict[int, str]:
|
|
151
|
+
"""Calculate mapping from if-block qubit registers to physical qubit names.
|
|
152
|
+
|
|
153
|
+
The if-block circuit has no qregs of its own, just references to the parent circuit qubits.
|
|
154
|
+
Depending on how the circuit was transpiled, the if-block Qubit Objects might
|
|
155
|
+
not be present in the parent Circuit. This method finds the appropriate physical qubits
|
|
156
|
+
to make a new qubit index to name mapping for it.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
circuit: The parent quantum circuit containing the if-block.
|
|
160
|
+
if_block_qubits: The qubits used in the if-block.
|
|
161
|
+
overwrite_layout: An alternative layout indicating the physical qubit mapping to use for the serialized
|
|
162
|
+
instructions, this overwrites the circuit's layout.
|
|
163
|
+
qubit_index_to_name: Mapping from qubit indices to the corresponding qubit names as obtained from a backend.
|
|
164
|
+
|
|
165
|
+
"""
|
|
166
|
+
# Check if we can use the overwrite layout
|
|
167
|
+
use_overwrite_layout = overwrite_layout is not None and all(
|
|
168
|
+
qb in overwrite_layout.get_physical_bits().values() for qb in if_block_qubits
|
|
169
|
+
)
|
|
170
|
+
if use_overwrite_layout:
|
|
171
|
+
physical_qubits = {q: i for i, q in overwrite_layout.get_physical_bits().items()} # type: ignore[union-attr]
|
|
172
|
+
return {k: qubit_index_to_name[physical_qubits[q]] for k, q in enumerate(if_block_qubits)}
|
|
173
|
+
# The if-block qubits are not in the circuit, so we hope they are in the layout
|
|
174
|
+
use_circuit_layout_guess = circuit.layout is not None and all(
|
|
175
|
+
qb in circuit.layout.initial_layout.get_physical_bits().values() for qb in if_block_qubits
|
|
176
|
+
)
|
|
177
|
+
if use_circuit_layout_guess:
|
|
178
|
+
physical_qubits = {q: i for i, q in circuit.layout.initial_layout.get_physical_bits().items()}
|
|
179
|
+
return {k: qubit_index_to_name[physical_qubits[q]] for k, q in enumerate(if_block_qubits)}
|
|
180
|
+
|
|
181
|
+
# Hope that we can find the qubits in the circuit - can be wrong.
|
|
182
|
+
use_circuit_find_bit = all(qb in circuit.qubits for qb in if_block_qubits)
|
|
183
|
+
if use_circuit_find_bit:
|
|
184
|
+
return {k: qubit_index_to_name[circuit.find_bit(q).index] for k, q in enumerate(if_block_qubits)}
|
|
185
|
+
# Catch-all: we cannot determine the mapping, this should never happen.
|
|
186
|
+
raise ValueError(
|
|
187
|
+
"Could not determine the physical locations for if-block qubits. "
|
|
188
|
+
"The if-block uses {if_block_qubits} qubits, but the parent circuit has qubits {circuit.qubits}, "
|
|
189
|
+
"the circuit layout is {circuit.layout.initial_layout}, and the overwrite layout is {overwrite_layout}."
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
96
193
|
def serialize_instructions( # noqa: PLR0912, PLR0915
|
|
97
|
-
circuit: QiskitQuantumCircuit,
|
|
194
|
+
circuit: QiskitQuantumCircuit,
|
|
195
|
+
qubit_index_to_name: dict[int, str],
|
|
196
|
+
allowed_nonnative_gates: Collection[str] = (),
|
|
197
|
+
*,
|
|
198
|
+
clbit_to_measure: dict[Clbit, CircuitOperation] | None = None,
|
|
199
|
+
overwrite_layout: Layout | None = None,
|
|
98
200
|
) -> list[CircuitOperation]:
|
|
99
201
|
"""Serialize a quantum circuit into the IQM data transfer format.
|
|
100
202
|
|
|
@@ -109,9 +211,13 @@ def serialize_instructions( # noqa: PLR0912, PLR0915
|
|
|
109
211
|
If such gates are present in the circuit, the caller must edit the result to be valid and executable.
|
|
110
212
|
Notably, since IQM transfer format requires named parameters and qiskit parameters don't have names, the
|
|
111
213
|
`i` th parameter of an unrecognized instruction is given the name ``"p<i>"``.
|
|
214
|
+
clbit_to_measure: Maps clbits to the latest "measure" instruction to store its result there, or
|
|
215
|
+
None if nothing has been measured yet.
|
|
216
|
+
overwrite_layout: A layout indicating the physical qubit mapping to use for the serialized instructions, this
|
|
217
|
+
overwrites the circuit's layout.
|
|
112
218
|
|
|
113
219
|
Returns:
|
|
114
|
-
list of instructions representing the circuit
|
|
220
|
+
list of IQM instructions representing the circuit
|
|
115
221
|
|
|
116
222
|
Raises:
|
|
117
223
|
ValueError: circuit contains an unsupported instruction or is not transpiled in general
|
|
@@ -119,10 +225,18 @@ def serialize_instructions( # noqa: PLR0912, PLR0915
|
|
|
119
225
|
"""
|
|
120
226
|
instructions: list[CircuitOperation] = []
|
|
121
227
|
# maps clbits to the latest "measure" instruction to store its result there
|
|
122
|
-
clbit_to_measure
|
|
228
|
+
if clbit_to_measure is None:
|
|
229
|
+
clbit_to_measure = {}
|
|
230
|
+
invalid_layout = circuit.layout is None or circuit.layout.initial_layout.get_registers() != set(circuit.qregs)
|
|
123
231
|
for circuit_instruction in circuit.data:
|
|
124
232
|
instruction = circuit_instruction.operation
|
|
125
|
-
|
|
233
|
+
if invalid_layout:
|
|
234
|
+
qubit_names = tuple(
|
|
235
|
+
qubit_index_to_name[circuit.find_bit(qubit).index] for qubit in circuit_instruction.qubits
|
|
236
|
+
)
|
|
237
|
+
else:
|
|
238
|
+
physical_qubits = {q: i for i, q in circuit.layout.initial_layout.get_physical_bits().items()}
|
|
239
|
+
qubit_names = tuple(qubit_index_to_name[physical_qubits[qubit]] for qubit in circuit_instruction.qubits)
|
|
126
240
|
if instruction.name == "r":
|
|
127
241
|
angle = float(instruction.params[0])
|
|
128
242
|
phase = float(instruction.params[1])
|
|
@@ -178,44 +292,38 @@ def serialize_instructions( # noqa: PLR0912, PLR0915
|
|
|
178
292
|
elif instruction.name in allowed_nonnative_gates:
|
|
179
293
|
args = {f"p{i}": param for i, param in enumerate(instruction.params)}
|
|
180
294
|
native_inst = CircuitOperation(name=instruction.name, locus=qubit_names, args=args)
|
|
295
|
+
elif instruction.name == "if_else":
|
|
296
|
+
if_block, else_block = instruction.params
|
|
297
|
+
if else_block is not None and len(else_block) > 0: # Non-empty circuit in else-block
|
|
298
|
+
raise ValueError("The use of an else-block with if_test is not supported.")
|
|
299
|
+
# Recursively serialize the if-block.
|
|
300
|
+
q_index_to_name = _calculate_ifblock_idx2name_mapping(
|
|
301
|
+
circuit, if_block.qubits, overwrite_layout, qubit_index_to_name
|
|
302
|
+
)
|
|
303
|
+
if_instructions = serialize_instructions(
|
|
304
|
+
if_block, q_index_to_name, allowed_nonnative_gates, clbit_to_measure=clbit_to_measure
|
|
305
|
+
)
|
|
306
|
+
_apply_condition(instruction, if_instructions, clbit_to_measure)
|
|
307
|
+
instructions.extend(if_instructions)
|
|
308
|
+
continue # Skip the rest of the loop, as we already handled the instructions
|
|
181
309
|
else:
|
|
182
310
|
raise ValueError(
|
|
183
311
|
f"Instruction '{instruction.name}' in the circuit '{circuit.name}' is not natively supported. "
|
|
184
312
|
f"You need to transpile the circuit before execution."
|
|
185
313
|
)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
creg, value = condition
|
|
197
|
-
if isinstance(creg, ClassicalRegister):
|
|
198
|
-
if len(creg) != 1:
|
|
199
|
-
raise ValueError(f"{instruction} is conditioned on multiple bits, this is not supported.")
|
|
200
|
-
if value != 1:
|
|
201
|
-
raise ValueError(
|
|
202
|
-
f"{instruction} is conditioned on integer value {value}, only value 1 is supported."
|
|
314
|
+
# classically controlled gates (using the c_if method) need to be updated
|
|
315
|
+
if (
|
|
316
|
+
Version(qiskit_version) < Version("2.0.0") and instruction.condition is not None
|
|
317
|
+
): # None means no classical condition
|
|
318
|
+
if Version(qiskit_version) < Version("1.3.0"):
|
|
319
|
+
# Avoid double deprecation warnings.
|
|
320
|
+
warnings.warn(
|
|
321
|
+
DeprecationWarning(
|
|
322
|
+
"The use of Qiskit's `c_if` method is deprecated and will be removed in a future release"
|
|
323
|
+
"of IQM Client. Please use the `with circuit.if_test(...)` construction instead."
|
|
203
324
|
)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
clbit = creg # it is a Clbit
|
|
207
|
-
|
|
208
|
-
# Set up feedback routing.
|
|
209
|
-
# The latest "measure" instruction to write to that classical bit is modified, it is
|
|
210
|
-
# given an explicit feedback_key equal to its measurement key.
|
|
211
|
-
# The same feedback_key is given to the controlled instruction, along with the feedback qubit.
|
|
212
|
-
measure_inst = clbit_to_measure[clbit]
|
|
213
|
-
feedback_key = measure_inst.args["key"]
|
|
214
|
-
measure_inst.args["feedback_key"] = feedback_key # this measure is used to provide feedback
|
|
215
|
-
physical_qubit_name = measure_inst.locus[0] # single-qubit measurement
|
|
216
|
-
native_inst.args["feedback_key"] = feedback_key
|
|
217
|
-
native_inst.args["feedback_qubit"] = physical_qubit_name
|
|
218
|
-
|
|
325
|
+
)
|
|
326
|
+
_apply_condition(instruction, [native_inst], clbit_to_measure)
|
|
219
327
|
instructions.append(native_inst)
|
|
220
328
|
return instructions
|
|
221
329
|
|
|
@@ -299,7 +407,8 @@ def deserialize_instructions(
|
|
|
299
407
|
phase = instr.args["phase"]
|
|
300
408
|
feedback_key = instr.args["feedback_key"]
|
|
301
409
|
# NOTE: 'feedback_qubit' is not needed, because in Qiskit you only have single-qubit measurements.
|
|
302
|
-
circuit.
|
|
410
|
+
with circuit.if_test((fk_to_clbit[feedback_key], 1)):
|
|
411
|
+
circuit.r(angle, phase, locus[0])
|
|
303
412
|
elif instr.name == "reset":
|
|
304
413
|
for qubit in locus:
|
|
305
414
|
circuit.reset(qubit)
|
|
@@ -63,15 +63,18 @@ class IQMSchedulingPlugin(PassManagerStagePlugin):
|
|
|
63
63
|
scheduling.append(
|
|
64
64
|
IQMOptimizeSingleQubitGates(drop_final_rz=self.drop_final_rz, ignore_barriers=self.ignore_barriers)
|
|
65
65
|
)
|
|
66
|
-
if
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
if self.move_gate_routing:
|
|
67
|
+
if pass_manager_config.target is None:
|
|
68
|
+
raise ValueError(
|
|
69
|
+
"PassManagerConfig must have a target backend set, unable to schedule MoveGate routing."
|
|
70
|
+
)
|
|
71
|
+
if isinstance(pass_manager_config.target, IQMTarget):
|
|
72
|
+
scheduling.append(
|
|
73
|
+
IQMNaiveResonatorMoving(
|
|
74
|
+
target=pass_manager_config.target,
|
|
75
|
+
existing_moves_handling=self.existing_move_handling,
|
|
76
|
+
)
|
|
73
77
|
)
|
|
74
|
-
)
|
|
75
78
|
return scheduling
|
|
76
79
|
|
|
77
80
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: iqm-client
|
|
3
|
-
Version:
|
|
3
|
+
Version: 33.0.0
|
|
4
4
|
Summary: Client library for accessing an IQM quantum computer
|
|
5
5
|
Author-email: IQM Finland Oy <developers@meetiqm.com>
|
|
6
6
|
License: Apache License
|
|
@@ -216,35 +216,25 @@ Requires-Python: <3.13,>=3.10
|
|
|
216
216
|
Description-Content-Type: text/x-rst
|
|
217
217
|
License-File: LICENSE.txt
|
|
218
218
|
License-File: AUTHORS.rst
|
|
219
|
-
Requires-Dist: iqm-station-control-client <12,>=11
|
|
220
|
-
Requires-Dist: iqm-exa-common <28,>=27
|
|
221
|
-
Requires-Dist: iqm-pulse <13,>=12
|
|
222
219
|
Requires-Dist: numpy <3.0,>=1.26.4
|
|
223
220
|
Requires-Dist: packaging ==24.1
|
|
224
221
|
Requires-Dist: pydantic <3.0,>=2.9.2
|
|
225
222
|
Requires-Dist: requests ==2.32.3
|
|
223
|
+
Requires-Dist: iqm-pulse
|
|
224
|
+
Requires-Dist: iqm-station-control-client
|
|
226
225
|
Provides-Extra: cirq
|
|
227
|
-
Requires-Dist: iqm-station-control-client <12,>=11 ; extra == 'cirq'
|
|
228
|
-
Requires-Dist: iqm-exa-common <28,>=27 ; extra == 'cirq'
|
|
229
|
-
Requires-Dist: iqm-pulse <13,>=12 ; extra == 'cirq'
|
|
230
226
|
Requires-Dist: cirq-core[contrib] ~=1.2 ; extra == 'cirq'
|
|
231
227
|
Requires-Dist: ply ==3.11 ; extra == 'cirq'
|
|
232
228
|
Requires-Dist: llvmlite >=0.44.0 ; extra == 'cirq'
|
|
233
229
|
Requires-Dist: numba >=0.61.0 ; extra == 'cirq'
|
|
234
230
|
Provides-Extra: cli
|
|
235
|
-
Requires-Dist: iqm-station-control-client <12,>=11 ; extra == 'cli'
|
|
236
|
-
Requires-Dist: iqm-exa-common <28,>=27 ; extra == 'cli'
|
|
237
|
-
Requires-Dist: iqm-pulse <13,>=12 ; extra == 'cli'
|
|
238
231
|
Requires-Dist: click <9,>=8.1.6 ; extra == 'cli'
|
|
239
232
|
Requires-Dist: jsonschema >=4.6.0 ; extra == 'cli'
|
|
240
233
|
Requires-Dist: psutil >=5.9.2 ; extra == 'cli'
|
|
241
234
|
Requires-Dist: types-psutil ; extra == 'cli'
|
|
242
235
|
Requires-Dist: python-daemon >=2.3.0 ; extra == 'cli'
|
|
243
236
|
Provides-Extra: qiskit
|
|
244
|
-
Requires-Dist:
|
|
245
|
-
Requires-Dist: iqm-exa-common <28,>=27 ; extra == 'qiskit'
|
|
246
|
-
Requires-Dist: iqm-pulse <13,>=12 ; extra == 'qiskit'
|
|
247
|
-
Requires-Dist: qiskit <=1.4.2,>=1.0 ; extra == 'qiskit'
|
|
237
|
+
Requires-Dist: qiskit <2.2,>=1.0 ; extra == 'qiskit'
|
|
248
238
|
Requires-Dist: qiskit-aer <0.18,>=0.13.1 ; extra == 'qiskit'
|
|
249
239
|
|
|
250
240
|
IQM Client
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
iqm/cirq_iqm/__init__.py,sha256=1zTyxtF39OD11D00ZujgqciJ_9GBDYe-PVBLqZp4NaA,831
|
|
2
|
+
iqm/cirq_iqm/extended_qasm_parser.py,sha256=csDzfHLhy_9maGbappLbnFo2NHQjQeyd-1F8P380Mbk,1917
|
|
3
|
+
iqm/cirq_iqm/iqm_gates.py,sha256=xnZex5ZfNOk_WSsFjVCRybc14FlGNbmwOs3mIfOE_F8,2488
|
|
4
|
+
iqm/cirq_iqm/iqm_sampler.py,sha256=b5CpcD7tgUAWKYdAKcFrshfv1I1GN5eC7mfMyXoGF_8,12606
|
|
5
|
+
iqm/cirq_iqm/optimizers.py,sha256=Jcb6W7-M9wYa5mZztq33jQpWuIzD5ulE16ZperIc-wU,8566
|
|
6
|
+
iqm/cirq_iqm/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
iqm/cirq_iqm/serialize.py,sha256=2w_8sk-X18qWb2FFocBP_MXJALoNmosZIs5Ilp7ueR8,8516
|
|
8
|
+
iqm/cirq_iqm/transpiler.py,sha256=zjJzZb5HyjTfqhL0rMI3dt_3GPGLdVYah9UlGoC8hcc,2173
|
|
9
|
+
iqm/cirq_iqm/devices/__init__.py,sha256=WxbvNAqmeoV4mNy9M9IpjwmyNDpAP7ec1XFdjN7w_YA,840
|
|
10
|
+
iqm/cirq_iqm/devices/adonis.py,sha256=ZWaA4_OfO6fBcrLYHONTjtW8aSlVq2nwy9IiW529gQw,1390
|
|
11
|
+
iqm/cirq_iqm/devices/aphrodite.py,sha256=0K8zRo6gVVadQo7LJfs6laUVLzS3fNkrXMrPlwieyJ8,4018
|
|
12
|
+
iqm/cirq_iqm/devices/apollo.py,sha256=_k7L45zyHZnpdZWMMXO6zci3XY3UEnBj2RmvxM6D7Mg,2238
|
|
13
|
+
iqm/cirq_iqm/devices/iqm_device.py,sha256=CyAP0kU9vfovNWvF4CVX8Wp6_QLxLN8fy9I2YZkHHwM,15425
|
|
14
|
+
iqm/cirq_iqm/devices/iqm_device_metadata.py,sha256=3ONFzPa1G_nE4nSAldsd_Ly8i1__n2Sll43qN9yNQUw,7161
|
|
15
|
+
iqm/cirq_iqm/examples/demo_adonis.py,sha256=rPd8VYqccYijG6t92hfvKsk8RAaMGHOmm4JelYjt3rw,1728
|
|
16
|
+
iqm/cirq_iqm/examples/demo_apollo.py,sha256=vnDwcEXqEyew0cf4SDDQ2budP-giizSNJU3dgOw15H0,1751
|
|
17
|
+
iqm/cirq_iqm/examples/demo_common.py,sha256=k0MAeLDNxZJGv8FNrgMEwaQZsuXeDY5NBM2rLSIQxvU,8745
|
|
18
|
+
iqm/cirq_iqm/examples/demo_iqm_execution.py,sha256=_Wf6rsL_q93M5Ww6eurbXL8VPngGkxtpZBAbNpnn2ek,2440
|
|
19
|
+
iqm/cirq_iqm/examples/usage.ipynb,sha256=Kyfyu_MwqzTavHVNjgrWJo1tZPeJwTw7ExcU0MFYNRk,34208
|
|
20
|
+
iqm/iqm_client/__init__.py,sha256=43TjxuxX_iFl5h2GbQqyIkxmuraWkX4OyvF444Hlyvk,1306
|
|
21
|
+
iqm/iqm_client/errors.py,sha256=weKTljBvDzJxK58NHCXaZXoITVMBvsOkvYP0abs5Dfc,1226
|
|
22
|
+
iqm/iqm_client/iqm_client.py,sha256=OGKp6QDwtIY2RjJ8_uG44UJlMpm7VH_HTgqZFPPN2YA,22632
|
|
23
|
+
iqm/iqm_client/models.py,sha256=UHlkdG0bjaksvyARYB4RZYx1EJ4nLMyHiPS_7-Bwr14,15888
|
|
24
|
+
iqm/iqm_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
+
iqm/iqm_client/transpile.py,sha256=ZicsOJiT5zEaaYMWuFddnJT2e4e9Oyu7B5pO8Z_ah7M,37334
|
|
26
|
+
iqm/iqm_client/util.py,sha256=obzh1g6PNEXOj7k3gUkiylNUhyqutbWlxlEpfyyU_fk,1505
|
|
27
|
+
iqm/iqm_client/validation.py,sha256=SyshUOxmnlwb0haWEAVkgynGOYUMV7Os281sUe29tpE,12621
|
|
28
|
+
iqm/iqm_server_client/__init__.py,sha256=hqfe65DmdYu5qDbYsg3Uq94DRe2zkbMJP_XFYsMbGSQ,645
|
|
29
|
+
iqm/iqm_server_client/errors.py,sha256=I48dRY_Sies2vQzyjzQxhHm_J5RopyL5hqAmlnBy67w,192
|
|
30
|
+
iqm/iqm_server_client/iqm_server_client.py,sha256=en2C4hZ4VzHtg07EtxpuC-cFEw2kzTi1_GzfYKk-NWY,31365
|
|
31
|
+
iqm/iqm_server_client/models.py,sha256=YpyppxEu2obSIaUvuc3_mRKcGscs8YLrcWrTk7EHKzM,5597
|
|
32
|
+
iqm/iqm_server_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
+
iqm/qiskit_iqm/__init__.py,sha256=VPmcMV5nBOEIhVsOceIUkdZtWJ3tGlaKrDFP-FRuOCs,1667
|
|
34
|
+
iqm/qiskit_iqm/iqm_backend.py,sha256=3ydSroylh_Us-5RJfOQgOkL7eqF4fWe5ejXueDTcAj8,5584
|
|
35
|
+
iqm/qiskit_iqm/iqm_circuit.py,sha256=jaPo3zc5FC0vAIumh5d56fr44fDaJXXwcquBzQEy1Yg,1400
|
|
36
|
+
iqm/qiskit_iqm/iqm_circuit_validation.py,sha256=SzfCJclUh1kK6Kcz5puKlCtE0hZfWxYYKF35EagU204,1750
|
|
37
|
+
iqm/qiskit_iqm/iqm_job.py,sha256=SdyZeQi5CoGxBeJyfIvOM7DA0ONJ5tbTHpk4hajpUFk,12395
|
|
38
|
+
iqm/qiskit_iqm/iqm_move_layout.py,sha256=vFdba0DStu8Pebi3qxZBYOLCYC2Atl28YlSzbSGER4Y,10557
|
|
39
|
+
iqm/qiskit_iqm/iqm_naive_move_pass.py,sha256=GcS2DyYWwG-qMyczXqTXxMxNqRB4IVeWNP3CzguKpBw,15639
|
|
40
|
+
iqm/qiskit_iqm/iqm_provider.py,sha256=pK1CcAOQKG5jXYfjxshuVSmMLWQG1-k0cyghRmGpWN8,19273
|
|
41
|
+
iqm/qiskit_iqm/iqm_target.py,sha256=nqurRgM_p2nOw8ty8ncw38vSErEdXpHSlbp7Rpavnc4,16232
|
|
42
|
+
iqm/qiskit_iqm/iqm_transpilation.py,sha256=RccAHY7lNXvg7TWKG7fBNBCgFu5Xd9B_J9V9uKLlmuY,18336
|
|
43
|
+
iqm/qiskit_iqm/move_gate.py,sha256=UbrQSfrpVV3QKGJ93TelxEfZkl1wY4uWL8IH_QDpGUw,2840
|
|
44
|
+
iqm/qiskit_iqm/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
|
+
iqm/qiskit_iqm/qiskit_to_iqm.py,sha256=imMmuOi_tuujIrGzBFnGOtxpGHcIkncXutr5QFekJl4,20677
|
|
46
|
+
iqm/qiskit_iqm/transpiler_plugins.py,sha256=BrCkUFQUdi0m8K8V0ERYgtPAkvoX4VlYIJwnFKyCN9Q,8831
|
|
47
|
+
iqm/qiskit_iqm/examples/__init__.py,sha256=M4ElQHCo-WxtVXK39bF3QiFT3IGXPtZ1khqexHiTBEc,20
|
|
48
|
+
iqm/qiskit_iqm/examples/bell_measure.py,sha256=-20oihBKuK4s9rA_9fuyJBM3Du8NWZUTZ8YhI3Q4TpM,3064
|
|
49
|
+
iqm/qiskit_iqm/examples/transpile_example.py,sha256=vGcs2OpsYTVcWyX-qzmfjio4JcIBi_Dk-hrQRGO4oGs,2401
|
|
50
|
+
iqm/qiskit_iqm/fake_backends/__init__.py,sha256=fkw2UHT-3aJbAKvR1WYUN7_4N5Gdwpx9bm6vlWj1tm0,874
|
|
51
|
+
iqm/qiskit_iqm/fake_backends/fake_adonis.py,sha256=DWftCPu6ElE4P47Z-y3bojg0unDJ6F5ur2aDqfoY85s,2248
|
|
52
|
+
iqm/qiskit_iqm/fake_backends/fake_aphrodite.py,sha256=oB5wFtZ2VYy0TxoL-eBgYnVAwamGPYlzIQK89npwQUg,15533
|
|
53
|
+
iqm/qiskit_iqm/fake_backends/fake_apollo.py,sha256=C05u3knnCsA8DCuWU31EwUvJ6xilef36J06GoE2vAe4,6623
|
|
54
|
+
iqm/qiskit_iqm/fake_backends/fake_deneb.py,sha256=HstlV-PSbyCttY1uEyWr-YgsMNkv9Ntf6zffav837_4,3216
|
|
55
|
+
iqm/qiskit_iqm/fake_backends/fake_garnet.py,sha256=GI0xafTCj1Um09qVuccO6GPOGBm6ygul_O40Wu220Ys,5555
|
|
56
|
+
iqm/qiskit_iqm/fake_backends/iqm_fake_backend.py,sha256=IfVKxlPlAVCHTgli2scRP1gkVCXIiSuL6-QjjsZp83Q,16808
|
|
57
|
+
iqm_client-33.0.0.dist-info/AUTHORS.rst,sha256=qsxeK5A3-B_xK3hNbhFHEIkoHNpo7sdzYyRTs7Bdtm8,795
|
|
58
|
+
iqm_client-33.0.0.dist-info/LICENSE.txt,sha256=2DXrmQtVVUV9Fc9RBFJidMiTEaQlG2oAtlC9PMrEwTk,11333
|
|
59
|
+
iqm_client-33.0.0.dist-info/METADATA,sha256=7caTuL76eOR8Gh87dPMW9WpRecywAmFiss3E6T8Pe9Q,17290
|
|
60
|
+
iqm_client-33.0.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
|
|
61
|
+
iqm_client-33.0.0.dist-info/entry_points.txt,sha256=Kk2qfRwk8vbIJ7qCAvmaUogfRRn6t92_hBFhe6kqAE4,1317
|
|
62
|
+
iqm_client-33.0.0.dist-info/top_level.txt,sha256=NB4XRfyDS6_wG9gMsyX-9LTU7kWnTQxNvkbzIxGv3-c,4
|
|
63
|
+
iqm_client-33.0.0.dist-info/RECORD,,
|
iqm/iqm_client/api.py
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# Copyright 2024 IQM client 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
|
-
"""This module contains definitions of IQM Server API endpoints."""
|
|
15
|
-
|
|
16
|
-
from enum import Enum, auto
|
|
17
|
-
from posixpath import join
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class APIEndpoint(Enum):
|
|
21
|
-
"""Supported API endpoints."""
|
|
22
|
-
|
|
23
|
-
GET_JOB_RESULT = auto()
|
|
24
|
-
GET_JOB_REQUEST_PARAMETERS = auto()
|
|
25
|
-
GET_JOB_CALIBRATION_SET_ID = auto()
|
|
26
|
-
GET_JOB_CIRCUITS_BATCH = auto()
|
|
27
|
-
GET_JOB_ERROR_LOG = auto()
|
|
28
|
-
SUBMIT_JOB = auto()
|
|
29
|
-
GET_JOB_COUNTS = auto()
|
|
30
|
-
GET_JOB_STATUS = auto()
|
|
31
|
-
GET_JOB_TIMELINE = auto()
|
|
32
|
-
ABORT_JOB = auto()
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class APIConfig:
|
|
36
|
-
"""Provides supported API endpoints for a given API variant."""
|
|
37
|
-
|
|
38
|
-
def __init__(self, station_control_url: str):
|
|
39
|
-
"""Args:
|
|
40
|
-
station_control_url: URL of the IQM server,
|
|
41
|
-
e.g. https://test.qc.iqm.fi/station or https://cocos.resonance.meetiqm.com/garnet
|
|
42
|
-
|
|
43
|
-
"""
|
|
44
|
-
self.station_control_url = station_control_url
|
|
45
|
-
self.urls = self._get_api_urls()
|
|
46
|
-
|
|
47
|
-
@staticmethod
|
|
48
|
-
def _get_api_urls() -> dict[APIEndpoint, str]:
|
|
49
|
-
"""Returns:
|
|
50
|
-
Relative URLs for each supported API endpoints.
|
|
51
|
-
|
|
52
|
-
"""
|
|
53
|
-
return {
|
|
54
|
-
# TODO SW-1434: Use StationControlClient methods for communication instead of REST endpoints
|
|
55
|
-
APIEndpoint.GET_JOB_RESULT: "jobs/%s/measurements",
|
|
56
|
-
APIEndpoint.GET_JOB_REQUEST_PARAMETERS: "jobs/%s/request_parameters",
|
|
57
|
-
APIEndpoint.GET_JOB_CALIBRATION_SET_ID: "jobs/%s/calibration_set_id",
|
|
58
|
-
APIEndpoint.GET_JOB_CIRCUITS_BATCH: "jobs/%s/circuits_batch",
|
|
59
|
-
APIEndpoint.GET_JOB_ERROR_LOG: "jobs/%s/error_log",
|
|
60
|
-
APIEndpoint.SUBMIT_JOB: "circuits",
|
|
61
|
-
APIEndpoint.GET_JOB_COUNTS: "circuits/%s/counts",
|
|
62
|
-
APIEndpoint.GET_JOB_STATUS: "jobs/%s/status",
|
|
63
|
-
APIEndpoint.GET_JOB_TIMELINE: "jobs/%s/timeline",
|
|
64
|
-
APIEndpoint.ABORT_JOB: "jobs/%s/abort",
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
def is_supported(self, endpoint: APIEndpoint) -> bool:
|
|
68
|
-
"""Args:
|
|
69
|
-
endpoint: API endpoint.
|
|
70
|
-
|
|
71
|
-
Returns:
|
|
72
|
-
True if the endpoint is supported, False otherwise.
|
|
73
|
-
|
|
74
|
-
"""
|
|
75
|
-
return endpoint in self.urls
|
|
76
|
-
|
|
77
|
-
def url(self, endpoint: APIEndpoint, *args) -> str:
|
|
78
|
-
"""Args:
|
|
79
|
-
endpoint: API endpoint.
|
|
80
|
-
args: Arguments to be passed to the URL.
|
|
81
|
-
|
|
82
|
-
Returns:
|
|
83
|
-
URL for the given endpoint.
|
|
84
|
-
|
|
85
|
-
Raises:
|
|
86
|
-
ValueError: If the endpoint is not supported.
|
|
87
|
-
|
|
88
|
-
"""
|
|
89
|
-
url = self.urls.get(endpoint, "")
|
|
90
|
-
return join(self.station_control_url, url % args)
|