cirq-aqt 1.4.0.dev20240415214855__py3-none-any.whl → 1.4.0.dev20240419073809__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.
cirq_aqt/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.4.0.dev20240415214855"
1
+ __version__ = "1.4.0.dev20240419073809"
cirq_aqt/aqt_device.py CHANGED
@@ -25,6 +25,7 @@ The native gate set consists of the local gates: X, Y, and XX entangling gates
25
25
  """
26
26
 
27
27
  import json
28
+ from enum import Enum
28
29
  from typing import Any, cast, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union
29
30
 
30
31
  import networkx as nx
@@ -36,11 +37,27 @@ from cirq_aqt import aqt_device_metadata
36
37
  gate_dict = {'X': cirq.X, 'Y': cirq.Y, 'Z': cirq.Z, 'MS': cirq.XX, 'R': cirq.PhasedXPowGate}
37
38
 
38
39
 
40
+ class OperationString(Enum):
41
+ """String representations of operations supported by AQT resources."""
42
+
43
+ MS = "MS"
44
+ """Cirq: XXPowGate, AQT: RXX gate."""
45
+
46
+ Z = "Z"
47
+ """Cirq: ZPowGate, AQT: RZ gate."""
48
+
49
+ R = "R"
50
+ """Cirq: PhasedXPowGate, AQT: R gate."""
51
+
52
+ MEASURE = "Meas"
53
+ """Measurement gate."""
54
+
55
+
39
56
  def get_op_string(op_obj: cirq.Operation) -> str:
40
57
  """Find the string representation for a given gate or operation.
41
58
 
42
59
  Args:
43
- op_obj: Gate or operation object. Gate must be one of: XXPowGate, XPowGate, YPowGate,
60
+ op_obj: Gate or operation object. Gate must be one of: XXPowGate,
44
61
  ZPowGate, PhasedXPowGate, or MeasurementGate.
45
62
 
46
63
  Returns:
@@ -50,20 +67,16 @@ def get_op_string(op_obj: cirq.Operation) -> str:
50
67
  ValueError: If the gate is not one of the supported gates.
51
68
  """
52
69
  if isinstance(op_obj.gate, cirq.XXPowGate):
53
- op_str = 'MS'
54
- elif isinstance(op_obj.gate, cirq.XPowGate):
55
- op_str = 'X'
56
- elif isinstance(op_obj.gate, cirq.YPowGate):
57
- op_str = 'Y'
70
+ op_str = OperationString.MS.value
58
71
  elif isinstance(op_obj.gate, cirq.ZPowGate):
59
- op_str = 'Z'
72
+ op_str = OperationString.Z.value
60
73
  elif isinstance(op_obj.gate, cirq.PhasedXPowGate):
61
- op_str = 'R'
74
+ op_str = OperationString.R.value
62
75
  elif isinstance(op_obj.gate, cirq.MeasurementGate):
63
- op_str = 'Meas'
76
+ op_str = OperationString.MEASURE.value
64
77
  else:
65
78
  raise ValueError(f'Got unknown gate on operation: {op_obj}.')
66
- return op_str
79
+ return str(op_str)
67
80
 
68
81
 
69
82
  class AQTNoiseModel(cirq.NoiseModel):
@@ -97,6 +110,7 @@ class AQTNoiseModel(cirq.NoiseModel):
97
110
  for qubit in op.qubits:
98
111
  noise_list.append(noise_op.on(qubit))
99
112
  noise_list += self.get_crosstalk_operation(op, system_qubits)
113
+
100
114
  return list(moment) + noise_list
101
115
 
102
116
  def get_crosstalk_operation(
@@ -122,16 +136,18 @@ class AQTNoiseModel(cirq.NoiseModel):
122
136
  for neigh_idx in neighbors:
123
137
  if neigh_idx >= 0 and neigh_idx < num_qubits:
124
138
  xtlk_arr[neigh_idx] = self.noise_op_dict['crosstalk']
139
+
125
140
  for idx in idx_list:
126
141
  xtlk_arr[idx] = 0
127
142
  xtlk_op_list = []
128
143
  op_str = get_op_string(operation)
129
144
  gate = cast(cirq.EigenGate, gate_dict[op_str])
145
+
130
146
  if len(operation.qubits) == 1:
131
147
  for idx in xtlk_arr.nonzero()[0]:
132
148
  exponent = operation.gate.exponent # type:ignore
133
149
  exponent = exponent * xtlk_arr[idx]
134
- xtlk_op = gate.on(system_qubits[idx]) ** exponent
150
+ xtlk_op = operation.gate.on(system_qubits[idx]) ** exponent # type:ignore
135
151
  xtlk_op_list.append(xtlk_op)
136
152
  elif len(operation.qubits) == 2:
137
153
  for op_qubit in operation.qubits:
@@ -216,10 +232,14 @@ class AQTSimulator:
216
232
  noise_model = cirq.NO_NOISE
217
233
  else:
218
234
  noise_model = AQTNoiseModel()
235
+
219
236
  if self.circuit == cirq.Circuit():
220
237
  raise RuntimeError('Simulate called without a valid circuit.')
238
+
221
239
  sim = cirq.DensityMatrixSimulator(noise=noise_model)
240
+
222
241
  result = sim.run(self.circuit, repetitions=repetitions)
242
+
223
243
  return result
224
244
 
225
245
 
@@ -342,10 +362,9 @@ def get_aqt_device(num_qubits: int) -> Tuple[AQTDevice, List[cirq.LineQubit]]:
342
362
  def get_default_noise_dict() -> Dict[str, Any]:
343
363
  """Returns the current noise parameters"""
344
364
  default_noise_dict = {
345
- 'X': cirq.depolarize(1e-3),
346
- 'Y': cirq.depolarize(1e-3),
347
- 'Z': cirq.depolarize(1e-3),
348
- 'MS': cirq.depolarize(1e-2),
365
+ OperationString.R.value: cirq.depolarize(1e-3),
366
+ OperationString.Z.value: cirq.depolarize(0),
367
+ OperationString.MS.value: cirq.depolarize(1e-2),
349
368
  'crosstalk': 0.03,
350
369
  }
351
370
  return default_noise_dict
@@ -53,8 +53,6 @@ class AQTDeviceMetadata(cirq.DeviceMetadata):
53
53
  self._gate_durations = {
54
54
  cirq.GateFamily(cirq.MeasurementGate): self._measurement_duration,
55
55
  cirq.GateFamily(cirq.XXPowGate): self._twoq_gates_duration,
56
- cirq.GateFamily(cirq.XPowGate): self._oneq_gates_duration,
57
- cirq.GateFamily(cirq.YPowGate): self._oneq_gates_duration,
58
56
  cirq.GateFamily(cirq.ZPowGate): self._oneq_gates_duration,
59
57
  cirq.GateFamily(cirq.PhasedXPowGate): self._oneq_gates_duration,
60
58
  }
@@ -45,7 +45,7 @@ def test_aqtdevice_metadata(metadata, qubits):
45
45
  assert len(edges) == 10
46
46
  assert all(q0 != q1 for q0, q1 in edges)
47
47
  assert AQTTargetGateset() == metadata.gateset
48
- assert len(metadata.gate_durations) == 6
48
+ assert len(metadata.gate_durations) == 4
49
49
 
50
50
 
51
51
  def test_aqtdevice_duration_of(metadata, qubits):
cirq_aqt/aqt_sampler.py CHANGED
@@ -25,13 +25,75 @@ API keys for classical simulators and quantum devices can be obtained at:
25
25
  import json
26
26
  import time
27
27
  import uuid
28
- from typing import cast, Dict, List, Sequence, Tuple, Union
28
+ from typing import Callable, cast, Dict, List, Sequence, Tuple, Union, Literal, TypedDict
29
+ from urllib.parse import urljoin
29
30
 
30
31
  import numpy as np
31
- from requests import put
32
+ from requests import post, get
32
33
 
33
34
  import cirq
34
- from cirq_aqt.aqt_device import AQTSimulator, get_op_string
35
+ from cirq_aqt.aqt_device import AQTSimulator, get_op_string, OperationString
36
+
37
+
38
+ _DEFAULT_HOST = "https://arnica.aqt.eu/api/v1/"
39
+
40
+
41
+ class SingleQubitGate(TypedDict):
42
+ """Abstract single qubit rotation."""
43
+
44
+ qubit: int
45
+
46
+
47
+ class GateRZ(SingleQubitGate):
48
+ """A single-qubit rotation rotation around the Bloch sphere's z-axis."""
49
+
50
+ operation: Literal["RZ"]
51
+ phi: float
52
+
53
+
54
+ class GateR(SingleQubitGate):
55
+ """A single-qubit rotation around an arbitrary axis on the Bloch sphere's equatorial plane."""
56
+
57
+ operation: Literal["R"]
58
+ phi: float
59
+ theta: float
60
+
61
+
62
+ class GateRXX(TypedDict):
63
+ """A two-qubit entangling gate of Mølmer-Sørenson-type."""
64
+
65
+ operation: Literal["RXX"]
66
+ qubits: list[int]
67
+ theta: float
68
+
69
+
70
+ class Measure(TypedDict):
71
+ """Measurement operation.
72
+
73
+ The MEASURE operation instructs the resource
74
+ to perform a projective measurement of all qubits.
75
+ """
76
+
77
+ operation: Literal["MEASURE"]
78
+
79
+
80
+ Gate = GateRZ | GateR | GateRXX
81
+ Operation = Gate | Measure
82
+
83
+
84
+ class Resource(TypedDict):
85
+ """A quantum computing device."""
86
+
87
+ id: str
88
+ name: str
89
+ type: Literal["device", "simulator"]
90
+
91
+
92
+ class Workspace(TypedDict):
93
+ """A user workspace."""
94
+
95
+ id: str
96
+ resources: list[Resource]
35
97
 
