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.
Files changed (45) hide show
  1. iqm/cirq_iqm/devices/iqm_device_metadata.py +2 -1
  2. iqm/cirq_iqm/examples/demo_common.py +1 -1
  3. iqm/cirq_iqm/examples/demo_iqm_execution.py +3 -3
  4. iqm/cirq_iqm/iqm_sampler.py +47 -29
  5. iqm/cirq_iqm/serialize.py +1 -1
  6. iqm/cirq_iqm/transpiler.py +3 -1
  7. iqm/iqm_client/__init__.py +0 -2
  8. iqm/iqm_client/errors.py +6 -17
  9. iqm/iqm_client/iqm_client.py +199 -602
  10. iqm/iqm_client/models.py +20 -611
  11. iqm/iqm_client/transpile.py +11 -8
  12. iqm/iqm_client/validation.py +18 -9
  13. iqm/iqm_server_client/__init__.py +14 -0
  14. iqm/iqm_server_client/errors.py +6 -0
  15. iqm/iqm_server_client/iqm_server_client.py +755 -0
  16. iqm/iqm_server_client/models.py +179 -0
  17. iqm/iqm_server_client/py.typed +0 -0
  18. iqm/qiskit_iqm/__init__.py +8 -0
  19. iqm/qiskit_iqm/examples/bell_measure.py +2 -2
  20. iqm/qiskit_iqm/examples/transpile_example.py +9 -4
  21. iqm/qiskit_iqm/fake_backends/fake_adonis.py +2 -1
  22. iqm/qiskit_iqm/fake_backends/fake_aphrodite.py +2 -1
  23. iqm/qiskit_iqm/fake_backends/fake_apollo.py +2 -1
  24. iqm/qiskit_iqm/fake_backends/fake_deneb.py +2 -1
  25. iqm/qiskit_iqm/fake_backends/iqm_fake_backend.py +8 -7
  26. iqm/qiskit_iqm/iqm_backend.py +3 -4
  27. iqm/qiskit_iqm/iqm_circuit_validation.py +8 -7
  28. iqm/qiskit_iqm/iqm_job.py +106 -88
  29. iqm/qiskit_iqm/iqm_move_layout.py +2 -1
  30. iqm/qiskit_iqm/iqm_naive_move_pass.py +115 -56
  31. iqm/qiskit_iqm/iqm_provider.py +49 -36
  32. iqm/qiskit_iqm/iqm_target.py +12 -8
  33. iqm/qiskit_iqm/iqm_transpilation.py +219 -26
  34. iqm/qiskit_iqm/qiskit_to_iqm.py +150 -41
  35. iqm/qiskit_iqm/transpiler_plugins.py +11 -8
  36. {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/METADATA +4 -14
  37. iqm_client-33.0.0.dist-info/RECORD +63 -0
  38. iqm/iqm_client/api.py +0 -90
  39. iqm/iqm_client/authentication.py +0 -206
  40. iqm_client-32.0.0.dist-info/RECORD +0 -60
  41. {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/AUTHORS.rst +0 -0
  42. {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/LICENSE.txt +0 -0
  43. {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/WHEEL +0 -0
  44. {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/entry_points.txt +0 -0
  45. {iqm_client-32.0.0.dist-info → iqm_client-33.0.0.dist-info}/top_level.txt +0 -0
@@ -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.circuit import ClassicalRegister, Clbit, QuantumRegister
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 server."""
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 server, and can encode the necessary information in
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, qubit_index_to_name: dict[int, str], allowed_nonnative_gates: Collection[str] = ()
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: dict[Clbit, CircuitOperation] = {}
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
- qubit_names = tuple(qubit_index_to_name[circuit.find_bit(qubit).index] for qubit in circuit_instruction.qubits)
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
- # classically controlled gates (using the c_if method)
188
- # TODO we do not check anywhere if cc_prx is available for this locus!
189
- condition = instruction.condition
190
- if condition is not None:
191
- if native_inst.name != "prx":
192
- raise ValueError(
193
- f"This backend only supports conditionals on r, x, y, rx and ry gates, not on {instruction.name}"
194
- )
195
- native_inst.name = "cc_prx"
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
- clbit = creg[0]
205
- else:
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.r(angle, phase, locus[0]).c_if(fk_to_clbit[feedback_key], 1)
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 pass_manager_config.target is None:
67
- raise ValueError("PassManagerConfig must have a target backend set, unable to schedule MoveGate routing.")
68
- if self.move_gate_routing and isinstance(pass_manager_config.target, IQMTarget):
69
- scheduling.append(
70
- IQMNaiveResonatorMoving(
71
- target=pass_manager_config.target,
72
- existing_moves_handling=self.existing_move_handling,
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: 32.0.0
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: iqm-station-control-client <12,>=11 ; extra == 'qiskit'
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)