cirq-core 1.5.0.dev20250116193042__py3-none-any.whl → 1.5.0.dev20250117150435__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.

Potentially problematic release.


This version of cirq-core might be problematic. Click here for more details.

cirq/_version.py CHANGED
@@ -28,4 +28,4 @@ if sys.version_info < (3, 10, 0): # pragma: no cover
28
28
  'of cirq (e.g. "python -m pip install cirq==1.1.*")'
29
29
  )
30
30
 
31
- __version__ = "1.5.0.dev20250116193042"
31
+ __version__ = "1.5.0.dev20250117150435"
cirq/_version_test.py CHANGED
@@ -3,4 +3,4 @@ import cirq
3
3
 
4
4
 
5
5
  def test_version():
6
- assert cirq.__version__ == "1.5.0.dev20250116193042"
6
+ assert cirq.__version__ == "1.5.0.dev20250117150435"
@@ -366,10 +366,10 @@ class QasmOutput:
366
366
  if should_annotate:
367
367
  output_line_gap(1)
368
368
  if isinstance(main_op, ops.GateOperation):
369
- x = str(main_op.gate).replace('\n', '\n //')
369
+ x = str(main_op.gate).replace('\n', '\n// ')
370
370
  output(f'// Gate: {x!s}\n')
371
371
  else:
372
- x = str(main_op).replace('\n', '\n //')
372
+ x = str(main_op).replace('\n', '\n// ')
373
373
  output(f'// Operation: {x!s}\n')
374
374
 
375
375
  for qasm in qasms:
@@ -33,6 +33,7 @@ class QasmLexer:
33
33
  'creg': 'CREG',
34
34
  'measure': 'MEASURE',
35
35
  'reset': 'RESET',
36
+ 'gate': 'GATE',
36
37
  'if': 'IF',
37
38
  '->': 'ARROW',
38
39
  '==': 'EQ',
@@ -120,6 +121,10 @@ class QasmLexer:
120
121
  r"""reset"""
121
122
  return t
122
123
 
124
+ def t_GATE(self, t):
125
+ r"""gate"""
126
+ return t
127
+
123
128
  def t_IF(self, t):
124
129
  r"""if"""
125
130
  return t
@@ -159,6 +159,74 @@ def test_creg():
159
159
  assert token.value == ";"
160
160
 
161
161
 
162
+ def test_custom_gate():
163
+ lexer = QasmLexer()
164
+ lexer.input('gate name(param1,param2) q1, q2 {X(q1)}')
165
+ token = lexer.token()
166
+ assert token.type == "GATE"
167
+ assert token.value == "gate"
168
+
169
+ token = lexer.token()
170
+ assert token.type == "ID"
171
+ assert token.value == "name"
172
+
173
+ token = lexer.token()
174
+ assert token.type == "("
175
+ assert token.value == "("
176
+
177
+ token = lexer.token()
178
+ assert token.type == "ID"
179
+ assert token.value == "param1"
180
+
181
+ token = lexer.token()
182
+ assert token.type == ","
183
+ assert token.value == ","
184
+
185
+ token = lexer.token()
186
+ assert token.type == "ID"
187
+ assert token.value == "param2"
188
+
189
+ token = lexer.token()
190
+ assert token.type == ")"
191
+ assert token.value == ")"
192
+
193
+ token = lexer.token()
194
+ assert token.type == "ID"
195
+ assert token.value == "q1"
196
+
197
+ token = lexer.token()
198
+ assert token.type == ","
199
+ assert token.value == ","
200
+
201
+ token = lexer.token()
202
+ assert token.type == "ID"
203
+ assert token.value == "q2"
204
+
205
+ token = lexer.token()
206
+ assert token.type == "{"
207
+ assert token.value == "{"
208
+
209
+ token = lexer.token()
210
+ assert token.type == "ID"
211
+ assert token.value == "X"
212
+
213
+ token = lexer.token()
214
+ assert token.type == "("
215
+ assert token.value == "("
216
+
217
+ token = lexer.token()
218
+ assert token.type == "ID"
219
+ assert token.value == "q1"
220
+
221
+ token = lexer.token()
222
+ assert token.type == ")"
223
+ assert token.value == ")"
224
+
225
+ token = lexer.token()
226
+ assert token.type == "}"
227
+ assert token.value == "}"
228
+
229
+
162
230
  def test_error():
163
231
  lexer = QasmLexer()
164
232
  lexer.input('θ')
@@ -12,15 +12,28 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import dataclasses
15
16
  import functools
16
17
  import operator
17
- from typing import Any, Callable, cast, Dict, Iterable, List, Optional, Union, TYPE_CHECKING
18
+ from typing import (
19
+ Any,
20
+ Callable,
21
+ cast,
22
+ Dict,
23
+ Iterable,
24
+ List,
25
+ Optional,
26
+ Set,
27
+ Tuple,
28
+ Union,
29
+ TYPE_CHECKING,
30
+ )
18
31
 
19
32
  import numpy as np
20
33
  import sympy
21
34
  from ply import yacc
22
35
 
23
- from cirq import ops, Circuit, NamedQubit, CX
36
+ from cirq import ops, value, Circuit, CircuitOperation, CX, FrozenCircuit, NamedQubit
24
37
  from cirq.circuits.qasm_output import QasmUGate
25
38
  from cirq.contrib.qasm_import._lexer import QasmLexer
26
39
  from cirq.contrib.qasm_import.exception import QasmException
@@ -47,6 +60,31 @@ class Qasm:
47
60
  self.circuit = c
48
61
 
49
62
 