36
98
 
37
99
  class AQTSampler(cirq.Sampler):
@@ -40,16 +102,127 @@ class AQTSampler(cirq.Sampler):
40
102
  runs a single circuit or an entire sweep remotely
41
103
  """
42
104
 
43
- def __init__(self, remote_host: str, access_token: str):
105
+ def __init__(
106
+ self, workspace: str, resource: str, access_token: str, remote_host: str = _DEFAULT_HOST
107
+ ):
44
108
  """Inits AQTSampler.
45
109
 
46
110
  Args:
47
- remote_host: Address of the remote device.
48
- access_token: Access token for the remote api.
111
+ workspace: the ID of the workspace you have access to.
112
+ resource: the ID of the resource to run the circuit on.
113
+ access_token: Access token for the AQT API.
114
+ remote_host: Address of the AQT API.
49
115
  """
116
+ self.workspace = workspace
117
+ self.resource = resource
50
118
  self.remote_host = remote_host
51
119
  self.access_token = access_token
52
120
 
121
+ @staticmethod
122
+ def fetch_resources(access_token: str, remote_host: str = _DEFAULT_HOST) -> list[Workspace]:
123
+ """Lists the workspaces and resources that are accessible with access_token.
124
+
125
+ Returns a list containing the workspaces and resources that the passed
126
+ access_token gives access to. The workspace and resource IDs in this list can be
127
+ used to submit jobs using the run and run_sweep methods.
128
+
129
+ The printed table contains four columns:
130
+ - WORKSPACE ID: the ID of the workspace. Use this value to submit circuits.
131
+ - RESOURCE NAME: the human-readable name of the resource.
132
+ - RESOURCE ID: the ID of the resource. Use this value to submit circuits.
133
+ - D/S: whether the resource is a (D)evice or (S)imulator.
134
+
135
+ Args:
136
+ access_token: Access token for the AQT API.
137
+ remote_host: Address of the AQT API. Defaults to "https://arnica.aqt.eu/api/v1/".
138
+
139
+ Raises:
140
+ RuntimeError: If there was an unexpected response from the server.
141
+ """
142
+ headers = {"Authorization": f"Bearer {access_token}", "SDK": "cirq"}
143
+ url = urljoin(remote_host if remote_host[-1] == "/" else remote_host + "/", "workspaces")
144
+
145
+ response = get(url, headers=headers)
146
+ if response.status_code != 200:
147
+ raise RuntimeError('Got unexpected return data from server: \n' + str(response.json()))
148
+
149
+ workspaces = [
150
+ Workspace(
151
+ id=w['id'],
152
+ resources=[
153
+ Resource(id=r['id'], name=r['name'], type=r['type']) for r in w['resources']
154
+ ],
155
+ )
156
+ for w in response.json()
157
+ ]
158
+
159
+ return workspaces
160
+
161
+ @staticmethod
162
+ def print_resources(
163
+ access_token: str, emit: Callable = print, remote_host: str = _DEFAULT_HOST
164
+ ) -> None:
165
+ """Displays the workspaces and resources that are accessible with access_token.
166
+
167
+ Prints a table using the function passed as 'emit' containing the workspaces and
168
+ resources that the passed access_token gives access to. The IDs in this table
169
+ can be used to submit jobs using the run and run_sweep methods.
170
+
171
+ The printed table contains four columns:
172
+ - WORKSPACE ID: the ID of the workspace. Use this value to submit circuits.
173
+ - RESOURCE NAME: the human-readable name of the resource.
174
+ - RESOURCE ID: the ID of the resource. Use this value to submit circuits.
175
+ - D/S: whether the resource is a (D)evice or (S)imulator.
176
+
177
+ Args:
178
+ access_token: Access token for the AQT API.
179
+ emit (optional): A Callable which will be called once with a single string argument,
180
+ containing the table. Defaults to print from the standard library.
181
+ remote_host (optional): Address of the AQT API. Defaults to
182
+ "https://arnica.aqt.eu/api/v1/".
183
+
184
+ Raises:
185
+ RuntimeError: If there was an unexpected response from the server.
186
+ """
187
+ table_lines = []
188
+ workspaces = AQTSampler.fetch_resources(access_token, remote_host)
189
+
190
+ if len(workspaces) == 0:
191
+ return emit("No workspaces are accessible with this access token.")
192
+ if any(len(w['resources']) == 0 for w in workspaces):
193
+ return emit("No workspaces accessible with this access token contain resources.")
194
+
195
+ col_widths = [
196
+ max([len(w['id']) for w in workspaces]),
197
+ max([len(d['name']) for w in workspaces for d in w['resources']]),
198
+ max([len(d['id']) for w in workspaces for d in w['resources']]),
199
+ 3,
200
+ ]
201
+ SEPARATOR = "+-" + "-+-".join(col_width * "-" for col_width in col_widths) + "-+"
202
+
203
+ table_lines.append(SEPARATOR)
204
+ table_lines.append(
205
+ f"| {'WORKSPACE ID'.ljust(col_widths[0])} |"
206
+ f" {'RESOURCE NAME'.ljust(col_widths[1])} |"
207
+ f" {'RESOURCE ID'.ljust(col_widths[2])} |"
208
+ f" {'D/S'.ljust(col_widths[3])} |"
209
+ )
210
+ table_lines.append(SEPARATOR)
211
+
212
+ for workspace in workspaces:
213
+ next_workspace = workspace['id']
214
+ for resource in workspace["resources"]:
215
+ table_lines.append(
216
+ f"| {next_workspace.ljust(col_widths[0])} |"
217
+ f" {resource['name'].ljust(col_widths[1])} |"
218
+ f" {resource['id'].ljust(col_widths[2])} |"
219
+ f" {resource['type'][0].upper().ljust(col_widths[3])} |"
220
+ )
221
+ next_workspace = ""
222
+ table_lines.append(SEPARATOR)
223
+
224
+ emit("\n".join(table_lines))
225
+
53
226
  def _generate_json(
54
227
  self, circuit: cirq.AbstractCircuit, param_resolver: cirq.ParamResolverOrSimilarType
55
228
  ) -> str:
@@ -62,7 +235,7 @@ class AQTSampler(cirq.Sampler):
62
235
  which is a list of sequential quantum operations,
63
236
  each operation defined by:
64
237
 
65
- op_string: str that specifies the operation type: "X","Y","Z","MS"
238
+ op_string: str that specifies the operation type: "Z","MS","R","Meas"
66
239
  gate_exponent: float that specifies the gate_exponent of the operation
67
240
  qubits: list of qubits where the operation acts on.
68
241
 
@@ -100,27 +273,72 @@ class AQTSampler(cirq.Sampler):
100
273
  json_str = json.dumps(seq_list)
101
274
  return json_str
102
275
 
276
+ def _parse_legacy_circuit_json(self, json_str: str) -> list[Operation]:
277
+ """Converts a legacy JSON circuit representation.
278
+
279
+ Converts a JSON created for the legacy API into one that will work
280
+ with the Arnica v1 API.
281
+
282
+ Raises:
283
+ ValueError:
284
+ * if there is not exactly one measurement operation at the end
285
+ of the circuit.
286
+
287
+ * if an operation is found in json_str that is not in
288
+ OperationString.
289
+
290
+ Args:
291
+ json_str: A JSON-formatted string that could be used as the
292
+ data parameter in the body of a request to the old AQT API.
293
+ """
294
+ circuit = []
295
+ number_of_measurements = 0
296
+ instruction: Operation
297
+
298
+ for legacy_op in json.loads(json_str):
299
+ if number_of_measurements > 0:
300
+ raise ValueError("Need exactly one `MEASURE` operation at the end of the circuit.")
301
+
302
+ if legacy_op[0] == OperationString.Z.value:
303
+ instruction = GateRZ(operation="RZ", qubit=legacy_op[2][0], phi=legacy_op[1])
304
+
305
+ elif legacy_op[0] == OperationString.R.value:
306
+ instruction = GateR(
307
+ operation="R", qubit=legacy_op[3][0], theta=legacy_op[1], phi=legacy_op[2]
308
+ )
309
+
310
+ elif legacy_op[0] == OperationString.MS.value:
311
+ instruction = GateRXX(operation="RXX", qubits=legacy_op[2], theta=legacy_op[1])
312
+
313
+ elif legacy_op[0] == OperationString.MEASURE.value:
314
+ instruction = Measure(operation="MEASURE")
315
+ number_of_measurements += 1
316
+
317
+ else:
318
+ raise ValueError(f'Got unknown gate on operation: {legacy_op}.')
319
+
320
+ circuit.append(instruction)
321
+
322
+ if circuit[-1]["operation"] != "MEASURE":
323
+ circuit.append({"operation": "MEASURE"})
324
+
325
+ return circuit
326
+
103
327
  def _send_json(
104
- self,
105
- *,
106
- json_str: str,
107
- id_str: Union[str, uuid.UUID],
108
- repetitions: int = 1,
109
- num_qubits: int = 1,
328
+ self, *, json_str: str, id_str: str, repetitions: int = 1, num_qubits: int = 1
110
329
  ) -> np.ndarray:
111
- """Sends the json string to the remote AQT device
330
+ """Sends the json string to the remote AQT device.
112
331
 
113
- The interface is given by PUT requests to a single endpoint URL.
114
- The first PUT will insert the circuit into the remote queue,
115
- given a valid access key.
116
- Every subsequent PUT will return a dictionary, where the key "status"
117
- is either 'queued', if the circuit has not been processed yet or
118
- 'finished' if the circuit has been processed.
119
- The experimental data is returned via the key 'data'
332
+ Submits a pre-prepared JSON string representing a circuit to the AQT
333
+ API, then polls for the result, which is parsed and returned when
334
+ available.
335
+
336
+ Please consider that due to the potential for long wait-times, there is
337
+ no timeout in the result polling.
120
338
 
121
339
  Args:
122
340
  json_str: Json representation of the circuit.
123
- id_str: Unique id of the datapoint.
341
+ id_str: A label to help identify a circuit.
124
342
  repetitions: Number of repetitions.
125
343
  num_qubits: Number of qubits present in the device.
126
344
 
@@ -130,49 +348,60 @@ class AQTSampler(cirq.Sampler):
130
348
  Raises:
131
349
  RuntimeError: If there was an unexpected response from the server.
132
350
  """
