Skip to content

Commit 01469ab

Browse files
authored
QASM parsing for classical controls (quantumlib#4738)
Part 11 of https://tinyurl.com/cirq-feedforward. This is self-contained in the QASM lexer and parser classes.
1 parent 09f6316 commit 01469ab

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

cirq/contrib/qasm_import/_lexer.py

+10
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ def __init__(self):
3030
'qreg': 'QREG',
3131
'creg': 'CREG',
3232
'measure': 'MEASURE',
33+
'if': 'IF',
3334
'->': 'ARROW',
35+
'!=': 'NE',
3436
}
3537

3638
tokens = [
@@ -98,10 +100,18 @@ def t_MEASURE(self, t):
98100
r"""measure"""
99101
return t
100102

103+
def t_IF(self, t):
104+
r"""if"""
105+
return t
106+
101107
def t_ARROW(self, t):
102108
"""->"""
103109
return t
104110

111+
def t_NE(self, t):
112+
"""!="""
113+
return t
114+
105115
def t_ID(self, t):
106116
r"""[a-zA-Z][a-zA-Z\d_]*"""
107117
return t

cirq/contrib/qasm_import/_parser.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,17 @@ def p_format(self, p):
290290
# circuit : new_reg circuit
291291
# | gate_op circuit
292292
# | measurement circuit
293+
# | if circuit
293294
# | empty
294295

295296
def p_circuit_reg(self, p):
296297
"""circuit : new_reg circuit"""
297298
p[0] = self.circuit
298299

299-
def p_circuit_gate_or_measurement(self, p):
300+
def p_circuit_gate_or_measurement_or_if(self, p):
300301
"""circuit : circuit gate_op
301-
| circuit measurement"""
302+
| circuit measurement
303+
| circuit if"""
302304
self.circuit.append(p[2])
303305
p[0] = self.circuit
304306

@@ -497,6 +499,13 @@ def p_measurement(self, p):
497499
ops.MeasurementGate(num_qubits=1, key=creg[i]).on(qreg[i]) for i in range(len(qreg))
498500
]
499501

502+
# if operations
503+
# if : IF '(' carg NE NATURAL_NUMBER ')' ID qargs
504+
505+
def p_if(self, p):
506+
"""if : IF '(' carg NE NATURAL_NUMBER ')' gate_op"""
507+
p[0] = [ops.ClassicallyControlledOperation(conditions=p[3], sub_operation=tuple(p[7])[0])]
508+
500509
def p_error(self, p):
501510
if p is None:
502511
raise QasmException('Unexpected end of file')

cirq/contrib/qasm_import/_parser_test.py

+25
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,31 @@ def test_CX_gate():
217217
assert parsed_qasm.qregs == {'q1': 2, 'q2': 2}
218218

219219

220+
def test_classical_control():
221+
qasm = """OPENQASM 2.0;
222+
qreg q[2];
223+
creg m_a[1];
224+
measure q[0] -> m_a[0];
225+
if (m_a!=0) CX q[0], q[1];
226+
"""
227+
parser = QasmParser()
228+
229+
q_0 = cirq.NamedQubit('q_0')
230+
q_1 = cirq.NamedQubit('q_1')
231+
expected_circuit = cirq.Circuit(
232+
cirq.measure(q_0, key='m_a_0'),
233+
cirq.CNOT(q_0, q_1).with_classical_controls('m_a_0'),
234+
)
235+
236+
parsed_qasm = parser.parse(qasm)
237+
238+
assert parsed_qasm.supportedFormat
239+
assert not parsed_qasm.qelib1Include
240+
241+
ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit)
242+
assert parsed_qasm.qregs == {'q': 2}
243+
244+
220245
def test_CX_gate_not_enough_args():
221246
qasm = """OPENQASM 2.0;
222247
qreg q[2];

0 commit comments

Comments
 (0)