63
+ def _generate_op_qubits(args: List[List[ops.Qid]], lineno: int) -> List[List[ops.Qid]]:
64
+ """Generates the Cirq qubits for an operation from the OpenQASM qregs.
65
+
66
+ OpenQASM gates can be applied on single qubits and qubit registers.
67
+ We represent single qubits as registers of size 1.
68
+ Based on the OpenQASM spec (https://arxiv.org/abs/1707.03429),
69
+ single qubit arguments can be mixed with qubit registers.
70
+ Given quantum registers of length reg_size and single qubits are both
71
+ used as arguments, we generate reg_size GateOperations via iterating
72
+ through each qubit of the registers 0 to n-1 and use the same one
73
+ qubit from the "single-qubit registers" for each operation."""
74
+ reg_sizes = np.unique([len(reg) for reg in args])
75
+ if len(reg_sizes) > 2 or (len(reg_sizes) > 1 and reg_sizes[0] != 1):
76
+ raise QasmException(
77
+ f"Non matching quantum registers of length {reg_sizes} at line {lineno}"
78
+ )
79
+ op_qubits_gen = functools.reduce(
80
+ cast(Callable[[List['cirq.Qid'], List['cirq.Qid']], List['cirq.Qid']], np.broadcast), args
81
+ )
82
+ op_qubits = [[q] if isinstance(q, ops.Qid) else q for q in op_qubits_gen]
83
+ if any(len(set(q)) < len(q) for q in op_qubits):
84
+ raise QasmException(f"Overlapping qubits in arguments at line {lineno}")
85
+ return op_qubits
86
+
87
+
50
88
  class QasmGateStatement:
51
89
  """Specifies how to convert a call to an OpenQASM gate
52
90
  to a list of `cirq.GateOperation`s.
@@ -87,7 +125,7 @@ class QasmGateStatement:
87
125
  f"got: {len(args)}, at line {lineno}"
88
126
  )
89
127
 
90
- def _validate_params(self, params: List[float], lineno: int):
128
+ def _validate_params(self, params: List[value.TParamVal], lineno: int):
91
129
  if len(params) != self.num_params:
92
130
  raise QasmException(
93
131
  f"{self.qasm_gate} takes {self.num_params} parameter(s), "
@@ -95,41 +133,47 @@ class QasmGateStatement:
95
133
  )
96
134
 
97
135
  def on(
98
- self, params: List[float], args: List[List[ops.Qid]], lineno: int
136
+ self, params: List[value.TParamVal], args: List[List[ops.Qid]], lineno: int
99
137
  ) -> Iterable[ops.Operation]:
100
138
  self._validate_args(args, lineno)
101
139
  self._validate_params(params, lineno)
102
140
 
103
- reg_sizes = np.unique([len(reg) for reg in args])
104
- if len(reg_sizes) > 2 or (len(reg_sizes) > 1 and reg_sizes[0] != 1):
105
- raise QasmException(
106
- f"Non matching quantum registers of length {reg_sizes} at line {lineno}"
107
- )
108
-
109
141
  # the actual gate we'll apply the arguments to might be a parameterized
110
142
  # or non-parameterized gate
111
143
  final_gate: ops.Gate = (
112
144
  self.cirq_gate if isinstance(self.cirq_gate, ops.Gate) else self.cirq_gate(params)
113
145
  )
114
- # OpenQASM gates can be applied on single qubits and qubit registers.
115
- # We represent single qubits as registers of size 1.
116
- # Based on the OpenQASM spec (https://arxiv.org/abs/1707.03429),
117
- # single qubit arguments can be mixed with qubit registers.
118
- # Given quantum registers of length reg_size and single qubits are both
119
- # used as arguments, we generate reg_size GateOperations via iterating
120
- # through each qubit of the registers 0 to n-1 and use the same one
121
- # qubit from the "single-qubit registers" for each operation.
122
- op_qubits = functools.reduce(
123
- cast(Callable[[List['cirq.Qid'], List['cirq.Qid']], List['cirq.Qid']], np.broadcast),
124
- args,
125
- )
126
- for qubits in op_qubits:
127
- if isinstance(qubits, ops.Qid):
128
- yield final_gate.on(qubits)
129
- elif len(np.unique(qubits)) < len(qubits):
130
- raise QasmException(f"Overlapping qubits in arguments at line {lineno}")
131
- else:
132
- yield final_gate.on(*qubits)
146
+ for qubits in _generate_op_qubits(args, lineno):
147
+ yield final_gate.on(*qubits)
148
+
149
+
150
+ @dataclasses.dataclass
151
+ class CustomGate:
152
+ """Represents an invocation of a user-defined gate.
153
+
154
+ The custom gate definition is encoded here as a `FrozenCircuit`, and the
155
+ arguments (params and qubits) of the specific invocation of that gate are
156
+ stored here too. When `on` is called, we create a CircuitOperation, mapping
157
+ the qubits and params to the values provided."""
158
+
159
+ name: str
160
+ circuit: FrozenCircuit
161
+ params: Tuple[str, ...]
162
+ qubits: Tuple[ops.Qid, ...]
163
+
164
+ def on(
165
+ self, params: List[value.TParamVal], args: List[List[ops.Qid]], lineno: int
166
+ ) -> Iterable[ops.Operation]:
167
+ if len(params) != len(self.params):
168
+ raise QasmException(f"Wrong number of params for '{self.name}' at line {lineno}")
169
+ if len(args) != len(self.qubits):
170
+ raise QasmException(f"Wrong number of qregs for '{self.name}' at line {lineno}")
171
+ for qubits in _generate_op_qubits(args, lineno):
172
+ yield CircuitOperation(
173
+ self.circuit,
174
+ param_resolver={k: v for k, v in zip(self.params, params)},
175
+ qubit_map={k: v for k, v in zip(self.qubits, qubits)},
176
+ )
133
177
 
134
178
 
135
179
  class QasmParser:
@@ -146,6 +190,18 @@ class QasmParser:
146
190
  self.circuit = Circuit()
147
191
  self.qregs: Dict[str, int] = {}
148
192
  self.cregs: Dict[str, int] = {}
193
+ self.gate_set: Dict[str, Union[CustomGate, QasmGateStatement]] = {**self.basic_gates}
194
+ """The gates available to use in the circuit, including those from libraries, and
195
+ user-defined ones."""
196
+ self.in_custom_gate_scope = False
197
+ """This is set to True when the parser is in the middle of parsing a custom gate
198
+ definition."""
199
+ self.custom_gate_scoped_params: Set[str] = set()
200
+ """The params declared within the current custom gate definition. Empty if not in
201
+ custom gate scope."""
202
+ self.custom_gate_scoped_qubits: Dict[str, ops.Qid] = {}
203
+ """The qubits declared within the current custom gate definition. Empty if not in
204
+ custom gate scope."""
149
205
  self.qelibinc = False
150
206
  self.lexer = QasmLexer()
151
207
  self.supported_format = False
@@ -270,8 +326,6 @@ class QasmParser:
270
326
  'tdg': QasmGateStatement(qasm_gate='tdg', num_params=0, num_args=1, cirq_gate=ops.T**-1),
271
327
  }
272
328
 
273
- all_gates = {**basic_gates, **qelib_gates}
274
-
275
329
  tokens = QasmLexer.tokens
276
330
  start = 'start'
277
331
 
@@ -296,11 +350,13 @@ class QasmParser:
296
350
  def p_qasm_include(self, p):
297
351
  """qasm : qasm QELIBINC"""
298
352
  self.qelibinc = True
353
+ self.gate_set |= self.qelib_gates
299
354
  p[0] = Qasm(self.supported_format, self.qelibinc, self.qregs, self.cregs, self.circuit)
300
355
 
301
356
  def p_qasm_include_stdgates(self, p):
302
357
  """qasm : qasm STDGATESINC"""
303
358
  self.qelibinc = True
359
+ self.gate_set |= self.qelib_gates
304
360
  p[0] = Qasm(self.supported_format, self.qelibinc, self.qregs, self.cregs, self.circuit)
305
361
 
306
362
  def p_qasm_circuit(self, p):
@@ -338,6 +394,10 @@ class QasmParser:
338
394
  """circuit : empty"""
339
395
  p[0] = self.circuit
340
396
 
397
+ def p_circuit_gate_def(self, p):
398
+ """circuit : gate_def"""
399
+ p[0] = self.circuit
400
+
341
401
  # qreg and creg
342
402
 
343
403
  def p_new_reg(self, p):
@@ -382,14 +442,13 @@ class QasmParser:
382
442
  self._resolve_gate_operation(args=p[5], gate=p[1], p=p, params=p[3])
383
443
 
384
444
  def _resolve_gate_operation(
385
- self, args: List[List[ops.Qid]], gate: str, p: Any, params: List[float]
445
+ self, args: List[List[ops.Qid]], gate: str, p: Any, params: List[value.TParamVal]
386
446
  ):
387
- gate_set = self.basic_gates if not self.qelibinc else self.all_gates
388
- if gate not in gate_set.keys():
447
+ if gate not in self.gate_set:
389
448
  tip = ", did you forget to include qelib1.inc?" if not self.qelibinc else ""
390
449
  msg = f'Unknown gate "{gate}" at line {p.lineno(1)}{tip}'
391
450
  raise QasmException(msg)
392
- p[0] = gate_set[gate].on(args=args, params=params, lineno=p.lineno(1))
451
+ p[0] = self.gate_set[gate].on(args=args, params=params, lineno=p.lineno(1))
393
452
 
394
453
  # params : parameter ',' params
395
454
  # | parameter
@@ -404,7 +463,8 @@ class QasmParser:
404
463
  p[0] = [p[1]]
405
464
 
406
465
  # expr : term
407
- # | func '(' expression ')' """
466
+ # | ID
467
+ # | func '(' expression ')'
408
468
  # | binary_op