133
- header = {"Ocp-Apim-Subscription-Key": self.access_token, "SDK": "cirq"}
134
- response = put(
135
- self.remote_host,
136
- data={
137
- 'data': json_str,
138
- 'access_token': self.access_token,
139
- 'repetitions': repetitions,
140
- 'no_qubits': num_qubits,
351
+ headers = {"Authorization": f"Bearer {self.access_token}", "SDK": "cirq"}
352
+ quantum_circuit = self._parse_legacy_circuit_json(json_str)
353
+ submission_data = {
354
+ "job_type": "quantum_circuit",
355
+ "label": id_str,
356
+ "payload": {
357
+ "circuits": [
358
+ {
359
+ "repetitions": repetitions,
360
+ "quantum_circuit": quantum_circuit,
361
+ "number_of_qubits": num_qubits,
362
+ }
363
+ ]
141
364
  },
142
- headers=header,
143
- )
365
+ }
366
+
367
+ submission_url = urljoin(self.remote_host, f"submit/{self.workspace}/{self.resource}")
368
+
369
+ response = post(submission_url, json=submission_data, headers=headers)
144
370
  response = response.json()
145
371
  data = cast(Dict, response)
146
- if 'status' not in data.keys():
372
+
373
+ if 'response' not in data.keys() or 'status' not in data['response'].keys():
147
374
  raise RuntimeError('Got unexpected return data from server: \n' + str(data))
148
- if data['status'] == 'error':
375
+ if data['response']['status'] == 'error':
149
376
  raise RuntimeError('AQT server reported error: \n' + str(data))
150
377
 
151
- if 'id' not in data.keys():
378
+ if 'job' not in data.keys() or 'job_id' not in data['job'].keys():
152
379
  raise RuntimeError('Got unexpected return data from AQT server: \n' + str(data))
153
- id_str = data['id']
380
+ job_id = data['job']['job_id']
154
381
 
382
+ result_url = urljoin(self.remote_host, f"result/{job_id}")
155
383
  while True:
156
- response = put(
157
- self.remote_host,
158
- data={'id': id_str, 'access_token': self.access_token},
159
- headers=header,
160
- )
384
+ response = get(result_url, headers=headers)
161
385
  response = response.json()
162
386
  data = cast(Dict, response)
163
- if 'status' not in data.keys():
387
+
388
+ if 'response' not in data.keys() or 'status' not in data['response'].keys():
164
389
  raise RuntimeError('Got unexpected return data from AQT server: \n' + str(data))
165
- if data['status'] == 'finished':
390
+ if data['response']['status'] == 'finished':
166
391
  break
167
- elif data['status'] == 'error':
392
+ elif data['response']['status'] == 'error':
168
393
  raise RuntimeError('Got unexpected return data from AQT server: \n' + str(data))
169
394
  time.sleep(1.0)
170
- measurements_int = data['samples']
171
- measurements = np.zeros((len(measurements_int), num_qubits))
172
- for i, result_int in enumerate(measurements_int):
173
- measurement_int_bin = format(result_int, f'0{num_qubits}b')
395
+
396
+ if 'result' not in data['response'].keys():
397
+ raise RuntimeError('Got unexpected return data from AQT server: \n' + str(data))
398
+
399
+ measurement_int = data['response']['result']['0']
400
+ measurements = np.zeros((repetitions, num_qubits), dtype=int)
401
+ for i, repetition in enumerate(measurement_int):
174
402
  for j in range(num_qubits):
175
- measurements[i, j] = int(measurement_int_bin[j])
403
+ measurements[i, j] = repetition[j]
404
+
176
405
  return measurements
177
406
 
178
407
  def run_sweep(
@@ -198,7 +427,7 @@ class AQTSampler(cirq.Sampler):
198
427
  meas_name = 'm'
199
428
  trial_results: List[cirq.Result] = []
200
429
  for param_resolver in cirq.to_resolvers(params):
201
- id_str = uuid.uuid1()
430
+ id_str = str(uuid.uuid1())
202
431
  num_qubits = len(program.all_qubits())
203
432
  json_str = self._generate_json(circuit=program, param_resolver=param_resolver)
204
433
  results = self._send_json(
@@ -223,10 +452,19 @@ class AQTSamplerLocalSimulator(AQTSampler):
223
452
  sampler.simulate_ideal=True
224
453
  """
225
454
 
226
- def __init__(self, remote_host: str = '', access_token: str = '', simulate_ideal: bool = False):
455
+ def __init__(
456
+ self,
457
+ workspace: str = "",
458
+ resource: str = "",
459
+ access_token: str = "",
460
+ remote_host: str = "",
461
+ simulate_ideal: bool = False,
462
+ ):
227
463
  """Args:
228
- remote_host: Remote host is not used by the local simulator.
464
+ workspace: Workspace is not used by the local simulator.
465
+ resource: Resource is not used by the local simulator.
229
466
  access_token: Access token is not used by the local simulator.
467
+ remote_host: Remote host is not used by the local simulator.
230
468
  simulate_ideal: Boolean that determines whether a noisy or
231
469
  an ideal simulation is performed.
232
470
  """
@@ -235,18 +473,13 @@ class AQTSamplerLocalSimulator(AQTSampler):
235
473
  self.simulate_ideal = simulate_ideal
236
474
 
237
475
  def _send_json(
238
- self,
239
- *,
240
- json_str: str,
241
- id_str: Union[str, uuid.UUID],
242
- repetitions: int = 1,
243
- num_qubits: int = 1,
476
+ self, *, json_str: str, id_str: str, repetitions: int = 1, num_qubits: int = 1
244
477
  ) -> np.ndarray:
245
478
  """Replaces the remote host with a local simulator
246
479
 
247
480
  Args:
248
481
  json_str: Json representation of the circuit.
249
- id_str: Unique id of the datapoint.
482
+ id_str: A label to help identify a datapoint.
250
483
  repetitions: Number of repetitions.
251
484
  num_qubits: Number of qubits present in the device.
252
485
 
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  from unittest import mock
16
+ import json
16
17
  import numpy as np
17
18
  import pytest
18
19
  import sympy
@@ -22,15 +23,11 @@ from cirq_aqt import AQTSampler, AQTSamplerLocalSimulator
22
23
  from cirq_aqt.aqt_device import get_aqt_device, get_op_string
23
24
 
24
25
 
25
- class EngineReturn:
26
+ class GetResultReturn:
26
27
  """A put mock class for testing the REST interface"""
27
28
 
28
29
  def __init__(self):
29
- self.test_dict = {
30
- 'status': 'queued',
31
- 'id': '2131da',
32
- 'samples': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
33
- }
30
+ self.test_dict = {'job': {'job_id': '2131da'}, 'response': {'status': 'queued'}}
34
31
  self.counter = 0
35
32
 
36
33
  def json(self):
@@ -38,75 +35,104 @@ class EngineReturn:
38
35
  return self.test_dict
39
36
 
40
37
  def update(self, *args, **kwargs):
41
- if self.counter >= 2:
42
- self.test_dict['status'] = 'finished'
43
38
  return self
44
39
 
45
40
 
46
- class EngineError(EngineReturn):
41
+ class GetResultError(GetResultReturn):
47
42
  """A put mock class for testing error responses"""
48
43
 
49
44
  def __init__(self):
50
- self.test_dict = {'status': 'error', 'id': '2131da', 'samples': "Error message"}
45
+ self.test_dict = {'response': {}}
46
+ self.test_dict['response']['status'] = 'error'
47
+ self.test_dict['response']['message'] = "Error message"
51
48
  self.counter = 0
52
49
 
53
50
 
54
- class EngineNoid(EngineReturn):
55
- """A put mock class for testing error responses
56
- This will not return an id at the first call"""
57
-
58
- def __init__(self):
59
- self.test_dict = {'status': 'queued'}
60
- self.counter = 0
61
-
62
-
63
- class EngineNoStatus(EngineReturn):
51
+ class GetResultNoStatus(GetResultReturn):
64
52
  """A put mock class for testing error responses
65
53
  This will not return a status in the second call"""
66
54
 
67
55
  def update(self, *args, **kwargs):
68
- del self.test_dict['status']
56
+ del self.test_dict['response']['status']
69
57
  return self
70
58
 
71
59
 
72
- class EngineNoStatus2(EngineReturn):
60
+ class GetResultErrorSecond(GetResultReturn):
73
61
  """A put mock class for testing error responses
74
- This will not return a status in the second call"""
62
+ This will return an error on the second put call"""
75
63
 
76
64
  def update(self, *args, **kwargs):
77
65
  if self.counter >= 1:
78
- del self.test_dict['status']
66
+ self.test_dict['response']['status'] = 'error'
79
67
  return self
80
68
 
81
69
 
82
- class EngineErrorSecond(EngineReturn):
70
+ class SubmitGoodResponse:
71
+ def json(self):
72
+ return {"job": {"job_id": "test_job"}, "response": {"status": "queued"}}
73
+
74
+
75
+ class SubmitResultNoID:
83
76
  """A put mock class for testing error responses
84
- This will return an error on the second put call"""
77
+ This will not return an id at the first call"""
78
+
79
+ def json(self):
80
+ return {"job": {}, "response": {"status": "queued"}}
81
+
82
+
83
+ class SubmitResultNoStatus:
84
+ """A put mock class for testing error responses
85
+ This will not return an id at the first call"""
86
+
87
+ def json(self):
88
+ return {"job": {"job_id": "test_job"}, "response": {}}
85
89
 
86
- def update(self, *args, **kwargs):
87
- if self.counter >= 1:
88
- self.test_dict['status'] = 'error'
89
- return self
90
90
 
91
+ class SubmitResultWithError:
92
+ """A put mock class for testing error responses
93
+ This will not return an id at the first call"""
94
+
95
+ def json(self):
96
+ return {"job": {"job_id": "test_job"}, "response": {"status": "error"}}
91
97
 
92
- def test_aqt_sampler_error_handling():
93
- for e_return in [
94
- EngineError(),
95
- EngineErrorSecond(),
96
- EngineNoStatus(),
97
- EngineNoStatus2(),
98
- EngineNoid(),
99
- ]:
100
- with mock.patch(
101
- 'cirq_aqt.aqt_sampler.put', return_value=e_return, side_effect=e_return.update
102
- ) as _mock_method:
98
+
99
+ def test_aqt_sampler_submit_job_error_handling():
100
+ for e_return in [SubmitResultNoID(), SubmitResultNoStatus(), SubmitResultWithError()]:
101
+ with (
102
+ mock.patch('cirq_aqt.aqt_sampler.post', return_value=e_return),
103
+ mock.patch('cirq_aqt.aqt_sampler.get', return_value=GetResultReturn()),
104
+ ):
103
105
  theta = sympy.Symbol('theta')
104
106
  num_points = 1
105
107
  max_angle = np.pi
106
108
  repetitions = 10
107
- sampler = AQTSampler(remote_host="http://localhost:5000", access_token='testkey')
109
+ sampler = AQTSampler(access_token='testkey', workspace="default", resource="test")
108
110
  _, qubits = get_aqt_device(1)
109
- circuit = cirq.Circuit(cirq.X(qubits[0]) ** theta)
111
+ circuit = cirq.Circuit(
112
+ cirq.PhasedXPowGate(exponent=theta, phase_exponent=0.0).on(qubits[0])
113
+ )
114
+ sweep = cirq.Linspace(key='theta', start=0.1, stop=max_angle / np.pi, length=num_points)
115
+ with pytest.raises(RuntimeError):
116
+ _results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions)
117
+
118
+
119
+ def test_aqt_sampler_get_result_error_handling():
120
+ for e_return in [GetResultError(), GetResultErrorSecond(), GetResultNoStatus()]:
121
+ with (
122
+ mock.patch('cirq_aqt.aqt_sampler.post', return_value=SubmitGoodResponse()),
123
+ mock.patch(
124
+ 'cirq_aqt.aqt_sampler.get', return_value=e_return, side_effect=e_return.update
125
+ ),
126
+ ):
127
+ theta = sympy.Symbol('theta')
128
+ num_points = 1
129
+ max_angle = np.pi
130
+ repetitions = 10
131
+ sampler = AQTSampler(access_token='testkey', workspace="default", resource="test")
132
+ _, qubits = get_aqt_device(1)
133
+ circuit = cirq.Circuit(
134
+ cirq.PhasedXPowGate(exponent=theta, phase_exponent=0.0).on(qubits[0])
135
+ )
110
136
  sweep = cirq.Linspace(key='theta', start=0.1, stop=max_angle / np.pi, length=num_points)
111
137
  with pytest.raises(RuntimeError):
112
138
  _results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions)
@@ -127,28 +153,48 @@ def test_aqt_sampler_empty_circuit():
127
153
 
128
154
 
129
155
  def test_aqt_sampler():
130
- put_call_args0 = {'access_token': 'testkey', 'id': '2131da'}
131
-
132
- e_return = EngineReturn()
133
- with mock.patch(
134
- 'cirq_aqt.aqt_sampler.put', return_value=e_return, side_effect=e_return.update
135
- ) as mock_method:
156
+ class ResultReturn:
157
+ def __init__(self):
158
+ self.request_counter = 0
159
+ self.status = "queued"
160
+
161
+ def json(self):
162
+ return {"response": {"status": self.status, "result": {"0": [[1, 1], [0, 0]]}}}
163
+
164
+ def on_request(self, *args, **kwargs):
165
+ self.request_counter += 1
166
+ if self.request_counter >= 3:
167
+ self.status = "finished"
168
+ return self
169
+
170
+ result_return = ResultReturn()
171
+
172
+ with (
173
+ mock.patch('cirq_aqt.aqt_sampler.post', return_value=SubmitGoodResponse()) as submit_method,
174
+ mock.patch(
175
+ 'cirq_aqt.aqt_sampler.get',
176
+ return_value=result_return,
177
+ side_effect=result_return.on_request,
178
+ ) as result_method,
179
+ ):
136
180
  theta = sympy.Symbol('theta')
137
181
  num_points = 1
138
182
  max_angle = np.pi
139
183
  repetitions = 10
140
- sampler = AQTSampler(remote_host="http://localhost:5000", access_token='testkey')
184
+ sampler = AQTSampler(access_token='testkey', workspace="default", resource="test")
141
185
  _, qubits = get_aqt_device(1)
142
- circuit = cirq.Circuit(cirq.X(qubits[0]) ** theta)
186
+ circuit = cirq.Circuit(
187
+ cirq.PhasedXPowGate(exponent=theta, phase_exponent=0.0).on(qubits[0])
188
+ )
143
189
  sweep = cirq.Linspace(key='theta', start=0.1, stop=max_angle / np.pi, length=num_points)
144
190
  results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions)
