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 +1 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/qasm_output.py +2 -2
- cirq/contrib/qasm_import/_lexer.py +5 -0
- cirq/contrib/qasm_import/_lexer_test.py +68 -0
- cirq/contrib/qasm_import/_parser.py +169 -36
- cirq/contrib/qasm_import/_parser_test.py +314 -42
- {cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/METADATA +1 -1
- {cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/RECORD +12 -12
- {cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/LICENSE +0 -0
- {cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/WHEEL +0 -0
- {cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/top_level.txt +0 -0
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
cirq/circuits/qasm_output.py
CHANGED
|
@@ -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
|
|
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,
|
|
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[
|
|
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[
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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[
|
|
445
|
+
self, args: List[List[ops.Qid]], gate: str, p: Any, params: List[value.TParamVal]
|
|
386
446
|
):
|
|
387
|
-
|
|
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
|
-
# |
|
|
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
|
+
)
|
{cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cirq-core
|
|
3
|
-
Version: 1.5.0.
|
|
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
|
{cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/RECORD
RENAMED
|
@@ -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=
|
|
8
|
-
cirq/_version_test.py,sha256=
|
|
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=
|
|
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=
|
|
107
|
-
cirq/contrib/qasm_import/_lexer_test.py,sha256=
|
|
108
|
-
cirq/contrib/qasm_import/_parser.py,sha256=
|
|
109
|
-
cirq/contrib/qasm_import/_parser_test.py,sha256=
|
|
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.
|
|
1207
|
-
cirq_core-1.5.0.
|
|
1208
|
-
cirq_core-1.5.0.
|
|
1209
|
-
cirq_core-1.5.0.
|
|
1210
|
-
cirq_core-1.5.0.
|
|
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,,
|
{cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/LICENSE
RENAMED
|
File without changes
|
{cirq_core-1.5.0.dev20250116193042.dist-info → cirq_core-1.5.0.dev20250117150435.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|