iqm-client 30.1.0__py3-none-any.whl → 31.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.
@@ -364,5 +364,5 @@ class IQMDevice(devices.Device):
364
364
  if len(qubits_updated) != 0:
365
365
  raise ValueError(f"Circuit ends with a qubit state in the resonator {res!r}.")
366
366
 
367
- def __eq__(self, other):
367
+ def __eq__(self, other): # noqa: ANN001
368
368
  return self.__class__ == other.__class__ and self._metadata == other._metadata
@@ -166,5 +166,5 @@ class IQMDeviceMetadata(devices.DeviceMetadata):
166
166
  """Returns the ``cirq.Gateset`` of supported gates on this device."""
167
167
  return self._gateset
168
168
 
169
- def _value_equality_values_(self):
169
+ def _value_equality_values_(self): # noqa: ANN202
170
170
  return *super()._value_equality_values_(), self._gateset
@@ -85,7 +85,7 @@ class IQMSampler(cirq.work.Sampler):
85
85
  """Returns the device used by the sampler."""
86
86
  return self._device
87
87
 
88
- def close_client(self):
88
+ def close_client(self): # noqa: ANN201
89
89
  """Close IQMClient's session with the user authentication server. Discard the client."""
90
90
  if not self._client:
91
91
  return
@@ -92,7 +92,7 @@ class MergeOneParameterGroupGates(circuits.PointOptimizer):
92
92
  GATE_MERGING_TOLERANCE = 1e-10
93
93
 
94
94
  @classmethod
95
- def _normalize_par(cls, par):
95
+ def _normalize_par(cls, par): # noqa: ANN001
96
96
  """Normalizes the given parameter value to (-period/2, period/2]."""
97
97
  shift = cls.PERIOD / 2
98
98
  return operator.mod(par - shift, -cls.PERIOD) + shift
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
- from iqm.iqm_client import Instruction
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 instruction_to_operation(instr: Instruction) -> Operation:
47
- """Convert an IQM instruction to a Cirq Operation.
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
- instr: the IQM instruction
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 instr.name not in _IQM_CIRQ_OP_MAP:
60
- raise OperationNotSupportedError(f"Operation {instr.name} not supported.")
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 instr.qubits]
65
+ qubits = [NamedQid(qubit, dimension=2) for qubit in circuit_operation.locus]
63
66
 
64
- if instr.name == "cc_prx":
67
+ if circuit_operation.name == "cc_prx":
65
68
  # special case
66
- args = {"exponent": 2 * instr.args["angle_t"], "phase_exponent": 2 * instr.args["phase_t"]}
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(instr.args["feedback_key"])
70
-
71
- cirq_op = _IQM_CIRQ_OP_MAP[instr.name][0]
72
- if instr.name == "prx":
73
- args = {"exponent": 2 * instr.args["angle_t"], "phase_exponent": 2 * instr.args["phase_t"]}
74
- elif instr.name == "measure":
75
- args = {"num_qubits": len(qubits), "key": instr.args["key"]}
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 map_operation(operation: Operation) -> Instruction:
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
- Instruction: the converted operation
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 Instruction(
114
+ return CircuitOperation(
106
115
  name="prx",
107
- qubits=locus,
108
- args={"angle_t": operation.gate.exponent / 2, "phase_t": operation.gate.phase_exponent / 2},
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 Instruction(
123
+ return CircuitOperation(
115
124
  name="measure",
116
- qubits=locus,
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 Instruction(
130
+ return CircuitOperation(
122
131
  name="cz",
123
- qubits=locus,
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 Instruction(
140
+ return CircuitOperation(
132
141
  name="move",
133
- qubits=locus,
142
+ locus=locus,
134
143
  args={},
135
144
  )
136
145
 
137
146
  if isinstance(operation.gate, ResetChannel):
138
- return Instruction(name="reset", qubits=locus)
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 Instruction(
155
+ return CircuitOperation(
147
156
  name="cc_prx",
148
- qubits=locus,
157
+ locus=locus,
149
158
  args={
150
- "angle_t": operation._sub_operation.gate.exponent / 2,
151
- "phase_t": operation._sub_operation.gate.phase_exponent / 2,
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) -> iqm_client.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 = list(map(map_operation, total_ops_list))
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.qubits) != 1:
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.qubits[0]
204
+ inst.args["feedback_qubit"] = measurement.locus[0]
196
205
  measurement.args["feedback_key"] = feedback_key
197
206
 
198
- return iqm_client.Circuit(name="Serialized from Cirq", instructions=instructions, metadata=None)
207
+ return iqm.pulse.Circuit(name="Serialized from Cirq", instructions=instructions, metadata=None)
199
208
 
200
209
 
201
- def deserialize_circuit(circuit: iqm_client.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
- instruction_to_operation,
222
+ circuit_operation_to_operation,
214
223
  circuit.instructions,
215
224
  )
216
225
  )
iqm/iqm_client/cli/cli.py CHANGED
@@ -58,7 +58,7 @@ class ClickLoggingHandler(logging.Handler):
58
58
  super().__init__(level=logging.NOTSET)
59
59
  self.formatter = logging.Formatter("%(message)s")
60
60
 
61
- def emit(self, record):
61
+ def emit(self, record): # noqa: ANN001, ANN201
62
62
  click.echo(self.format(record))
63
63
 
64
64
 
@@ -463,7 +463,7 @@ def auth() -> None:
463
463
  help="Location of the configuration file to be used.",
464
464
  )
465
465
  @click.option("-v", "--verbose", is_flag=True, help="Print extra information.")
466
- def status(config_file, verbose) -> None:
466
+ def status(config_file, verbose) -> None: # noqa: ANN001
467
467
  """Check status of authentication."""
468
468
  _set_log_level_by_verbosity(verbose)
469
469
 
@@ -503,7 +503,7 @@ def status(config_file, verbose) -> None:
503
503
  click.echo(f"Token manager: {click.style('NOT RUNNING', fg='red')}")
504
504
 
505
505
 
506
- def _validate_iqm_client_cli_auth_login(no_daemon, no_refresh, config_file) -> ConfigFile:
506
+ def _validate_iqm_client_cli_auth_login(no_daemon, no_refresh, config_file) -> ConfigFile: # noqa: ANN001
507
507
  """Checks if provided combination of auth login options is valid:
508
508
  - no_daemon and no_refresh are mutually exclusive
509
509
  - config file should pass validation
@@ -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