409
469
  # | unary_op
410
470
 
@@ -412,6 +472,14 @@ class QasmParser:
412
472
  """expr : term"""
413
473
  p[0] = p[1]
414
474
 
475
+ def p_expr_identifier(self, p):
476
+ """expr : ID"""
477
+ if not self.in_custom_gate_scope:
478
+ raise QasmException(f"Parameter '{p[1]}' in line {p.lineno(1)} not supported")
479
+ if p[1] not in self.custom_gate_scoped_params:
480
+ raise QasmException(f"Undefined parameter '{p[1]}' in line {p.lineno(1)}'")
481
+ p[0] = sympy.Symbol(p[1])
482
+
415
483
  def p_expr_parens(self, p):
416
484
  """expr : '(' expr ')'"""
417
485
  p[0] = p[2]
@@ -464,6 +532,15 @@ class QasmParser:
464
532
  def p_quantum_arg_register(self, p):
465
533
  """qarg : ID"""
466
534
  reg = p[1]
535
+ if self.in_custom_gate_scope:
536
+ if reg not in self.custom_gate_scoped_qubits:
537
+ if reg not in self.qregs:
538
+ msg = f"Undefined qubit '{reg}'"
539
+ else:
540
+ msg = f"'{reg}' is a register, not a qubit"
541
+ raise QasmException(f"{msg} at line {p.lineno(1)}")
542
+ p[0] = [self.custom_gate_scoped_qubits[reg]]
543
+ return
467
544
  if reg not in self.qregs.keys():
468
545
  raise QasmException(f'Undefined quantum register "{reg}" at line {p.lineno(1)}')
469
546
  qubits = []
@@ -492,6 +569,8 @@ class QasmParser:
492
569
  """qarg : ID '[' NATURAL_NUMBER ']'"""
493
570
  reg = p[1]
494
571
  idx = p[3]
572
+ if self.in_custom_gate_scope:
573
+ raise QasmException(f"Unsupported indexed qreg '{reg}[{idx}]' at line {p.lineno(1)}")
495
574
  arg_name = self.make_name(idx, reg)
496
575
  if reg not in self.qregs.keys():
497
576
  raise QasmException(f'Undefined quantum register "{reg}" at line {p.lineno(1)}')
@@ -570,6 +649,60 @@ class QasmParser:
570
649
  ops.ClassicallyControlledOperation(conditions=conditions, sub_operation=tuple(p[7])[0])
571
650
  ]
572
651
 