145
191
  excited_state_probs = np.zeros(num_points)
192
+
146
193
  for i in range(num_points):
147
194
  excited_state_probs[i] = np.mean(results[i].measurements['m'])
148
- callargs = mock_method.call_args[1]['data']
149
- for keys in put_call_args0:
150
- assert callargs[keys] == put_call_args0[keys]
151
- assert mock_method.call_count == 3
195
+
196
+ assert submit_method.call_count == 1
197
+ assert result_method.call_count == 3
152
198
 
153
199
 
154
200
  def test_aqt_sampler_sim():
@@ -161,13 +207,13 @@ def test_aqt_sampler_sim():
161
207
  sampler = AQTSamplerLocalSimulator()
162
208
  sampler.simulate_ideal = True
163
209
  circuit = cirq.Circuit(
164
- cirq.X(qubits[3]) ** theta,
165
- cirq.X(qubits[0]),
166
- cirq.X(qubits[0]),
167
- cirq.X(qubits[1]),
168
- cirq.X(qubits[1]),
169
- cirq.X(qubits[2]),
170
- cirq.X(qubits[2]),
210
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=theta).on(qubits[3]),
211
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[0]),
212
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[0]),
213
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[1]),
214
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[1]),
215
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[2]),
216
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[2]),
171
217
  )
