iqm-client 30.2.0__py3-none-any.whl → 31.1.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/serialize.py +50 -41
- iqm/iqm_client/iqm_client.py +1 -1
- iqm/iqm_client/models.py +152 -361
- iqm/iqm_client/transpile.py +37 -31
- iqm/iqm_client/validation.py +23 -19
- iqm/qiskit_iqm/iqm_job.py +2 -1
- iqm/qiskit_iqm/iqm_provider.py +2 -1
- iqm/qiskit_iqm/qiskit_to_iqm.py +32 -31
- {iqm_client-30.2.0.dist-info → iqm_client-31.1.0.dist-info}/METADATA +9 -5
- {iqm_client-30.2.0.dist-info → iqm_client-31.1.0.dist-info}/RECORD +15 -15
- {iqm_client-30.2.0.dist-info → iqm_client-31.1.0.dist-info}/AUTHORS.rst +0 -0
- {iqm_client-30.2.0.dist-info → iqm_client-31.1.0.dist-info}/LICENSE.txt +0 -0
- {iqm_client-30.2.0.dist-info → iqm_client-31.1.0.dist-info}/WHEEL +0 -0
- {iqm_client-30.2.0.dist-info → iqm_client-31.1.0.dist-info}/entry_points.txt +0 -0
- {iqm_client-30.2.0.dist-info → iqm_client-31.1.0.dist-info}/top_level.txt +0 -0
iqm/cirq_iqm/serialize.py
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Helper functions for serializing and deserializing quantum circuits between Cirq and IQM circuit formats."""
|
|
16
16
|
|
|
17
|
+
from math import pi
|
|
18
|
+
|
|
17
19
|
from cirq import Circuit, KeyCondition, NamedQid
|
|
18
20
|
from cirq.ops import (
|
|
19
21
|
ClassicallyControlledOperation,
|
|
@@ -26,9 +28,10 @@ from cirq.ops import (
|
|
|
26
28
|
XPowGate,
|
|
27
29
|
YPowGate,
|
|
28
30
|
)
|
|
29
|
-
from iqm import iqm_client
|
|
30
31
|
from iqm.cirq_iqm.iqm_gates import IQMMoveGate
|
|
31
|
-
|
|
32
|
+
|
|
33
|
+
import iqm.pulse
|
|
34
|
+
from iqm.pulse import CircuitOperation
|
|
32
35
|
|
|
33
36
|
# Mapping from IQM operation names to cirq operations
|
|
34
37
|
_IQM_CIRQ_OP_MAP: dict[str, tuple[type[Gate], ...]] = {
|
|
@@ -43,11 +46,11 @@ _IQM_CIRQ_OP_MAP: dict[str, tuple[type[Gate], ...]] = {
|
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
|
|
46
|
-
def
|
|
47
|
-
"""Convert an IQM
|
|
49
|
+
def circuit_operation_to_operation(circuit_operation: CircuitOperation) -> Operation:
|
|
50
|
+
"""Convert an IQM circuit operation to a Cirq Operation.
|
|
48
51
|
|
|
49
52
|
Args:
|
|
50
|
-
|
|
53
|
+
circuit_operation: the IQM circuit_operation
|
|
51
54
|
|
|
52
55
|
Returns:
|
|
53
56
|
Operation: the converted operation
|
|
@@ -56,23 +59,29 @@ def instruction_to_operation(instr: Instruction) -> Operation:
|
|
|
56
59
|
OperationNotSupportedError When the circuit contains an unsupported operation.
|
|
57
60
|
|
|
58
61
|
"""
|
|
59
|
-
if
|
|
60
|
-
raise OperationNotSupportedError(f"Operation {
|
|
62
|
+
if circuit_operation.name not in _IQM_CIRQ_OP_MAP:
|
|
63
|
+
raise OperationNotSupportedError(f"Operation {circuit_operation.name} not supported.")
|
|
61
64
|
|
|
62
|
-
qubits = [NamedQid(qubit, dimension=2) for qubit in
|
|
65
|
+
qubits = [NamedQid(qubit, dimension=2) for qubit in circuit_operation.locus]
|
|
63
66
|
|
|
64
|
-
if
|
|
67
|
+
if circuit_operation.name == "cc_prx":
|
|
65
68
|
# special case
|
|
66
|
-
args = {
|
|
69
|
+
args = {
|
|
70
|
+
"exponent": circuit_operation.args["angle"] / pi,
|
|
71
|
+
"phase_exponent": circuit_operation.args["phase"] / pi,
|
|
72
|
+
}
|
|
67
73
|
# ignore feedback_qubit, we currently only support 1-qubit KeyConditions so it can be
|
|
68
74
|
# added in serialize_circuit
|
|
69
|
-
return PhasedXPowGate(**args)(*qubits).with_classical_controls(
|
|
70
|
-
|
|
71
|
-
cirq_op = _IQM_CIRQ_OP_MAP[
|
|
72
|
-
if
|
|
73
|
-
args = {
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
return PhasedXPowGate(**args)(*qubits).with_classical_controls(circuit_operation.args["feedback_key"])
|
|
76
|
+
|
|
77
|
+
cirq_op = _IQM_CIRQ_OP_MAP[circuit_operation.name][0]
|
|
78
|
+
if circuit_operation.name == "prx":
|
|
79
|
+
args = {
|
|
80
|
+
"exponent": circuit_operation.args["angle"] / pi,
|
|
81
|
+
"phase_exponent": circuit_operation.args["phase"] / pi,
|
|
82
|
+
}
|
|
83
|
+
elif circuit_operation.name == "measure":
|
|
84
|
+
args = {"num_qubits": len(qubits), "key": circuit_operation.args["key"]}
|
|
76
85
|
# ignore feedback_key, in Cirq it has to be the same as key
|
|
77
86
|
else:
|
|
78
87
|
# cz, move, reset have no args
|
|
@@ -84,7 +93,7 @@ class OperationNotSupportedError(RuntimeError):
|
|
|
84
93
|
"""Raised when a given operation is not supported by the IQM server."""
|
|
85
94
|
|
|
86
95
|
|
|
87
|
-
def
|
|
96
|
+
def operation_to_circuit_operation(operation: Operation) -> CircuitOperation:
|
|
88
97
|
"""Map a Cirq Operation to the IQM data transfer format.
|
|
89
98
|
|
|
90
99
|
Assumes the circuit has been transpiled so that it only contains operations natively supported by the
|
|
@@ -94,7 +103,7 @@ def map_operation(operation: Operation) -> Instruction:
|
|
|
94
103
|
operation: a Cirq Operation
|
|
95
104
|
|
|
96
105
|
Returns:
|
|
97
|
-
|
|
106
|
+
CircuitOperation: the converted operation
|
|
98
107
|
|
|
99
108
|
Raises:
|
|
100
109
|
OperationNotSupportedError When the circuit contains an unsupported operation.
|
|
@@ -102,25 +111,25 @@ def map_operation(operation: Operation) -> Instruction:
|
|
|
102
111
|
"""
|
|
103
112
|
locus = tuple(qubit.name if isinstance(qubit, NamedQid) else str(qubit) for qubit in operation.qubits)
|
|
104
113
|
if isinstance(operation.gate, (PhasedXPowGate, XPowGate, YPowGate)):
|
|
105
|
-
return
|
|
114
|
+
return CircuitOperation(
|
|
106
115
|
name="prx",
|
|
107
|
-
|
|
108
|
-
args={"
|
|
116
|
+
locus=locus,
|
|
117
|
+
args={"angle": operation.gate.exponent * pi, "phase": operation.gate.phase_exponent * pi},
|
|
109
118
|
)
|
|
110
119
|
if isinstance(operation.gate, MeasurementGate):
|
|
111
120
|
if any(operation.gate.full_invert_mask()):
|
|
112
121
|
raise OperationNotSupportedError("Invert mask not supported")
|
|
113
122
|
|
|
114
|
-
return
|
|
123
|
+
return CircuitOperation(
|
|
115
124
|
name="measure",
|
|
116
|
-
|
|
125
|
+
locus=locus,
|
|
117
126
|
args={"key": operation.gate.key},
|
|
118
127
|
)
|
|
119
128
|
if isinstance(operation.gate, CZPowGate):
|
|
120
129
|
if operation.gate.exponent == 1.0:
|
|
121
|
-
return
|
|
130
|
+
return CircuitOperation(
|
|
122
131
|
name="cz",
|
|
123
|
-
|
|
132
|
+
locus=locus,
|
|
124
133
|
args={},
|
|
125
134
|
)
|
|
126
135
|
raise OperationNotSupportedError(
|
|
@@ -128,14 +137,14 @@ def map_operation(operation: Operation) -> Instruction:
|
|
|
128
137
|
)
|
|
129
138
|
|
|
130
139
|
if isinstance(operation.gate, IQMMoveGate):
|
|
131
|
-
return
|
|
140
|
+
return CircuitOperation(
|
|
132
141
|
name="move",
|
|
133
|
-
|
|
142
|
+
locus=locus,
|
|
134
143
|
args={},
|
|
135
144
|
)
|
|
136
145
|
|
|
137
146
|
if isinstance(operation.gate, ResetChannel):
|
|
138
|
-
return
|
|
147
|
+
return CircuitOperation(name="reset", locus=locus)
|
|
139
148
|
|
|
140
149
|
if isinstance(operation, ClassicallyControlledOperation):
|
|
141
150
|
if len(operation._conditions) > 1:
|
|
@@ -143,12 +152,12 @@ def map_operation(operation: Operation) -> Instruction:
|
|
|
143
152
|
if not isinstance(operation._conditions[0], KeyCondition):
|
|
144
153
|
raise OperationNotSupportedError("Only KeyConditions are supported as classical controls.")
|
|
145
154
|
if isinstance(operation._sub_operation.gate, (PhasedXPowGate, XPowGate, YPowGate)):
|
|
146
|
-
return
|
|
155
|
+
return CircuitOperation(
|
|
147
156
|
name="cc_prx",
|
|
148
|
-
|
|
157
|
+
locus=locus,
|
|
149
158
|
args={
|
|
150
|
-
"
|
|
151
|
-
"
|
|
159
|
+
"angle": operation._sub_operation.gate.exponent * pi,
|
|
160
|
+
"phase": operation._sub_operation.gate.phase_exponent * pi,
|
|
152
161
|
"feedback_qubit": "",
|
|
153
162
|
"feedback_key": str(operation._conditions[0]),
|
|
154
163
|
},
|
|
@@ -162,7 +171,7 @@ def map_operation(operation: Operation) -> Instruction:
|
|
|
162
171
|
raise OperationNotSupportedError(f"{type(operation.gate)} not natively supported.")
|
|
163
172
|
|
|
164
173
|
|
|
165
|
-
def serialize_circuit(circuit: Circuit) ->
|
|
174
|
+
def serialize_circuit(circuit: Circuit) -> iqm.pulse.Circuit:
|
|
166
175
|
"""Serializes a quantum circuit into the IQM data transfer format.
|
|
167
176
|
|
|
168
177
|
Args:
|
|
@@ -174,10 +183,10 @@ def serialize_circuit(circuit: Circuit) -> iqm_client.Circuit:
|
|
|
174
183
|
"""
|
|
175
184
|
total_ops_list = [op for moment in circuit for op in moment]
|
|
176
185
|
cc_prx_support = any(isinstance(op, ClassicallyControlledOperation) for op in total_ops_list)
|
|
177
|
-
instructions =
|
|
186
|
+
instructions = tuple(map(operation_to_circuit_operation, total_ops_list))
|
|
178
187
|
|
|
179
188
|
if cc_prx_support:
|
|
180
|
-
mkey_to_measurement = {}
|
|
189
|
+
mkey_to_measurement: dict[str, CircuitOperation] = {}
|
|
181
190
|
for inst in instructions:
|
|
182
191
|
if inst.name == "measure":
|
|
183
192
|
if inst.args["key"] in mkey_to_measurement:
|
|
@@ -190,15 +199,15 @@ def serialize_circuit(circuit: Circuit) -> iqm_client.Circuit:
|
|
|
190
199
|
raise OperationNotSupportedError(
|
|
191
200
|
f"cc_prx has feedback_key {feedback_key}, but no measure operation with that key precedes it."
|
|
192
201
|
)
|
|
193
|
-
if len(measurement.
|
|
202
|
+
if len(measurement.locus) != 1:
|
|
194
203
|
raise OperationNotSupportedError("cc_prx must depend on the measurement result of a single qubit.")
|
|
195
|
-
inst.args["feedback_qubit"] = measurement.
|
|
204
|
+
inst.args["feedback_qubit"] = measurement.locus[0]
|
|
196
205
|
measurement.args["feedback_key"] = feedback_key
|
|
197
206
|
|
|
198
|
-
return
|
|
207
|
+
return iqm.pulse.Circuit(name="Serialized from Cirq", instructions=instructions, metadata=None)
|
|
199
208
|
|
|
200
209
|
|
|
201
|
-
def deserialize_circuit(circuit:
|
|
210
|
+
def deserialize_circuit(circuit: iqm.pulse.Circuit) -> Circuit:
|
|
202
211
|
"""Deserializes a quantum circuit from the IQM data transfer format to a Cirq Circuit.
|
|
203
212
|
|
|
204
213
|
Args:
|
|
@@ -210,7 +219,7 @@ def deserialize_circuit(circuit: iqm_client.Circuit) -> Circuit:
|
|
|
210
219
|
"""
|
|
211
220
|
return Circuit(
|
|
212
221
|
map(
|
|
213
|
-
|
|
222
|
+
circuit_operation_to_operation,
|
|
214
223
|
circuit.instructions,
|
|
215
224
|
)
|
|
216
225
|
)
|
iqm/iqm_client/iqm_client.py
CHANGED
|
@@ -243,7 +243,7 @@ class IQMClient:
|
|
|
243
243
|
# validate the circuit against the static information in iqm.iqm_client.models._SUPPORTED_OPERATIONS
|
|
244
244
|
validate_circuit(circuit)
|
|
245
245
|
except ValueError as e:
|
|
246
|
-
raise CircuitValidationError(f"The circuit at index {i} failed the validation").with_traceback(
|
|
246
|
+
raise CircuitValidationError(f"The circuit at index {i} failed the validation: {e}").with_traceback(
|
|
247
247
|
e.__traceback__
|
|
248
248
|
)
|
|
249
249
|
|