652
+ def p_gate_params_multiple(self, p):
653
+ """gate_params : ID ',' gate_params"""
654
+ self.p_gate_params_single(p)
655
+ p[0] += p[3]
656
+
657
+ def p_gate_params_single(self, p):
658
+ """gate_params : ID"""
659
+ self.in_custom_gate_scope = True
660
+ self.custom_gate_scoped_params.add(p[1])
661
+ p[0] = [p[1]]
662
+
663
+ def p_gate_qubits_multiple(self, p):
664
+ """gate_qubits : ID ',' gate_qubits"""
665
+ self.p_gate_qubits_single(p)
666
+ p[0] += p[3]
667
+
668
+ def p_gate_qubits_single(self, p):
669
+ """gate_qubits : ID"""
670
+ self.in_custom_gate_scope = True
671
+ q = NamedQubit(p[1])
672
+ self.custom_gate_scoped_qubits[p[1]] = q
673
+ p[0] = [q]
674
+
675
+ def p_gate_ops(self, p):
676
+ """gate_ops : gate_op gate_ops"""
677
+ p[0] = [p[1]] + p[2]
678
+
679
+ def p_gate_ops_empty(self, p):
680
+ """gate_ops : empty"""
681
+ self.in_custom_gate_scope = True
682
+ p[0] = []
683
+
684
+ def p_gate_def_parameterized(self, p):
685
+ """gate_def : GATE ID '(' gate_params ')' gate_qubits '{' gate_ops '}'"""
686
+ self._gate_def(p, has_params=True)
687
+
688
+ def p_gate_def(self, p):
689
+ """gate_def : GATE ID gate_qubits '{' gate_ops '}'"""
690
+ self._gate_def(p, has_params=False)
691
+
692
+ def _gate_def(self, p: List[Any], *, has_params: bool):
693
+ name = p[2]
694
+ gate_params = tuple(p[4]) if has_params else ()
695
+ offset = 3 if has_params else 0
696
+ gate_qubits = tuple(p[3 + offset])
697
+ gate_ops = p[5 + offset]
698
+ circuit = Circuit(gate_ops).freeze()
699
+ gate_def = CustomGate(name, circuit, gate_params, gate_qubits)
700
+ self.gate_set[name] = gate_def
701
+ self.custom_gate_scoped_params.clear()
702
+ self.custom_gate_scoped_qubits.clear()
703
+ self.in_custom_gate_scope = False
704
+ p[0] = gate_def
705
+
573
706
  def p_error(self, p):
574
707
  if p is None:
575
708
  raise QasmException('Unexpected end of file')
@@ -12,16 +12,18 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import re
15
16
  import textwrap
17
+ import warnings
16
18
  from typing import Callable
17
19
 
18
20
  import numpy as np
19
21
  import pytest
20
22
  import sympy
21
23
 
22
-
23
24
  import cirq
24
25
  import cirq.testing as ct
26
+ from cirq.testing import consistent_qasm as cq
25
27
  from cirq import Circuit
26
28
  from cirq.circuits.qasm_output import QasmUGate
27
29
  from cirq.contrib.qasm_import import QasmException
@@ -186,7 +188,7 @@ def test_CX_gate():
186
188
  qreg q2[2];
187
189
  CX q1[0], q1[1];
188
190
  CX q1, q2[0];
189
- CX q2, q1;
191
+ CX q2, q1;
190
192
  """
191
193
  parser = QasmParser()
192
194
 
@@ -390,7 +392,7 @@ def test_U_angles():
390
392
 
391
393
  def test_U_gate_zero_params_error():
392
394
  qasm = """OPENQASM 2.0;
393
- qreg q[2];
395
+ qreg q[2];
394
396
  U q[1];"""
395
397
 
396
398
  parser = QasmParser()
@@ -401,7 +403,7 @@ def test_U_gate_zero_params_error():
401
403
 
402
404
  def test_U_gate_too_much_params_error():
403
405
  qasm = """OPENQASM 2.0;
404
- qreg q[2];
406
+ qreg q[2];
405
407
  U(pi, pi, pi, pi) q[1];"""
406
408
 
407
409
  parser = QasmParser()
@@ -520,9 +522,9 @@ def test_rotation_gates(qasm_gate: str, cirq_gate: Callable[[float], cirq.Gate])
520
522
  def test_rotation_gates_wrong_number_of_args(qasm_gate: str):
521
523
  qasm = f"""
522
524
  OPENQASM 2.0;
523
- include "qelib1.inc";
524
- qreg q[2];
525
- {qasm_gate}(pi) q[0], q[1];
525
+ include "qelib1.inc";
526
+ qreg q[2];
527
+ {qasm_gate}(pi) q[0], q[1];
526
528
  """
527
529
 
528
530
  parser = QasmParser()
@@ -534,9 +536,9 @@ def test_rotation_gates_wrong_number_of_args(qasm_gate: str):
534
536
  @pytest.mark.parametrize('qasm_gate', [g[0] for g in rotation_gates])
535
537
  def test_rotation_gates_zero_params_error(qasm_gate: str):
536
538
  qasm = f"""OPENQASM 2.0;
537
- include "qelib1.inc";
538
- qreg q[2];
539
- {qasm_gate} q[1];
539
+ include "qelib1.inc";
540
+ qreg q[2];
541
+ {qasm_gate} q[1];
540
542
  """
541
543
 
542
544
  parser = QasmParser()
@@ -584,7 +586,7 @@ def test_measure_individual_bits():
584
586
  OPENQASM 2.0;
585
587
  include "qelib1.inc";
586
588
  qreg q1[2];
587
- creg c1[2];
589
+ creg c1[2];
588
590
  measure q1[0] -> c1[0];
589
591
  measure q1[1] -> c1[1];
590
592
  """
@@ -612,8 +614,8 @@ def test_measure_registers():
612
614
  qasm = """OPENQASM 2.0;
613
615
  include "qelib1.inc";
614
616
  qreg q1[3];
615
- creg c1[3];
616
- measure q1 -> c1;
617
+ creg c1[3];
618
+ measure q1 -> c1;
617
619
  """
618
620
  parser = QasmParser()
619
621
 
@@ -639,10 +641,10 @@ def test_measure_registers():
639
641
 
640
642
  def test_measure_mismatched_register_size():
641
643
  qasm = """OPENQASM 2.0;
642
- include "qelib1.inc";
644
+ include "qelib1.inc";
643
645
  qreg q1[2];
644
- creg c1[3];
645
- measure q1 -> c1;
646
+ creg c1[3];
647
+ measure q1 -> c1;
646
648
  """
647
649
 
648
650
  parser = QasmParser()
@@ -653,11 +655,11 @@ def test_measure_mismatched_register_size():
653
655
 
654
656
  def test_measure_to_quantum_register():
655
657
  qasm = """OPENQASM 2.0;
656
- include "qelib1.inc";
658
+ include "qelib1.inc";
657
659
  qreg q1[3];
658
660
  qreg q2[3];
659
- creg c1[3];
660
- measure q2 -> q1;
661
+ creg c1[3];
662
+ measure q2 -> q1;
661
663
  """