172
218
  circuit.append(cirq.PhasedXPowGate(phase_exponent=0.5, exponent=-0.5).on(qubits[0]))
173
219
  circuit.append(cirq.PhasedXPowGate(phase_exponent=0.5, exponent=0.5).on(qubits[0]))
@@ -188,11 +234,13 @@ def test_aqt_sampler_sim_xtalk():
188
234
  sampler = AQTSamplerLocalSimulator()
189
235
  sampler.simulate_ideal = False
190
236
  circuit = cirq.Circuit(
191
- cirq.X(qubits[0]),
192
- cirq.X(qubits[1]),
193
- cirq.X(qubits[1]),
194
- cirq.X(qubits[3]),
195
- cirq.X(qubits[2]),
237
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[0]),
238
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[1]),
239
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[1]),
240
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[3]),
241
+ cirq.PhasedXPowGate(phase_exponent=0.0, exponent=1.0).on(qubits[2]),
242
+ cirq.XX(qubits[0], qubits[1]) ** 0.5,
243
+ cirq.Z.on_each(*qubits),
196
244
  )
197
245
  sweep = cirq.Linspace(key='theta', start=0.1, stop=max_angle / np.pi, length=num_points)
198
246
  _results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions)
@@ -220,3 +268,190 @@ def test_aqt_device_wrong_op_str():
220
268
  for op in circuit.all_operations():