662
664
 
663
665
  parser = QasmParser()
@@ -668,10 +670,10 @@ def test_measure_to_quantum_register():
668
670
 
669
671
  def test_measure_undefined_classical_bit():
670
672
  qasm = """OPENQASM 2.0;
671
- include "qelib1.inc";
672
- qreg q1[3];
673
- creg c1[3];
674
- measure q1[1] -> c2[1];
673
+ include "qelib1.inc";
674
+ qreg q1[3];
675
+ creg c1[3];
676
+ measure q1[1] -> c2[1];
675
677
  """
676
678
 
677
679
  parser = QasmParser()
@@ -682,11 +684,11 @@ def test_measure_undefined_classical_bit():
682
684
 
683
685
  def test_measure_from_classical_register():
684
686
  qasm = """OPENQASM 2.0;
685
- include "qelib1.inc";
687
+ include "qelib1.inc";
686
688
  qreg q1[2];
687
- creg c1[3];
688
- creg c2[3];
689
- measure c1 -> c2;
689
+ creg c1[3];
690
+ creg c2[3];
691
+ measure c1 -> c2;
690
692
  """
691
693
 
692
694
  parser = QasmParser()
@@ -698,8 +700,8 @@ def test_measure_from_classical_register():
698
700
  def test_measurement_bounds():
699
701
  qasm = """OPENQASM 2.0;
700
702
  qreg q1[3];
701
- creg c1[3];
702
- measure q1[0] -> c1[4];
703
+ creg c1[3];
704
+ measure q1[0] -> c1[4];
703
705
  """
704
706
  parser = QasmParser()
705
707
 
@@ -741,7 +743,7 @@ def test_u1_gate():
741
743
  OPENQASM 2.0;
742
744
  include "qelib1.inc";
743
745
  qreg q[1];
744
- u1(pi / 3.0) q[0];
746
+ u1(pi / 3.0) q[0];
745
747
  """
746
748
  parser = QasmParser()
747
749
 
@@ -764,7 +766,7 @@ def test_u2_gate():
764
766
  OPENQASM 2.0;
765
767
  include "qelib1.inc";
766
768
  qreg q[1];
767
- u2(2 * pi, pi / 3.0) q[0];
769
+ u2(2 * pi, pi / 3.0) q[0];
768
770
  """
769
771
  parser = QasmParser()
770
772
 
@@ -787,7 +789,7 @@ def test_id_gate():
787
789
  OPENQASM 2.0;
788
790
  include "qelib1.inc";
789
791
  qreg q[2];
790
- id q;
792
+ id q;
791
793
  """
792
794
  parser = QasmParser()
793
795
 
@@ -846,7 +848,7 @@ def test_r_gate():
846
848
  OPENQASM 2.0;
847
849
  include "qelib1.inc";
848
850
  qreg q[1];
849
- r(pi, pi / 2.0) q[0];
851
+ r(pi, pi / 2.0) q[0];
850
852
  """
851
853
  parser = QasmParser()
852
854
 
@@ -871,9 +873,9 @@ def test_r_gate():
871
873
  def test_standard_single_qubit_gates_wrong_number_of_args(qasm_gate):
872
874
  qasm = f"""
873
875
  OPENQASM 2.0;
874
- include "qelib1.inc";
875
- qreg q[2];
876
- {qasm_gate} q[0], q[1];
876
+ include "qelib1.inc";
877
+ qreg q[2];
878
+ {qasm_gate} q[0], q[1];
877
879
  """
878
880
 
879
881
  parser = QasmParser()
@@ -889,9 +891,9 @@ def test_standard_single_qubit_gates_wrong_number_of_args(qasm_gate):
889
891
  )
890
892
  def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int):
891
893
  qasm = f"""OPENQASM 2.0;
892
- include "qelib1.inc";
893
- qreg q[2];
894
- {qasm_gate}(pi, 2*pi, 3*pi, 4*pi, 5*pi) q[1];
894
+ include "qelib1.inc";
895
+ qreg q[2];
896
+ {qasm_gate}(pi, 2*pi, 3*pi, 4*pi, 5*pi) q[1];
895
897
  """
896
898
 
897
899
  parser = QasmParser()
@@ -903,9 +905,9 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int):
903
905
  return
904
906
 
905
907
  qasm = f"""OPENQASM 2.0;
906
- include "qelib1.inc";
907
- qreg q[2];
908
- {qasm_gate} q[1];
908
+ include "qelib1.inc";
909
+ qreg q[2];
910
+ {qasm_gate} q[1];
909
911
  """
910
912
 
911
913
  parser = QasmParser()
@@ -1227,3 +1229,273 @@ def test_openqasm_3_0_scalar_qubit():
1227
1229
 
1228
1230
  ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit)
1229
1231
  assert parsed_qasm.qregs == {'q': 1}