221
269
  with pytest.raises(ValueError):
222
270
  _result = get_op_string(op)
271
+
272
+
273
+ def test_aqt_sampler_parses_legacy_json_correctly() -> None:
274
+ legacy_json = json.dumps(
275
+ [
276
+ ["R", 1.0, 0.0, [0]],
277
+ ["MS", 0.5, [0, 1]],
278
+ ["Z", -0.5, [0]],
279
+ ["R", 0.5, 1.0, [0]],
280
+ ["R", 0.5, 1.0, [1]],
281
+ ]
282
+ )
283
+
284
+ sampler = AQTSampler("default", "test", "testkey")
285
+ quantum_circuit = sampler._parse_legacy_circuit_json(legacy_json)
286
+
287
+ assert quantum_circuit == [
288
+ {"operation": "R", "phi": 0.0, "theta": 1.0, "qubit": 0},
289
+ {"operation": "RXX", "qubits": [0, 1], "theta": 0.5},
290
+ {"operation": "RZ", "qubit": 0, "phi": -0.5},
291
+ {"operation": "R", "qubit": 0, "theta": 0.5, "phi": 1.0},
292
+ {"operation": "R", "qubit": 1, "theta": 0.5, "phi": 1.0},
293
+ {"operation": "MEASURE"},
294
+ ]
295
+
296
+
297
+ def test_aqt_sampler_submits_jobs_correctly() -> None:
298
+ legacy_json = json.dumps(
299
+ [
300
+ ["R", 1.0, 0.0, [0]],
301
+ ["MS", 0.5, [0, 1]],
302
+ ["Z", -0.5, [0]],
303
+ ["R", 0.5, 1.0, [0]],
304
+ ["R", 0.5, 1.0, [1]],
305
+ ]
306
+ )
307
+
308
+ result = [[1, 1], [0, 0]]
309
+
310
+ class ResultReturn:
311
+ def json(self):
312
+ return {"response": {"status": "finished", "result": {"0": result}}}
313
+
314
+ sampler = AQTSampler("default", "test", "testkey", "http://localhost:7777/api/v1/")
315
+
316
+ with (
317
+ mock.patch('cirq_aqt.aqt_sampler.post', return_value=SubmitGoodResponse()) as submit_method,
318
+ mock.patch('cirq_aqt.aqt_sampler.get', return_value=ResultReturn()) as result_method,
319
+ ):
320
+ measurements = sampler._send_json(
321
+ json_str=legacy_json, id_str="test", repetitions=2, num_qubits=2
322
+ )
323
+
324
+ assert submit_method.call_count == 1
325
+ assert submit_method.call_args[0][0] == "http://localhost:7777/api/v1/submit/default/test"
326
+
327
+ assert result_method.call_count == 1
328
+ assert result_method.call_args[0][0] == "http://localhost:7777/api/v1/result/test_job"
329
+
330
+ for i, rep in enumerate(measurements):
331
+ for j, sample in enumerate(rep):
332
+ assert sample == result[i][j]
333
+
334
+
335
+ def test_measurement_not_at_end_is_not_allowed() -> None:
336
+ legacy_json = json.dumps([["R", 1.0, 0.0, [0]], ["Meas"], ["MS", 0.5, [0, 1]]])
337
+
338
+ sampler = AQTSampler("default", "dummy_resource", "test")
339
+ with pytest.raises(ValueError):
340
+ sampler._send_json(json_str=legacy_json, id_str="test")
341
+
342
+
343
+ def test_multiple_measurements_are_not_allowed() -> None:
344
+ legacy_json = json.dumps([["R", 1.0, 0.0, [0]], ["Meas"], ["Meas"]])
345
+
346
+ sampler = AQTSampler("default", "dummy_resource", "test")
347
+ with pytest.raises(ValueError):
348
+ sampler._send_json(json_str=legacy_json, id_str="test")
349
+
350
+
351
+ def test_unknown_gate_in_json() -> None:
352
+ legacy_json = json.dumps([["A", 1.0, 0.0, [0]], ["Meas"]])
353
+
354
+ sampler = AQTSampler("default", "dummy_resource", "test")
355
+ with pytest.raises(
356
+ ValueError, match=r"Got unknown gate on operation: \['A', 1\.0, 0\.0, \[0\]\]\."
357
+ ):
358
+ sampler._send_json(json_str=legacy_json, id_str="test")
359
+
360
+
361
+ def test_aqt_sampler_raises_exception_on_bad_result_response() -> None:
362
+ legacy_json = json.dumps([["R", 1.0, 0.0, [0]]])
363
+
364
+ class ResultReturn:
365
+ def json(self):
366
+ return {"response": {"status": "finished"}}
367
+
368
+ sampler = AQTSampler("default", "test", "testkey", "http://localhost:7777/api/v1/")
369
+
370
+ with (
371
+ mock.patch('cirq_aqt.aqt_sampler.post', return_value=SubmitGoodResponse()),
372
+ mock.patch('cirq_aqt.aqt_sampler.get', return_value=ResultReturn()),
373
+ pytest.raises(RuntimeError),
374
+ ):
375
+ sampler._send_json(json_str=legacy_json, id_str="test", repetitions=2, num_qubits=2)
376
+
377
+
378
+ def test_aqt_sampler_print_resources_shows_hint_if_no_workspaces() -> None:
379
+ output = []
380
+
381
+ def intercept(values):
382
+ output.append(str(values))
383
+
384
+ with mock.patch('cirq_aqt.aqt_sampler.AQTSampler.fetch_resources', return_value=[]):
385
+ AQTSampler.print_resources(access_token="test", emit=intercept)
386
+
387
+ assert output[0] == "No workspaces are accessible with this access token."
388
+
389
+
390
+ def test_aqt_sampler_print_resources_shows_hint_if_no_resources() -> None:
391
+ output = []
392
+
393
+ def intercept(values):
394
+ output.append(str(values))
395
+
396
+ empty_workspace_list = [{"id": "test_ws", "resources": []}]
397
+
398
+ with mock.patch(
399
+ 'cirq_aqt.aqt_sampler.AQTSampler.fetch_resources', return_value=empty_workspace_list
400
+ ):
401
+ AQTSampler.print_resources("test", emit=intercept)
402
+
403
+ assert output[0] == "No workspaces accessible with this access token contain resources."
404
+
405
+
406
+ def test_aqt_sampler_print_resources_includes_received_resources_in_table() -> None:
407
+ output = []
408
+
409
+ def intercept(values):
410
+ output.append(str(values))
411
+
412
+ workspace_list = [
413
+ {"id": "test_ws", "resources": [{"id": "resource", "name": "Resource", "type": "device"}]}
414
+ ]
415
+
416
+ with mock.patch('cirq_aqt.aqt_sampler.AQTSampler.fetch_resources', return_value=workspace_list):
417
+ AQTSampler.print_resources("test", emit=intercept)
418
+
419
+ assert any("test_ws" in o and "resource" in o and "Resource" in o and "D" in o for o in output)
420
+
421
+
422
+ def test_aqt_sampler_fetch_resources_raises_exception_if_non_200_status_code() -> None:
423
+ class ResourceResponse:
424
+ def __init__(self):
425
+ self.status_code = 403
426
+
427
+ def json(self):
428
+ return "error"
429
+
430
+ sampler = AQTSampler("default", "test", "testkey", "http://localhost:7777/api/v1/")
431
+
432
+ with (
433
+ mock.patch('cirq_aqt.aqt_sampler.get', return_value=ResourceResponse()),
434
+ pytest.raises(RuntimeError),
435
+ ):
436
+ sampler.fetch_resources("token")
437
+
438
+
439
+ def test_aqt_sampler_fetch_resources_returns_retrieved_resources() -> None:
440
+ class ResourceResponse:
441
+ def __init__(self):
442
+ self.status_code = 200
443
+
444
+ def json(self):
445
+ return [
446
+ {"id": "wid", "resources": [{"id": "rid", "name": "Resource", "type": "device"}]}
447
+ ]
448
+
449
+ sampler = AQTSampler("default", "test", "testkey", "http://localhost:7777/api/v1/")
450
+
451
+ with mock.patch('cirq_aqt.aqt_sampler.get', return_value=ResourceResponse()):
452
+ workspaces = sampler.fetch_resources("token")
453
+
454
+ assert workspaces[0]["id"] == "wid"
455
+ assert workspaces[0]["resources"][0]["id"] == "rid"
456
+ assert workspaces[0]["resources"][0]["name"] == "Resource"
457
+ assert workspaces[0]["resources"][0]["type"] == "device"
@@ -44,21 +44,3 @@ def test_ms_crosstalk_n_noise():
44
44
  (cirq.XX**0.015).on(cirq.LineQubit(2), cirq.LineQubit(0)),
45
45
  (cirq.XX**0.015).on(cirq.LineQubit(2), cirq.LineQubit(3)),
46
46
  ]
47
-
48
-
49
- def test_x_crosstalk_n_noise():
50
- num_qubits = 4
51
- noise_mod = AQTNoiseModel()
52
- _, qubits = get_aqt_device(num_qubits)
53
- circuit = cirq.Circuit()
54
- circuit.append(cirq.Y(qubits[1]) ** 0.5)
55
- circuit.append(cirq.Z(qubits[1]) ** 0.5)
56
- circuit.append(cirq.X(qubits[1]) ** 0.5)
57
- for moment in circuit.moments:
58
- noisy_moment = noise_mod.noisy_moment(moment, qubits)
59
- assert noisy_moment == [
60
- (cirq.X**0.5).on(cirq.LineQubit(1)),
61
- cirq.depolarize(p=0.001).on(cirq.LineQubit(1)),
62
- (cirq.X**0.015).on(cirq.LineQubit(0)),
63
- (cirq.X**0.015).on(cirq.LineQubit(2)),
64
- ]
@@ -30,8 +30,7 @@ class AQTTargetGateset(cirq.TwoQubitCompilationTargetGateset):
30
30
  gates to the following universal target gateset:
31
31
 
32
32
  - `cirq.XXPowGate`: The two qubit entangling gate.
33
- - `cirq.XPowGate`, `cirq.YPowGate`, `cirq.ZPowGate`,
34
- `cirq.PhasedXPowGate`: Single qubit rotations.
33
+ - `cirq.ZPowGate`, `cirq.PhasedXPowGate`: Single qubit rotations.
35
34
  - `cirq.MeasurementGate`: Measurements.