1232
+
1233
+
1234
+ def test_custom_gate():
1235
+ qasm = """OPENQASM 2.0;
1236
+ include "qelib1.inc";
1237
+ qreg q[2];
1238
+ gate g q0, q1 {
1239
+ x q0;
1240
+ y q0;
1241
+ z q1;
1242
+ }
1243
+ g q[0], q[1];
1244
+ g q[1], q[0];
1245
+ """
1246
+
1247
+ # The gate definition should translate to this
1248
+ q0, q1 = cirq.NamedQubit.range(2, prefix='q')
1249
+ g = cirq.FrozenCircuit(cirq.X(q0), cirq.Y(q0), cirq.Z(q1))
1250
+
1251
+ # The outer circuit should then translate to this
1252
+ q_0, q_1 = cirq.NamedQubit.range(2, prefix='q_') # The outer qreg array
1253
+ expected = cirq.Circuit(
1254
+ cirq.CircuitOperation(g, qubit_map={q0: q_0, q1: q_1}),
1255
+ cirq.CircuitOperation(g, qubit_map={q0: q_1, q1: q_0}),
1256
+ )
1257
+
1258
+ # Verify
1259
+ parser = QasmParser()
1260
+ parsed_qasm = parser.parse(qasm)
1261
+ assert parsed_qasm.circuit == expected
1262
+
1263
+ # Sanity check that this unrolls to a valid circuit
1264
+ unrolled_expected = cirq.Circuit(
1265
+ cirq.X(q_0), cirq.Y(q_0), cirq.Z(q_1), cirq.X(q_1), cirq.Y(q_1), cirq.Z(q_0)
1266
+ )
1267
+ unrolled = cirq.align_left(cirq.unroll_circuit_op(parsed_qasm.circuit, tags_to_check=None))
1268
+ assert unrolled == unrolled_expected
1269
+
1270
+ # Sanity check that these have the same unitaries as the QASM.
1271
+ cq.assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, cirq.unitary(parsed_qasm.circuit))
1272
+ cq.assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, cirq.unitary(unrolled))
1273
+
1274
+
1275
+ def test_custom_gate_parameterized():
1276
+ qasm = """OPENQASM 2.0;
1277
+ include "qelib1.inc";
1278
+ qreg q[2];
1279
+ gate g(p0, p1) q0, q1 {
1280
+ rx(p0) q0;
1281
+ ry(p0+p1+3) q0;
1282
+ rz(p1) q1;
1283
+ }
1284
+ g(1,2) q[0], q[1];
1285
+ g(0,4) q[1], q[0];
1286
+ """
1287
+
1288
+ # The gate definition should translate to this
1289
+ p0, p1 = sympy.symbols('p0, p1')
1290
+ q0, q1 = cirq.NamedQubit.range(2, prefix='q')
1291
+ g = cirq.FrozenCircuit(
1292
+ cirq.Rx(rads=p0).on(q0), cirq.Ry(rads=p0 + p1 + 3).on(q0), cirq.Rz(rads=p1).on(q1)
1293
+ )
1294
+
1295
+ # The outer circuit should then translate to this
1296
+ q_0, q_1 = cirq.NamedQubit.range(2, prefix='q_') # The outer qreg array
1297
+ expected = cirq.Circuit(
1298
+ cirq.CircuitOperation(g, qubit_map={q0: q_0, q1: q_1}, param_resolver={'p0': 1, 'p1': 2}),
1299
+ cirq.CircuitOperation(g, qubit_map={q0: q_1, q1: q_0}, param_resolver={'p0': 0, 'p1': 4}),
1300
+ )
1301
+
1302
+ # Verify
1303
+ parser = QasmParser()
1304
+ parsed_qasm = parser.parse(qasm)
1305
+ assert parsed_qasm.circuit == expected
1306
+
1307
+ # Sanity check that this unrolls to a valid circuit
1308
+ unrolled_expected = cirq.Circuit(
1309
+ cirq.Rx(rads=1).on(q_0),
1310
+ cirq.Ry(rads=6).on(q_0),
1311
+ cirq.Rz(rads=2).on(q_1),
1312
+ cirq.Rx(rads=0).on(q_1),
1313
+ cirq.Ry(rads=7).on(q_1),
1314
+ cirq.Rz(rads=4).on(q_0),
1315
+ )
1316
+ unrolled = cirq.align_left(cirq.unroll_circuit_op(parsed_qasm.circuit, tags_to_check=None))
1317
+ assert unrolled == unrolled_expected
1318
+
1319
+ # Sanity check that these have the same unitaries as the QASM.
1320
+ cq.assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, cirq.unitary(parsed_qasm.circuit))
1321
+ cq.assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, cirq.unitary(unrolled))
1322
+
1323
+
1324
+ def test_custom_gate_broadcast():
1325
+ qasm = """OPENQASM 2.0;
1326
+ include "qelib1.inc";
1327
+ qreg q[3];
1328
+ gate g q0 {
1329
+ x q0;
1330
+ y q0;
1331
+ z q0;
1332
+ }
1333
+ g q; // broadcast to all qubits in register
1334
+ """
1335
+
1336
+ # The gate definition should translate to this
1337
+ q0 = cirq.NamedQubit('q0')
1338
+ g = cirq.FrozenCircuit(cirq.X(q0), cirq.Y(q0), cirq.Z(q0))
1339
+
1340
+ # The outer circuit should then translate to this
1341
+ q_0, q_1, q_2 = cirq.NamedQubit.range(3, prefix='q_') # The outer qreg array
1342
+ expected = cirq.Circuit(
1343
+ # It is broadcast to all qubits in the qreg
1344
+ cirq.CircuitOperation(g, qubit_map={q0: q_0}),
1345
+ cirq.CircuitOperation(g, qubit_map={q0: q_1}),
1346
+ cirq.CircuitOperation(g, qubit_map={q0: q_2}),
1347
+ )
1348
+
1349
+ # Verify
1350
+ parser = QasmParser()
1351
+ parsed_qasm = parser.parse(qasm)
1352
+ assert parsed_qasm.circuit == expected
1353
+
1354
+ # Sanity check that this unrolls to a valid circuit
1355
+ unrolled_expected = cirq.Circuit(
1356
+ cirq.X(q_0),
1357
+ cirq.Y(q_0),
1358
+ cirq.Z(q_0),
1359
+ cirq.X(q_1),
1360
+ cirq.Y(q_1),
1361
+ cirq.Z(q_1),
1362
+ cirq.X(q_2),
1363
+ cirq.Y(q_2),
1364
+ cirq.Z(q_2),
1365
+ )
1366
+ unrolled = cirq.align_left(cirq.unroll_circuit_op(parsed_qasm.circuit, tags_to_check=None))
1367
+ assert unrolled == unrolled_expected
1368
+
1369
+ # Sanity check that these have the same unitaries as the QASM.
1370
+ cq.assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, cirq.unitary(parsed_qasm.circuit))
1371
+ cq.assert_qiskit_parsed_qasm_consistent_with_unitary(qasm, cirq.unitary(unrolled))
1372
+
1373
+
1374
+ def test_custom_gate_undefined_qubit_error():
1375
+ qasm = """OPENQASM 2.0;
1376
+ include "qelib1.inc";
1377
+ qreg q[1];
1378
+ gate g q0 { x q1; }
1379
+ g q
1380
+ """
1381
+ _test_parse_exception(
1382
+ qasm,
1383
+ cirq_err="Undefined qubit 'q1' at line 4",
1384
+ qiskit_err="4,19: 'q1' is not defined in this scope",
1385
+ )
1386
+
1387
+
1388
+ def test_custom_gate_qubit_scope_closure_error():
1389
+ qasm = """OPENQASM 2.0;
1390
+ include "qelib1.inc";
1391
+ qreg q[1];
1392
+ gate g q0 { x q; }
1393
+ g q
1394
+ """
1395
+ _test_parse_exception(
1396
+ qasm,
1397
+ cirq_err="'q' is a register, not a qubit at line 4",
1398
+ qiskit_err="4,19: 'q' is a quantum register, not a qubit",
1399
+ )
1400
+
1401
+
1402
+ def test_custom_gate_qubit_index_error():
1403
+ qasm = """OPENQASM 2.0;
1404
+ include "qelib1.inc";
1405
+ qreg q[1];
1406
+ gate g q0 { x q0[0]; }
1407
+ g q
1408
+ """
1409
+ _test_parse_exception(
1410
+ qasm,
1411
+ cirq_err="Unsupported indexed qreg 'q0[0]' at line 4",
1412
+ qiskit_err="4,21: needed ';', but instead saw [",
1413
+ )
1414
+
1415
+
1416
+ def test_custom_gate_qreg_count_error():
1417
+ qasm = """OPENQASM 2.0;
1418
+ include "qelib1.inc";
1419
+ qreg q[2];
1420
+ gate g q0 { x q0; }
1421
+ g q[0], q[1];
1422
+ """
1423
+ _test_parse_exception(
1424
+ qasm,
1425
+ cirq_err="Wrong number of qregs for 'g' at line 5",
1426
+ qiskit_err="5,5: 'g' takes 1 quantum argument, but got 2",
1427
+ )
1428
+
1429
+
1430
+ def test_custom_gate_missing_param_error():
1431
+ qasm = """OPENQASM 2.0;
1432
+ include "qelib1.inc";
1433
+ qreg q[1];
1434
+ gate g(p) q0 { rx(p) q0; }
1435
+ g q;
1436
+ """
1437
+ _test_parse_exception(
1438
+ qasm,
1439
+ cirq_err="Wrong number of params for 'g' at line 5",
1440
+ qiskit_err=None, # Qiskit bug? It's an invalid circuit that won't simulate.
1441
+ )
1442
+
1443
+
1444
+ def test_custom_gate_extra_param_error():
1445
+ qasm = """OPENQASM 2.0;
1446
+ include "qelib1.inc";
1447
+ qreg q[1];
1448
+ gate g q0 { x q0; }
1449
+ g(3) q;
1450
+ """
1451
+ _test_parse_exception(
1452
+ qasm,
1453
+ cirq_err="Wrong number of params for 'g' at line 5",
1454
+ qiskit_err="5,5: 'g' takes 0 parameters, but got 1",
1455
+ )
1456
+
1457
+
1458
+ def test_custom_gate_undefined_param_error():
1459
+ qasm = """OPENQASM 2.0;
1460
+ include "qelib1.inc";
1461
+ qreg q[1];
1462
+ gate g q0 { rx(p) q0; }
1463
+ g q;
1464
+ """
1465
+ _test_parse_exception(
1466
+ qasm,
1467
+ cirq_err="Undefined parameter 'p' in line 4",
1468
+ qiskit_err="4,20: 'p' is not a parameter",
1469
+ )
1470
+
1471
+
1472
+ def test_top_level_param_error():
1473
+ qasm = """OPENQASM 2.0;
1474
+ include "qelib1.inc";
1475
+ qreg q[1];
1476
+ rx(p) q;
1477
+ """
1478
+ _test_parse_exception(
1479
+ qasm,
1480
+ cirq_err="Parameter 'p' in line 4 not supported",
1481
+ qiskit_err="4,8: 'p' is not a parameter",
1482
+ )
1483
+
1484
+
1485
+ def _test_parse_exception(qasm: str, cirq_err: str, qiskit_err: str | None):
1486
+ parser = QasmParser()
1487
+ with pytest.raises(QasmException, match=re.escape(cirq_err)):
1488
+ parser.parse(qasm)
1489
+ try:
1490
+ import qiskit
1491
+
1492
+ if qiskit_err is None:
1493
+ qiskit.QuantumCircuit.from_qasm_str(qasm)
1494
+ return
1495
+ with pytest.raises(qiskit.qasm2.exceptions.QASM2ParseError, match=re.escape(qiskit_err)):
1496
+ qiskit.QuantumCircuit.from_qasm_str(qasm)
1497
+ except ImportError: # pragma: no cover
1498
+ warnings.warn(
1499
+ "Skipped _test_qiskit_parse_exception because "
1500
+ "qiskit isn't installed to verify against."
1501
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cirq-core
3
- Version: 1.5.0.dev20250116193042
3
+ Version: 1.5.0.dev20250117150435
4
4
  Summary: A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
5
5
  Home-page: http://github.com/quantumlib/cirq
6
6
  Author: The Cirq Developers
@@ -4,8 +4,8 @@ cirq/_compat_test.py,sha256=Qq3ZcfgD-Nb81cEppQdJqhAyrVqXKtfXZYGXT0p-Wh0,34718
4
4
  cirq/_doc.py,sha256=yDyWUD_2JDS0gShfGRb-rdqRt9-WeL7DhkqX7np0Nko,2879
5
5
  cirq/_import.py,sha256=p9gMHJscbtDDkfHOaulvd3Aer0pwUF5AXpL89XR8dNw,8402
6
6
  cirq/_import_test.py,sha256=6K_v0riZJXOXUphHNkGA8MY-JcmGlezFaGmvrNhm3OQ,1015
7
- cirq/_version.py,sha256=QXvghHl0V3mA8QJwT7jY-pR45Mk27wAFagBcxt2R9QY,1206
8
- cirq/_version_test.py,sha256=YqqtIAbpKDIr_L8hhTwOlAu9t3p8aXBKP7VKIyLNW7M,147
7
+ cirq/_version.py,sha256=itApAPrU3Nlc0VUngXvFdgN9PaFtg2kTcCJJEgOVmN8,1206
8
+ cirq/_version_test.py,sha256=EMPy4rHRA_aLjLjLms6KEjlYqaJa0XIDyRK_fpequU8,147
9
9
  cirq/conftest.py,sha256=X7yLFL8GLhg2CjPw0hp5e_dGASfvHx1-QT03aUbhKJw,1168
10
10
  cirq/json_resolver_cache.py,sha256=cpbvJMNIh0U-l1mEVb-TqhJUEXfm2vpuR3v432ORSmg,13702
11
11
  cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
@@ -28,7 +28,7 @@ cirq/circuits/moment.py,sha256=y9hyP-QObxgL64a1veeTwDsqdGHbDkbE_o1VmgsfY6Y,26203
28
28
  cirq/circuits/moment_test.py,sha256=oNHNXhiPEoCKbzeh16tRwiW1qZWlg4X2O_uiVDP1D58,27375
29
29
  cirq/circuits/optimization_pass.py,sha256=uw3ne0-ebZo6GNjwfQMuQ3b5u9RCgyaXRfhpbljlxao,6468
30
30
  cirq/circuits/optimization_pass_test.py,sha256=eQB0NBJ9EvqjgSFGQMgaHIh5niQhksdnvqSXhsj3nOg,5947
31
- cirq/circuits/qasm_output.py,sha256=QUOeggq7NK3qm342dk47SNRi2qh4_98_gI3SdPjqRkA,13073
31
+ cirq/circuits/qasm_output.py,sha256=fHbD2OeRzC0ZIvpN551JMaXDMTih7z9ZUIeCY6zQDQU,13090
32
32
  cirq/circuits/qasm_output_test.py,sha256=PawmzjqGpwauWgESqoi_U_iaYVZAMg_eIhZ_2VrPkPw,13634
33
33
  cirq/circuits/text_diagram_drawer.py,sha256=ctZUG5fk2pf4XswHTJG4kteQYzzH0TefL9JWUagLJvc,17232
34
34
  cirq/circuits/text_diagram_drawer_test.py,sha256=2bSoBIeQajRi0aQxqYDpbMlT2eqpx_f-Cmg9XO6A9Jk,10750
@@ -103,10 +103,10 @@ cirq/contrib/paulistring/recombine_test.py,sha256=hJ083nR67JsIs38TfmCjmBLnhqyG0r
103
103
  cirq/contrib/paulistring/separate.py,sha256=2g4l78mXYJDR6xkv51VExZDb-rm5JEvhYrpMPgWa0Us,3961
104
104
  cirq/contrib/paulistring/separate_test.py,sha256=FzR78MSHDhNJxizbXreK6u3BeYhT7xn7W1QyHfEZ34E,1267
105
105
  cirq/contrib/qasm_import/__init__.py,sha256=RKX0vGDC2Pe5rH5rM4ClXdvtrAU16ePFImQpiJtJVNo,744
106
- cirq/contrib/qasm_import/_lexer.py,sha256=J0ExK_6VGMoql0ha0hrxHzbFuqFYazHSSruhgznI66Y,3366
107
- cirq/contrib/qasm_import/_lexer_test.py,sha256=iiz-cmIt5hnhHBc4ub4btqHnbi4EPaO7BE7bsJKPet8,4142
108
- cirq/contrib/qasm_import/_parser.py,sha256=JroR-z7EcUhVd2-556h007H7SnzmmbqM4tsSOwsvwNw,21061
109
- cirq/contrib/qasm_import/_parser_test.py,sha256=EliIovGMcHYxgyxm12D41dN7LCM4oBL1okhSsUw0BzM,31706
106
+ cirq/contrib/qasm_import/_lexer.py,sha256=DFfDArOd8F46XNjmvGR3EW-TA2d8Tn3unSoQIg_krMw,3453
107
+ cirq/contrib/qasm_import/_lexer_test.py,sha256=lFLgL-D_-tXJOQJjwg_49tzhUqFnikvbB_SwV_s8qOg,5655
108
+ cirq/contrib/qasm_import/_parser.py,sha256=qyU4q9Fz-hJBlh9swcEeNCwJ8YUORrgMJoc-f9bbldA,25997
109
+ cirq/contrib/qasm_import/_parser_test.py,sha256=gW1sk7EKUgQP79t-RtgeiCeI88Vtp-zqy2f-yEHU91E,39299
110
110
  cirq/contrib/qasm_import/exception.py,sha256=Wm6cwUPIkNMPjkv-ELpQ-zSoXaiLOddOQ4iYybwuS6I,695
111
111
  cirq/contrib/qasm_import/qasm.py,sha256=CP444IWCw4zlDNA7HxsTJ2xIak4mZhQv62ZiLlUc2zo,914
112
112
  cirq/contrib/qasm_import/qasm_test.py,sha256=e5b7LVn_6FIFZ6kINqMzJFIjzgtTgutVhgXgX_DcTc0,1861
@@ -1203,8 +1203,8 @@ cirq/work/sampler.py,sha256=bE5tmVkcR6cZZMLETxDfHehdsYUMbx2RvBeIBetehI4,19187
1203
1203
  cirq/work/sampler_test.py,sha256=hL2UWx3dz2ukZVNxWftiKVvJcQoLplLZdQm-k1QcA40,13282
1204
1204
  cirq/work/zeros_sampler.py,sha256=x1C7cup66a43n-3tm8QjhiqJa07qcJW10FxNp9jJ59Q,2356
1205
1205
  cirq/work/zeros_sampler_test.py,sha256=JIkpBBFPJe5Ba4142vzogyWyboG1Q1ZAm0UVGgOoZn8,3279
1206
- cirq_core-1.5.0.dev20250116193042.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1207
- cirq_core-1.5.0.dev20250116193042.dist-info/METADATA,sha256=EigUVU1kx6_BuDpu3sMOZSL28HbwHQM2cWvKOcZiwQc,2105
1208
- cirq_core-1.5.0.dev20250116193042.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
1209
- cirq_core-1.5.0.dev20250116193042.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1210
- cirq_core-1.5.0.dev20250116193042.dist-info/RECORD,,
1206
+ cirq_core-1.5.0.dev20250117150435.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1207
+ cirq_core-1.5.0.dev20250117150435.dist-info/METADATA,sha256=gWBedqQ5REYCU3Q306OsPbAe5WThkyD63buc3ivxSiY,2105
1208
+ cirq_core-1.5.0.dev20250117150435.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
1209
+ cirq_core-1.5.0.dev20250117150435.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1210
+ cirq_core-1.5.0.dev20250117150435.dist-info/RECORD,,