36
35
  """
37
36
 
@@ -39,8 +38,6 @@ class AQTTargetGateset(cirq.TwoQubitCompilationTargetGateset):
39
38
  super().__init__(
40
39
  cirq.XXPowGate,
41
40
  cirq.MeasurementGate,
42
- cirq.XPowGate,
43
- cirq.YPowGate,
44
41
  cirq.ZPowGate,
45
42
  cirq.PhasedXPowGate,
46
43
  unroll_circuit_op=False,
@@ -31,8 +31,8 @@ Q, Q2, Q3, Q4 = cirq.LineQubit.range(4)
31
31
  (cirq.HPowGate(exponent=0.5)(Q), False),
32
32
  (cirq.XX(Q, Q2), True),
33
33
  (cirq.measure(Q), True),
34
- (cirq.XPowGate(exponent=0.5)(Q), True),
35
- (cirq.YPowGate(exponent=0.25)(Q), True),
34
+ (cirq.XPowGate(exponent=0.5)(Q), False),
35
+ (cirq.YPowGate(exponent=0.25)(Q), False),
36
36
  (cirq.ZPowGate(exponent=0.125)(Q), True),
37
37
  (cirq.PhasedXPowGate(exponent=0.25, phase_exponent=0.125)(Q), True),
38
38
  (cirq.CZPowGate(exponent=0.5)(Q, Q2), False),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cirq-aqt
3
- Version: 1.4.0.dev20240415214855
3
+ Version: 1.4.0.dev20240419073809
4
4
  Summary: A Cirq package to simulate and connect to Alpine Quantum Technologies quantum computers
5
5
  Home-page: http://github.com/quantumlib/cirq
6
6
  Author: The Cirq Developers
@@ -9,7 +9,7 @@ License: Apache 2
9
9
  Requires-Python: >=3.9.0
10
10
  License-File: LICENSE
11
11
  Requires-Dist: requests ~=2.18
12
- Requires-Dist: cirq-core ==1.4.0.dev20240415214855
12
+ Requires-Dist: cirq-core ==1.4.0.dev20240419073809
13
13
 
14
14
  **This is a development version of Cirq-AQT and may be unstable.**
15
15
 
@@ -0,0 +1,21 @@
1
+ cirq_aqt/__init__.py,sha256=2uufR12R3crUqeeDqMrA3rvsPqZuSNYysVLVvdpQzFk,803
2
+ cirq_aqt/_version.py,sha256=VLMyoKgtktjsOU359gwigM2OxEruVVvbeMGm1irygRs,40
3
+ cirq_aqt/_version_test.py,sha256=b1Lhv0twYyu-3pKzJygENb3Uy57KwZXQoctswTiRJSg,141
4
+ cirq_aqt/aqt_device.py,sha256=48OblqJDD0R7xuwRHxHMcP3yxeTbGc5gSfWHZM9LE0Y,13654
5
+ cirq_aqt/aqt_device_metadata.py,sha256=vdYGf3gdZNJEIttlYNutdXGh9qz-93vNzLrail6ujYc,4779
6
+ cirq_aqt/aqt_device_metadata_test.py,sha256=naTXEU4VCCdR__gBlzbWjR0-DzViZ1xgVrH_GAyjskY,2111
7
+ cirq_aqt/aqt_device_test.py,sha256=eYHT1DIt3EI_4e-rSROiUw5_E4A9Bjt8tIchvUrKnxs,5210
8
+ cirq_aqt/aqt_sampler.py,sha256=GKkbF1iEuseDui9fDR6stJSrwQcssX4DTTeUhzFdezg,18379
9
+ cirq_aqt/aqt_sampler_test.py,sha256=EspGPtmOs6WJUEOZEjCGcbUANawPyOWAFL3ozsFiu7Y,16402
10
+ cirq_aqt/aqt_simulator_test.py,sha256=LSRyNSnme3A1l5eyDC79MzJLKZNoKa3LdsN_NoKMPTE,1673
11
+ cirq_aqt/aqt_target_gateset.py,sha256=1hvaHH5zSz292qgMxE7MQJxngytpUAH2nEj5Ob9e8CI,2779
12
+ cirq_aqt/aqt_target_gateset_test.py,sha256=wILzfJ3uWTzs-9R93I_qReZoWER-TaBhVr1lG3zl1WU,3336
13
+ cirq_aqt/conftest.py,sha256=2-K0ZniZ28adwVNB-f5IqvYjavKEBwC4jes_WQ17Xzg,667
14
+ cirq_aqt/json_resolver_cache.py,sha256=oZUTckLvATBDSrn-Y6kEAjHjiGXtKc-Bz_i23WsxFj8,788
15
+ cirq_aqt/json_test_data/__init__.py,sha256=K0c9IduIrV7xvSXoc0yJVz5T-ITed3VKlssTN8XYq9w,892
16
+ cirq_aqt/json_test_data/spec.py,sha256=RMp340PqpXN2iFQClZzTcXrKDVMKa_OLcXQ8qn2mPsw,1051
17
+ cirq_aqt-1.4.0.dev20240419073809.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
18
+ cirq_aqt-1.4.0.dev20240419073809.dist-info/METADATA,sha256=waZ2q8mAIG3NIYIIoifxfHyLzhBLyerAL0qg_S_krJs,1789
19
+ cirq_aqt-1.4.0.dev20240419073809.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
20
+ cirq_aqt-1.4.0.dev20240419073809.dist-info/top_level.txt,sha256=culYyFTEtuC3Z7wT3wZ6kGVspH3hYFZUEKooByfe9h0,9
21
+ cirq_aqt-1.4.0.dev20240419073809.dist-info/RECORD,,
@@ -1,21 +0,0 @@
1
- cirq_aqt/__init__.py,sha256=2uufR12R3crUqeeDqMrA3rvsPqZuSNYysVLVvdpQzFk,803
2
- cirq_aqt/_version.py,sha256=iiKeRvFg2OmKbbnJRlID0KjT_MhK9l6wa0R7fi7oTtY,40
3
- cirq_aqt/_version_test.py,sha256=b1Lhv0twYyu-3pKzJygENb3Uy57KwZXQoctswTiRJSg,141
4
- cirq_aqt/aqt_device.py,sha256=RIjNlZzB4cZkNKHytKRe-HHT2y85Fwtbr51fiD5AguY,13327
5
- cirq_aqt/aqt_device_metadata.py,sha256=l8TtJtbxe1g99lygxVg5Njrn_mvnhxlvi0eZaptuuQI,4921
6
- cirq_aqt/aqt_device_metadata_test.py,sha256=CJ7XAvvogUSJPfduq5GDZp9t-nZaIZGaRqRexeUmHlg,2111
7
- cirq_aqt/aqt_device_test.py,sha256=eYHT1DIt3EI_4e-rSROiUw5_E4A9Bjt8tIchvUrKnxs,5210
8
- cirq_aqt/aqt_sampler.py,sha256=9Iuam2RXcWW0uHha0eZETotJdiIrnC1gx9oNwUEPzfw,9738
9
- cirq_aqt/aqt_sampler_test.py,sha256=0pYnqZikTySM1Yjr1IWoryGlIa_H54Dhq1e19poaaOg,7446
10
- cirq_aqt/aqt_simulator_test.py,sha256=ZRW04CtQduqYfoEsxEKNa04CdTAr987xMhck-KGUIm0,2292
11
- cirq_aqt/aqt_target_gateset.py,sha256=2HjfnCgJ2MaKITjvXqpej7Y2DVQEm7n7RAklanUKDWo,2873
12
- cirq_aqt/aqt_target_gateset_test.py,sha256=dnwyv74JmnU3G0OX9-RS-KuEyxTmx9JQ9SbHS1pBmRE,3334
13
- cirq_aqt/conftest.py,sha256=2-K0ZniZ28adwVNB-f5IqvYjavKEBwC4jes_WQ17Xzg,667
14
- cirq_aqt/json_resolver_cache.py,sha256=oZUTckLvATBDSrn-Y6kEAjHjiGXtKc-Bz_i23WsxFj8,788
15
- cirq_aqt/json_test_data/__init__.py,sha256=K0c9IduIrV7xvSXoc0yJVz5T-ITed3VKlssTN8XYq9w,892
16
- cirq_aqt/json_test_data/spec.py,sha256=RMp340PqpXN2iFQClZzTcXrKDVMKa_OLcXQ8qn2mPsw,1051
17
- cirq_aqt-1.4.0.dev20240415214855.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
18
- cirq_aqt-1.4.0.dev20240415214855.dist-info/METADATA,sha256=mTLxM84c2q1OcYhipAHKnl_E6IaaE1B78fPJE53QfIE,1789
19
- cirq_aqt-1.4.0.dev20240415214855.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
20
- cirq_aqt-1.4.0.dev20240415214855.dist-info/top_level.txt,sha256=culYyFTEtuC3Z7wT3wZ6kGVspH3hYFZUEKooByfe9h0,9
21
- cirq_aqt-1.4.0.dev20240415214855.dist-info/RECORD,,