From 00be042e5fc2299e9625a0e15bdec313f615f6f8 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 6 Dec 2024 17:27:49 -0600 Subject: [PATCH 01/13] additional qasm gate definitions --- cirq-core/cirq/contrib/qasm_import/_parser.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser.py b/cirq-core/cirq/contrib/qasm_import/_parser.py index eeb6ec98dd3..29452fdce86 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser.py @@ -243,6 +243,31 @@ def __init__(self) -> None: 'ch': QasmGateStatement( qasm_gate='ch', cirq_gate=ops.ControlledGate(ops.H), num_params=0, num_args=2 ), + "cu1": QasmGateStatement( + qasm_gate="cu1", + num_params=1, + num_args=2, + cirq_gate=( + lambda params: ops.ControlledGate(QasmUGate(0, 0, params[0] / np.pi)) + ), + ), + "cu3": QasmGateStatement( + qasm_gate="cu3", + num_params=3, + num_args=2, + cirq_gate=( + lambda params: ops.ControlledGate(QasmUGate(*[p / np.pi for p in params])) + ), + ), + "crz": QasmGateStatement( + qasm_gate="crz", + num_params=1, + num_args=2, + cirq_gate=(lambda params: ops.ControlledGate(ops.rz(params[0]))), + ), + "reset": QasmGateStatement( + qasm_gate="reset", num_params=0, num_args=1, cirq_gate=ops.ResetChannel() + ), 'swap': QasmGateStatement(qasm_gate='swap', cirq_gate=ops.SWAP, num_params=0, num_args=2), 'cswap': QasmGateStatement( qasm_gate='cswap', num_params=0, num_args=3, cirq_gate=ops.CSWAP From 449f7a5044df121b153d34e66cdf4c8a4c9ee24f Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 6 Dec 2024 17:28:17 -0600 Subject: [PATCH 02/13] updated tests for cu1, cu3, and crz Signed-off-by: Bharath --- .../cirq/contrib/qasm_import/_parser_test.py | 211 ++++++++++++------ 1 file changed, 147 insertions(+), 64 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index 07c301a2add..2f86936658e 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -186,7 +186,7 @@ def test_CX_gate(): qreg q2[2]; CX q1[0], q1[1]; CX q1, q2[0]; - CX q2, q1; + CX q2, q1; """ parser = QasmParser() @@ -390,7 +390,7 @@ def test_U_angles(): def test_U_gate_zero_params_error(): qasm = """OPENQASM 2.0; - qreg q[2]; + qreg q[2]; U q[1];""" parser = QasmParser() @@ -401,7 +401,7 @@ def test_U_gate_zero_params_error(): def test_U_gate_too_much_params_error(): qasm = """OPENQASM 2.0; - qreg q[2]; + qreg q[2]; U(pi, pi, pi, pi) q[1];""" parser = QasmParser() @@ -520,9 +520,9 @@ def test_rotation_gates(qasm_gate: str, cirq_gate: Callable[[float], cirq.Gate]) def test_rotation_gates_wrong_number_of_args(qasm_gate: str): qasm = f""" OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi) q[0], q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi) q[0], q[1]; """ parser = QasmParser() @@ -534,9 +534,9 @@ def test_rotation_gates_wrong_number_of_args(qasm_gate: str): @pytest.mark.parametrize('qasm_gate', [g[0] for g in rotation_gates]) def test_rotation_gates_zero_params_error(qasm_gate: str): qasm = f"""OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate} q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[1]; """ parser = QasmParser() @@ -584,7 +584,7 @@ def test_measure_individual_bits(): OPENQASM 2.0; include "qelib1.inc"; qreg q1[2]; - creg c1[2]; + creg c1[2]; measure q1[0] -> c1[0]; measure q1[1] -> c1[1]; """ @@ -612,8 +612,8 @@ def test_measure_registers(): qasm = """OPENQASM 2.0; include "qelib1.inc"; qreg q1[3]; - creg c1[3]; - measure q1 -> c1; + creg c1[3]; + measure q1 -> c1; """ parser = QasmParser() @@ -639,10 +639,10 @@ def test_measure_registers(): def test_measure_mismatched_register_size(): qasm = """OPENQASM 2.0; - include "qelib1.inc"; + include "qelib1.inc"; qreg q1[2]; - creg c1[3]; - measure q1 -> c1; + creg c1[3]; + measure q1 -> c1; """ parser = QasmParser() @@ -653,11 +653,11 @@ def test_measure_mismatched_register_size(): def test_measure_to_quantum_register(): qasm = """OPENQASM 2.0; - include "qelib1.inc"; + include "qelib1.inc"; qreg q1[3]; qreg q2[3]; - creg c1[3]; - measure q2 -> q1; + creg c1[3]; + measure q2 -> q1; """ parser = QasmParser() @@ -668,10 +668,10 @@ def test_measure_to_quantum_register(): def test_measure_undefined_classical_bit(): qasm = """OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[3]; - creg c1[3]; - measure q1[1] -> c2[1]; + include "qelib1.inc"; + qreg q1[3]; + creg c1[3]; + measure q1[1] -> c2[1]; """ parser = QasmParser() @@ -682,11 +682,11 @@ def test_measure_undefined_classical_bit(): def test_measure_from_classical_register(): qasm = """OPENQASM 2.0; - include "qelib1.inc"; + include "qelib1.inc"; qreg q1[2]; - creg c1[3]; - creg c2[3]; - measure c1 -> c2; + creg c1[3]; + creg c2[3]; + measure c1 -> c2; """ parser = QasmParser() @@ -698,8 +698,8 @@ def test_measure_from_classical_register(): def test_measurement_bounds(): qasm = """OPENQASM 2.0; qreg q1[3]; - creg c1[3]; - measure q1[0] -> c1[4]; + creg c1[3]; + measure q1[0] -> c1[4]; """ parser = QasmParser() @@ -741,7 +741,7 @@ def test_u1_gate(): OPENQASM 2.0; include "qelib1.inc"; qreg q[1]; - u1(pi / 3.0) q[0]; + u1(pi / 3.0) q[0]; """ parser = QasmParser() @@ -764,7 +764,7 @@ def test_u2_gate(): OPENQASM 2.0; include "qelib1.inc"; qreg q[1]; - u2(2 * pi, pi / 3.0) q[0]; + u2(2 * pi, pi / 3.0) q[0]; """ parser = QasmParser() @@ -787,7 +787,7 @@ def test_id_gate(): OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; - id q; + id q; """ parser = QasmParser() @@ -846,7 +846,7 @@ def test_r_gate(): OPENQASM 2.0; include "qelib1.inc"; qreg q[1]; - r(pi, pi / 2.0) q[0]; + r(pi, pi / 2.0) q[0]; """ parser = QasmParser() @@ -871,9 +871,9 @@ def test_r_gate(): def test_standard_single_qubit_gates_wrong_number_of_args(qasm_gate): qasm = f""" OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate} q[0], q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[0], q[1]; """ parser = QasmParser() @@ -889,9 +889,9 @@ def test_standard_single_qubit_gates_wrong_number_of_args(qasm_gate): ) def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): qasm = f"""OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi, 2*pi, 3*pi, 4*pi, 5*pi) q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi, 2*pi, 3*pi, 4*pi, 5*pi) q[1]; """ parser = QasmParser() @@ -903,9 +903,9 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): return qasm = f"""OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate} q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[1]; """ parser = QasmParser() @@ -923,24 +923,31 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): ('ch', cirq.ControlledGate(cirq.H)), ] +# Mapping of two-qubit gates and `num_params` +two_qubit_param_gates = { + ("cu1", cirq.ControlledGate(QasmUGate(0, 0, 0.1/np.pi))): 1, + ("cu3", cirq.ControlledGate(QasmUGate(0.1/np.pi, 0.2/np.pi, 0.3/np.pi))): 3, + ("crz", cirq.ControlledGate(cirq.rz(0.1))): 1, +} -@pytest.mark.parametrize('qasm_gate,cirq_gate', two_qubit_gates) + +@pytest.mark.parametrize("qasm_gate,cirq_gate", two_qubit_gates) def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[2]; - qreg q2[2]; - {qasm_gate} q1[0], q1[1]; - {qasm_gate} q1, q2[0]; - {qasm_gate} q2, q1; + OPENQASM 2.0; + include "qelib1.inc"; + qreg q1[2]; + qreg q2[2]; + {qasm_gate} q1[0], q1[1]; + {qasm_gate} q1, q2[0]; + {qasm_gate} q2, q1; """ parser = QasmParser() - q1_0 = cirq.NamedQubit('q1_0') - q1_1 = cirq.NamedQubit('q1_1') - q2_0 = cirq.NamedQubit('q2_0') - q2_1 = cirq.NamedQubit('q2_1') + q1_0 = cirq.NamedQubit("q1_0") + q1_1 = cirq.NamedQubit("q1_1") + q2_0 = cirq.NamedQubit("q2_0") + q2_1 = cirq.NamedQubit("q2_1") expected_circuit = Circuit() # CX q1[0], q1[1]; @@ -958,14 +965,85 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): assert parsed_qasm.qelib1Include ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {'q1': 2, 'q2': 2} + assert parsed_qasm.qregs == {"q1": 2, "q2": 2} + + +@pytest.mark.parametrize( + "qasm_gate,cirq_gate,num_params", + [ + (gate_map[0], gate_map[1], num_param) + for gate_map, num_param in two_qubit_param_gates.items() + ], +) +def test_two_qubit_param_gates( + qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate, num_params: int +): + params = "(0.1, 0.2, 0.3)" if num_params == 3 else "(0.1)" + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q1[2]; + qreg q2[2]; + {qasm_gate}{params} q1[0], q1[1]; + {qasm_gate}{params} q1, q2[0]; + {qasm_gate}{params} q2, q1; + """ + parser = QasmParser() + + q1_0 = cirq.NamedQubit("q1_0") + q1_1 = cirq.NamedQubit("q1_1") + q2_0 = cirq.NamedQubit("q2_0") + q2_1 = cirq.NamedQubit("q2_1") + + expected_circuit = cirq.Circuit() + expected_circuit.append(cirq_gate.on(q1_0, q1_1)) + expected_circuit.append(cirq_gate.on(q1_0, q2_0)) + expected_circuit.append(cirq_gate.on(q1_1, q2_0)) + expected_circuit.append(cirq_gate.on(q2_0, q1_0)) + expected_circuit.append(cirq_gate.on(q2_1, q1_1)) + parsed_qasm = parser.parse(qasm) + + assert parsed_qasm.supportedFormat + assert parsed_qasm.qelib1Include + + ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) + assert parsed_qasm.qregs == {"q1": 2, "q2": 2} -@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) +@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()]) +def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): + if qasm_gate in ("cu1", "crz"): + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(0.1) q[0]; + """ + elif qasm_gate == "cu3": + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(0.1, 0.2, 0.3) q[0]; + """ + else: + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[0]; + """ + + parser = QasmParser() + + with pytest.raises(QasmException, match=rf".*{qasm_gate}.* takes 2 arg\(s\).*got.*1.*line 5"): + parser.parse(qasm) + +@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_param_gates.keys()]) def test_two_qubit_gates_not_enough_args(qasm_gate: str): qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; + OPENQASM 2.0; + include "qelib1.inc"; qreg q[2]; {qasm_gate} q[0]; """ @@ -976,19 +1054,24 @@ def test_two_qubit_gates_not_enough_args(qasm_gate: str): parser.parse(qasm) -@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) +@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()]) def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str): + if qasm_gate in ("cu1", "cu3", "crz"): + num_params_needed = 3 if qasm_gate == "cu3" else 1 + else: + num_params_needed = 0 + qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi) q[0],q[1]; -""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi, pi/2, pi/3, pi/4) q[0],q[1]; + """ parser = QasmParser() with pytest.raises( - QasmException, match=rf".*{qasm_gate}.* takes 0 parameter\(s\).*got.*1.*line 5" + QasmException, match=rf".*{qasm_gate}*. takes {num_params_needed} parameter\(s\).*got.*4.*line 5" ): parser.parse(qasm) From 84f9d77f514b7686454e9ee7f42b18d119c998b2 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 6 Dec 2024 17:29:53 -0600 Subject: [PATCH 03/13] add test for qasm reset --- .../cirq/contrib/qasm_import/_parser_test.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index 2f86936658e..692f15d2c38 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -841,6 +841,35 @@ def test_u3_gate(): assert parsed_qasm.qregs == {'q': 2} +def test_reset(): + qasm = textwrap.dedent( + """\ + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[1]; + creg c[1]; + x q[0]; + reset q[0]; + measure q[0] -> c[0]; + """ + ) + + parser = QasmParser() + + q_0 = cirq.NamedQubit('q_0') + + expected_circuit = Circuit([cirq.X(q_0), cirq.reset(q_0), cirq.measure(q_0, key='c_0')]) + + parsed_qasm = parser.parse(qasm) + + assert parsed_qasm.supportedFormat + assert parsed_qasm.qelib1Include + + ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) + assert parsed_qasm.qregs == {'q': 1} + assert parsed_qasm.cregs == {'c': 1} + + def test_r_gate(): qasm = """ OPENQASM 2.0; From 9c892318cd541d4f34b9233432b4c1c822309511 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 6 Dec 2024 17:53:00 -0600 Subject: [PATCH 04/13] fix some checks Signed-off-by: Bharath --- cirq-core/cirq/contrib/qasm_import/_parser.py | 8 +--- .../cirq/contrib/qasm_import/_parser_test.py | 48 +++++-------------- 2 files changed, 14 insertions(+), 42 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser.py b/cirq-core/cirq/contrib/qasm_import/_parser.py index 29452fdce86..8df66103066 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser.py @@ -247,17 +247,13 @@ def __init__(self) -> None: qasm_gate="cu1", num_params=1, num_args=2, - cirq_gate=( - lambda params: ops.ControlledGate(QasmUGate(0, 0, params[0] / np.pi)) - ), + cirq_gate=(lambda params: ops.ControlledGate(QasmUGate(0, 0, params[0] / np.pi))), ), "cu3": QasmGateStatement( qasm_gate="cu3", num_params=3, num_args=2, - cirq_gate=( - lambda params: ops.ControlledGate(QasmUGate(*[p / np.pi for p in params])) - ), + cirq_gate=(lambda params: ops.ControlledGate(QasmUGate(*[p / np.pi for p in params]))), ), "crz": QasmGateStatement( qasm_gate="crz", diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index 692f15d2c38..d49cbba04cf 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -840,36 +840,6 @@ def test_u3_gate(): ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) assert parsed_qasm.qregs == {'q': 2} - -def test_reset(): - qasm = textwrap.dedent( - """\ - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[1]; - creg c[1]; - x q[0]; - reset q[0]; - measure q[0] -> c[0]; - """ - ) - - parser = QasmParser() - - q_0 = cirq.NamedQubit('q_0') - - expected_circuit = Circuit([cirq.X(q_0), cirq.reset(q_0), cirq.measure(q_0, key='c_0')]) - - parsed_qasm = parser.parse(qasm) - - assert parsed_qasm.supportedFormat - assert parsed_qasm.qelib1Include - - ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {'q': 1} - assert parsed_qasm.cregs == {'c': 1} - - def test_r_gate(): qasm = """ OPENQASM 2.0; @@ -954,8 +924,8 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): # Mapping of two-qubit gates and `num_params` two_qubit_param_gates = { - ("cu1", cirq.ControlledGate(QasmUGate(0, 0, 0.1/np.pi))): 1, - ("cu3", cirq.ControlledGate(QasmUGate(0.1/np.pi, 0.2/np.pi, 0.3/np.pi))): 3, + ("cu1", cirq.ControlledGate(QasmUGate(0, 0, 0.1 / np.pi))): 1, + ("cu3", cirq.ControlledGate(QasmUGate(0.1 / np.pi, 0.2 / np.pi, 0.3 / np.pi))): 3, ("crz", cirq.ControlledGate(cirq.rz(0.1))): 1, } @@ -1039,7 +1009,9 @@ def test_two_qubit_param_gates( assert parsed_qasm.qregs == {"q1": 2, "q2": 2} -@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()]) +@pytest.mark.parametrize( + "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] +) def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): if qasm_gate in ("cu1", "crz"): qasm = f""" @@ -1049,7 +1021,7 @@ def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): {qasm_gate}(0.1) q[0]; """ elif qasm_gate == "cu3": - qasm = f""" + qasm = f""" OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; @@ -1068,6 +1040,7 @@ def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): with pytest.raises(QasmException, match=rf".*{qasm_gate}.* takes 2 arg\(s\).*got.*1.*line 5"): parser.parse(qasm) + @pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_param_gates.keys()]) def test_two_qubit_gates_not_enough_args(qasm_gate: str): qasm = f""" @@ -1083,7 +1056,9 @@ def test_two_qubit_gates_not_enough_args(qasm_gate: str): parser.parse(qasm) -@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()]) +@pytest.mark.parametrize( + "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] +) def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str): if qasm_gate in ("cu1", "cu3", "crz"): num_params_needed = 3 if qasm_gate == "cu3" else 1 @@ -1100,7 +1075,8 @@ def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str): parser = QasmParser() with pytest.raises( - QasmException, match=rf".*{qasm_gate}*. takes {num_params_needed} parameter\(s\).*got.*4.*line 5" + QasmException, + match=rf".*{qasm_gate}*. takes {num_params_needed} parameter\(s\).*got.*4.*line 5", ): parser.parse(qasm) From 7234298853acdba2d087b8c8db0d3a59672eb491 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 6 Dec 2024 17:57:44 -0600 Subject: [PATCH 05/13] remove redundant reset definition Signed-off-by: Bharath --- cirq-core/cirq/contrib/qasm_import/_parser.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser.py b/cirq-core/cirq/contrib/qasm_import/_parser.py index 8df66103066..fc6ef571866 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser.py @@ -261,9 +261,6 @@ def __init__(self) -> None: num_args=2, cirq_gate=(lambda params: ops.ControlledGate(ops.rz(params[0]))), ), - "reset": QasmGateStatement( - qasm_gate="reset", num_params=0, num_args=1, cirq_gate=ops.ResetChannel() - ), 'swap': QasmGateStatement(qasm_gate='swap', cirq_gate=ops.SWAP, num_params=0, num_args=2), 'cswap': QasmGateStatement( qasm_gate='cswap', num_params=0, num_args=3, cirq_gate=ops.CSWAP From b406949187ff7ffd7ad597a4fb1e05591c6ac847 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 6 Dec 2024 22:10:23 -0600 Subject: [PATCH 06/13] remaining format fix --- cirq-core/cirq/contrib/qasm_import/_parser_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index d49cbba04cf..cea7996e003 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -840,6 +840,7 @@ def test_u3_gate(): ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) assert parsed_qasm.qregs == {'q': 2} + def test_r_gate(): qasm = """ OPENQASM 2.0; From 1d66a9800884851fff55443fa77213c588bdf723 Mon Sep 17 00:00:00 2001 From: Bharath Date: Mon, 9 Dec 2024 10:21:42 -0600 Subject: [PATCH 07/13] restore to original state Signed-off-by: Bharath --- .../cirq/contrib/qasm_import/_parser_test.py | 131 +++--------------- 1 file changed, 21 insertions(+), 110 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index cea7996e003..dfe0a823f8a 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -923,31 +923,24 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): ('ch', cirq.ControlledGate(cirq.H)), ] -# Mapping of two-qubit gates and `num_params` -two_qubit_param_gates = { - ("cu1", cirq.ControlledGate(QasmUGate(0, 0, 0.1 / np.pi))): 1, - ("cu3", cirq.ControlledGate(QasmUGate(0.1 / np.pi, 0.2 / np.pi, 0.3 / np.pi))): 3, - ("crz", cirq.ControlledGate(cirq.rz(0.1))): 1, -} - -@pytest.mark.parametrize("qasm_gate,cirq_gate", two_qubit_gates) +@pytest.mark.parametrize('qasm_gate,cirq_gate', two_qubit_gates) def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[2]; - qreg q2[2]; - {qasm_gate} q1[0], q1[1]; - {qasm_gate} q1, q2[0]; - {qasm_gate} q2, q1; + OPENQASM 2.0; + include "qelib1.inc"; + qreg q1[2]; + qreg q2[2]; + {qasm_gate} q1[0], q1[1]; + {qasm_gate} q1, q2[0]; + {qasm_gate} q2, q1; """ parser = QasmParser() - q1_0 = cirq.NamedQubit("q1_0") - q1_1 = cirq.NamedQubit("q1_1") - q2_0 = cirq.NamedQubit("q2_0") - q2_1 = cirq.NamedQubit("q2_1") + q1_0 = cirq.NamedQubit('q1_0') + q1_1 = cirq.NamedQubit('q1_1') + q2_0 = cirq.NamedQubit('q2_0') + q2_1 = cirq.NamedQubit('q2_1') expected_circuit = Circuit() # CX q1[0], q1[1]; @@ -965,84 +958,10 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): assert parsed_qasm.qelib1Include ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {"q1": 2, "q2": 2} - - -@pytest.mark.parametrize( - "qasm_gate,cirq_gate,num_params", - [ - (gate_map[0], gate_map[1], num_param) - for gate_map, num_param in two_qubit_param_gates.items() - ], -) -def test_two_qubit_param_gates( - qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate, num_params: int -): - params = "(0.1, 0.2, 0.3)" if num_params == 3 else "(0.1)" - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[2]; - qreg q2[2]; - {qasm_gate}{params} q1[0], q1[1]; - {qasm_gate}{params} q1, q2[0]; - {qasm_gate}{params} q2, q1; - """ - parser = QasmParser() - - q1_0 = cirq.NamedQubit("q1_0") - q1_1 = cirq.NamedQubit("q1_1") - q2_0 = cirq.NamedQubit("q2_0") - q2_1 = cirq.NamedQubit("q2_1") - - expected_circuit = cirq.Circuit() - expected_circuit.append(cirq_gate.on(q1_0, q1_1)) - expected_circuit.append(cirq_gate.on(q1_0, q2_0)) - expected_circuit.append(cirq_gate.on(q1_1, q2_0)) - expected_circuit.append(cirq_gate.on(q2_0, q1_0)) - expected_circuit.append(cirq_gate.on(q2_1, q1_1)) - parsed_qasm = parser.parse(qasm) - - assert parsed_qasm.supportedFormat - assert parsed_qasm.qelib1Include - - ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {"q1": 2, "q2": 2} - - -@pytest.mark.parametrize( - "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] -) -def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): - if qasm_gate in ("cu1", "crz"): - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(0.1) q[0]; - """ - elif qasm_gate == "cu3": - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(0.1, 0.2, 0.3) q[0]; - """ - else: - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate} q[0]; - """ - - parser = QasmParser() - - with pytest.raises(QasmException, match=rf".*{qasm_gate}.* takes 2 arg\(s\).*got.*1.*line 5"): - parser.parse(qasm) + assert parsed_qasm.qregs == {'q1': 2, 'q2': 2} -@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_param_gates.keys()]) +@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) def test_two_qubit_gates_not_enough_args(qasm_gate: str): qasm = f""" OPENQASM 2.0; @@ -1057,27 +976,19 @@ def test_two_qubit_gates_not_enough_args(qasm_gate: str): parser.parse(qasm) -@pytest.mark.parametrize( - "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] -) +@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str): - if qasm_gate in ("cu1", "cu3", "crz"): - num_params_needed = 3 if qasm_gate == "cu3" else 1 - else: - num_params_needed = 0 - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi, pi/2, pi/3, pi/4) q[0],q[1]; - """ + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi) q[0],q[1]; +""" parser = QasmParser() with pytest.raises( - QasmException, - match=rf".*{qasm_gate}*. takes {num_params_needed} parameter\(s\).*got.*4.*line 5", + QasmException, match=rf".*{qasm_gate}.* takes 0 parameter\(s\).*got.*1.*line 5" ): parser.parse(qasm) From adb8dc898f934f5cb46b3d0b8dfbfaeb1cb107ac Mon Sep 17 00:00:00 2001 From: Bharath Date: Mon, 9 Dec 2024 10:23:37 -0600 Subject: [PATCH 08/13] smaller diff changes Signed-off-by: Bharath --- .../cirq/contrib/qasm_import/_parser_test.py | 132 +++++++++++++++--- 1 file changed, 111 insertions(+), 21 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index dfe0a823f8a..01027be4c15 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -924,23 +924,31 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): ] -@pytest.mark.parametrize('qasm_gate,cirq_gate', two_qubit_gates) +# Mapping of two-qubit gates and `num_params` +two_qubit_param_gates = { + ("cu1", cirq.ControlledGate(QasmUGate(0, 0, 0.1 / np.pi))): 1, + ("cu3", cirq.ControlledGate(QasmUGate(0.1 / np.pi, 0.2 / np.pi, 0.3 / np.pi))): 3, + ("crz", cirq.ControlledGate(cirq.rz(0.1))): 1, +} + + +@pytest.mark.parametrize("qasm_gate,cirq_gate", two_qubit_gates) def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[2]; - qreg q2[2]; - {qasm_gate} q1[0], q1[1]; - {qasm_gate} q1, q2[0]; - {qasm_gate} q2, q1; + OPENQASM 2.0; + include "qelib1.inc"; + qreg q1[2]; + qreg q2[2]; + {qasm_gate} q1[0], q1[1]; + {qasm_gate} q1, q2[0]; + {qasm_gate} q2, q1; """ parser = QasmParser() - q1_0 = cirq.NamedQubit('q1_0') - q1_1 = cirq.NamedQubit('q1_1') - q2_0 = cirq.NamedQubit('q2_0') - q2_1 = cirq.NamedQubit('q2_1') + q1_0 = cirq.NamedQubit("q1_0") + q1_1 = cirq.NamedQubit("q1_1") + q2_0 = cirq.NamedQubit("q2_0") + q2_1 = cirq.NamedQubit("q2_1") expected_circuit = Circuit() # CX q1[0], q1[1]; @@ -958,10 +966,84 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): assert parsed_qasm.qelib1Include ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {'q1': 2, 'q2': 2} + assert parsed_qasm.qregs == {"q1": 2, "q2": 2} + + +@pytest.mark.parametrize( + "qasm_gate,cirq_gate,num_params", + [ + (gate_map[0], gate_map[1], num_param) + for gate_map, num_param in two_qubit_param_gates.items() + ], +) +def test_two_qubit_param_gates( + qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate, num_params: int +): + params = "(0.1, 0.2, 0.3)" if num_params == 3 else "(0.1)" + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q1[2]; + qreg q2[2]; + {qasm_gate}{params} q1[0], q1[1]; + {qasm_gate}{params} q1, q2[0]; + {qasm_gate}{params} q2, q1; + """ + parser = QasmParser() + q1_0 = cirq.NamedQubit("q1_0") + q1_1 = cirq.NamedQubit("q1_1") + q2_0 = cirq.NamedQubit("q2_0") + q2_1 = cirq.NamedQubit("q2_1") + + expected_circuit = cirq.Circuit() + expected_circuit.append(cirq_gate.on(q1_0, q1_1)) + expected_circuit.append(cirq_gate.on(q1_0, q2_0)) + expected_circuit.append(cirq_gate.on(q1_1, q2_0)) + expected_circuit.append(cirq_gate.on(q2_0, q1_0)) + expected_circuit.append(cirq_gate.on(q2_1, q1_1)) + parsed_qasm = parser.parse(qasm) + + assert parsed_qasm.supportedFormat + assert parsed_qasm.qelib1Include -@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) + ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) + assert parsed_qasm.qregs == {"q1": 2, "q2": 2} + + +@pytest.mark.parametrize( + "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] +) +def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): + if qasm_gate in ("cu1", "crz"): + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(0.1) q[0]; + """ + elif qasm_gate == "cu3": + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(0.1, 0.2, 0.3) q[0]; + """ + else: + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[0]; + """ + + parser = QasmParser() + + with pytest.raises(QasmException, match=rf".*{qasm_gate}.* takes 2 arg\(s\).*got.*1.*line 5"): + parser.parse(qasm) + + +@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_param_gates.keys()]) def test_two_qubit_gates_not_enough_args(qasm_gate: str): qasm = f""" OPENQASM 2.0; @@ -976,19 +1058,27 @@ def test_two_qubit_gates_not_enough_args(qasm_gate: str): parser.parse(qasm) -@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) +@pytest.mark.parametrize( + "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] +) def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str): + if qasm_gate in ("cu1", "cu3", "crz"): + num_params_needed = 3 if qasm_gate == "cu3" else 1 + else: + num_params_needed = 0 + qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi) q[0],q[1]; -""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi, pi/2, pi/3, pi/4) q[0],q[1]; + """ parser = QasmParser() with pytest.raises( - QasmException, match=rf".*{qasm_gate}.* takes 0 parameter\(s\).*got.*1.*line 5" + QasmException, + match=rf".*{qasm_gate}*. takes {num_params_needed} parameter\(s\).*got.*4.*line 5", ): parser.parse(qasm) From 3e37f90cc6828be32396710715981221a3d6d17d Mon Sep 17 00:00:00 2001 From: Bharath Date: Mon, 9 Dec 2024 10:31:35 -0600 Subject: [PATCH 09/13] revert to original state Signed-off-by: Bharath --- .../cirq/contrib/qasm_import/_parser_test.py | 218 +++++------------- 1 file changed, 64 insertions(+), 154 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index 01027be4c15..07c301a2add 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -186,7 +186,7 @@ def test_CX_gate(): qreg q2[2]; CX q1[0], q1[1]; CX q1, q2[0]; - CX q2, q1; + CX q2, q1; """ parser = QasmParser() @@ -390,7 +390,7 @@ def test_U_angles(): def test_U_gate_zero_params_error(): qasm = """OPENQASM 2.0; - qreg q[2]; + qreg q[2]; U q[1];""" parser = QasmParser() @@ -401,7 +401,7 @@ def test_U_gate_zero_params_error(): def test_U_gate_too_much_params_error(): qasm = """OPENQASM 2.0; - qreg q[2]; + qreg q[2]; U(pi, pi, pi, pi) q[1];""" parser = QasmParser() @@ -520,9 +520,9 @@ def test_rotation_gates(qasm_gate: str, cirq_gate: Callable[[float], cirq.Gate]) def test_rotation_gates_wrong_number_of_args(qasm_gate: str): qasm = f""" OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi) q[0], q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi) q[0], q[1]; """ parser = QasmParser() @@ -534,9 +534,9 @@ def test_rotation_gates_wrong_number_of_args(qasm_gate: str): @pytest.mark.parametrize('qasm_gate', [g[0] for g in rotation_gates]) def test_rotation_gates_zero_params_error(qasm_gate: str): qasm = f"""OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate} q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[1]; """ parser = QasmParser() @@ -584,7 +584,7 @@ def test_measure_individual_bits(): OPENQASM 2.0; include "qelib1.inc"; qreg q1[2]; - creg c1[2]; + creg c1[2]; measure q1[0] -> c1[0]; measure q1[1] -> c1[1]; """ @@ -612,8 +612,8 @@ def test_measure_registers(): qasm = """OPENQASM 2.0; include "qelib1.inc"; qreg q1[3]; - creg c1[3]; - measure q1 -> c1; + creg c1[3]; + measure q1 -> c1; """ parser = QasmParser() @@ -639,10 +639,10 @@ def test_measure_registers(): def test_measure_mismatched_register_size(): qasm = """OPENQASM 2.0; - include "qelib1.inc"; + include "qelib1.inc"; qreg q1[2]; - creg c1[3]; - measure q1 -> c1; + creg c1[3]; + measure q1 -> c1; """ parser = QasmParser() @@ -653,11 +653,11 @@ def test_measure_mismatched_register_size(): def test_measure_to_quantum_register(): qasm = """OPENQASM 2.0; - include "qelib1.inc"; + include "qelib1.inc"; qreg q1[3]; qreg q2[3]; - creg c1[3]; - measure q2 -> q1; + creg c1[3]; + measure q2 -> q1; """ parser = QasmParser() @@ -668,10 +668,10 @@ def test_measure_to_quantum_register(): def test_measure_undefined_classical_bit(): qasm = """OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[3]; - creg c1[3]; - measure q1[1] -> c2[1]; + include "qelib1.inc"; + qreg q1[3]; + creg c1[3]; + measure q1[1] -> c2[1]; """ parser = QasmParser() @@ -682,11 +682,11 @@ def test_measure_undefined_classical_bit(): def test_measure_from_classical_register(): qasm = """OPENQASM 2.0; - include "qelib1.inc"; + include "qelib1.inc"; qreg q1[2]; - creg c1[3]; - creg c2[3]; - measure c1 -> c2; + creg c1[3]; + creg c2[3]; + measure c1 -> c2; """ parser = QasmParser() @@ -698,8 +698,8 @@ def test_measure_from_classical_register(): def test_measurement_bounds(): qasm = """OPENQASM 2.0; qreg q1[3]; - creg c1[3]; - measure q1[0] -> c1[4]; + creg c1[3]; + measure q1[0] -> c1[4]; """ parser = QasmParser() @@ -741,7 +741,7 @@ def test_u1_gate(): OPENQASM 2.0; include "qelib1.inc"; qreg q[1]; - u1(pi / 3.0) q[0]; + u1(pi / 3.0) q[0]; """ parser = QasmParser() @@ -764,7 +764,7 @@ def test_u2_gate(): OPENQASM 2.0; include "qelib1.inc"; qreg q[1]; - u2(2 * pi, pi / 3.0) q[0]; + u2(2 * pi, pi / 3.0) q[0]; """ parser = QasmParser() @@ -787,7 +787,7 @@ def test_id_gate(): OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; - id q; + id q; """ parser = QasmParser() @@ -846,7 +846,7 @@ def test_r_gate(): OPENQASM 2.0; include "qelib1.inc"; qreg q[1]; - r(pi, pi / 2.0) q[0]; + r(pi, pi / 2.0) q[0]; """ parser = QasmParser() @@ -871,9 +871,9 @@ def test_r_gate(): def test_standard_single_qubit_gates_wrong_number_of_args(qasm_gate): qasm = f""" OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate} q[0], q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[0], q[1]; """ parser = QasmParser() @@ -889,9 +889,9 @@ def test_standard_single_qubit_gates_wrong_number_of_args(qasm_gate): ) def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): qasm = f"""OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi, 2*pi, 3*pi, 4*pi, 5*pi) q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi, 2*pi, 3*pi, 4*pi, 5*pi) q[1]; """ parser = QasmParser() @@ -903,9 +903,9 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): return qasm = f"""OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate} q[1]; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[1]; """ parser = QasmParser() @@ -924,31 +924,23 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): ] -# Mapping of two-qubit gates and `num_params` -two_qubit_param_gates = { - ("cu1", cirq.ControlledGate(QasmUGate(0, 0, 0.1 / np.pi))): 1, - ("cu3", cirq.ControlledGate(QasmUGate(0.1 / np.pi, 0.2 / np.pi, 0.3 / np.pi))): 3, - ("crz", cirq.ControlledGate(cirq.rz(0.1))): 1, -} - - -@pytest.mark.parametrize("qasm_gate,cirq_gate", two_qubit_gates) +@pytest.mark.parametrize('qasm_gate,cirq_gate', two_qubit_gates) def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[2]; - qreg q2[2]; - {qasm_gate} q1[0], q1[1]; - {qasm_gate} q1, q2[0]; - {qasm_gate} q2, q1; + OPENQASM 2.0; + include "qelib1.inc"; + qreg q1[2]; + qreg q2[2]; + {qasm_gate} q1[0], q1[1]; + {qasm_gate} q1, q2[0]; + {qasm_gate} q2, q1; """ parser = QasmParser() - q1_0 = cirq.NamedQubit("q1_0") - q1_1 = cirq.NamedQubit("q1_1") - q2_0 = cirq.NamedQubit("q2_0") - q2_1 = cirq.NamedQubit("q2_1") + q1_0 = cirq.NamedQubit('q1_0') + q1_1 = cirq.NamedQubit('q1_1') + q2_0 = cirq.NamedQubit('q2_0') + q2_1 = cirq.NamedQubit('q2_1') expected_circuit = Circuit() # CX q1[0], q1[1]; @@ -966,88 +958,14 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): assert parsed_qasm.qelib1Include ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {"q1": 2, "q2": 2} - - -@pytest.mark.parametrize( - "qasm_gate,cirq_gate,num_params", - [ - (gate_map[0], gate_map[1], num_param) - for gate_map, num_param in two_qubit_param_gates.items() - ], -) -def test_two_qubit_param_gates( - qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate, num_params: int -): - params = "(0.1, 0.2, 0.3)" if num_params == 3 else "(0.1)" - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[2]; - qreg q2[2]; - {qasm_gate}{params} q1[0], q1[1]; - {qasm_gate}{params} q1, q2[0]; - {qasm_gate}{params} q2, q1; - """ - parser = QasmParser() - - q1_0 = cirq.NamedQubit("q1_0") - q1_1 = cirq.NamedQubit("q1_1") - q2_0 = cirq.NamedQubit("q2_0") - q2_1 = cirq.NamedQubit("q2_1") - - expected_circuit = cirq.Circuit() - expected_circuit.append(cirq_gate.on(q1_0, q1_1)) - expected_circuit.append(cirq_gate.on(q1_0, q2_0)) - expected_circuit.append(cirq_gate.on(q1_1, q2_0)) - expected_circuit.append(cirq_gate.on(q2_0, q1_0)) - expected_circuit.append(cirq_gate.on(q2_1, q1_1)) - parsed_qasm = parser.parse(qasm) - - assert parsed_qasm.supportedFormat - assert parsed_qasm.qelib1Include - - ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {"q1": 2, "q2": 2} - - -@pytest.mark.parametrize( - "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] -) -def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): - if qasm_gate in ("cu1", "crz"): - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(0.1) q[0]; - """ - elif qasm_gate == "cu3": - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(0.1, 0.2, 0.3) q[0]; - """ - else: - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate} q[0]; - """ - - parser = QasmParser() - - with pytest.raises(QasmException, match=rf".*{qasm_gate}.* takes 2 arg\(s\).*got.*1.*line 5"): - parser.parse(qasm) + assert parsed_qasm.qregs == {'q1': 2, 'q2': 2} -@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_param_gates.keys()]) +@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) def test_two_qubit_gates_not_enough_args(qasm_gate: str): qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; + OPENQASM 2.0; + include "qelib1.inc"; qreg q[2]; {qasm_gate} q[0]; """ @@ -1058,27 +976,19 @@ def test_two_qubit_gates_not_enough_args(qasm_gate: str): parser.parse(qasm) -@pytest.mark.parametrize( - "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] -) +@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str): - if qasm_gate in ("cu1", "cu3", "crz"): - num_params_needed = 3 if qasm_gate == "cu3" else 1 - else: - num_params_needed = 0 - qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi, pi/2, pi/3, pi/4) q[0],q[1]; - """ + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi) q[0],q[1]; +""" parser = QasmParser() with pytest.raises( - QasmException, - match=rf".*{qasm_gate}*. takes {num_params_needed} parameter\(s\).*got.*4.*line 5", + QasmException, match=rf".*{qasm_gate}.* takes 0 parameter\(s\).*got.*1.*line 5" ): parser.parse(qasm) From d0c165ecb366cd30a385530474d8c97231b58c71 Mon Sep 17 00:00:00 2001 From: Bharath Date: Mon, 9 Dec 2024 10:34:21 -0600 Subject: [PATCH 10/13] smallest diff Signed-off-by: Bharath --- .../cirq/contrib/qasm_import/_parser_test.py | 136 +++++++++++++++--- 1 file changed, 113 insertions(+), 23 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index 07c301a2add..80262f01b9a 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -924,23 +924,31 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): ] -@pytest.mark.parametrize('qasm_gate,cirq_gate', two_qubit_gates) +# Mapping of two-qubit gates and `num_params` +two_qubit_param_gates = { + ("cu1", cirq.ControlledGate(QasmUGate(0, 0, 0.1 / np.pi))): 1, + ("cu3", cirq.ControlledGate(QasmUGate(0.1 / np.pi, 0.2 / np.pi, 0.3 / np.pi))): 3, + ("crz", cirq.ControlledGate(cirq.rz(0.1))): 1, +} + + +@pytest.mark.parametrize("qasm_gate,cirq_gate", two_qubit_gates) def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q1[2]; - qreg q2[2]; - {qasm_gate} q1[0], q1[1]; - {qasm_gate} q1, q2[0]; - {qasm_gate} q2, q1; + OPENQASM 2.0; + include "qelib1.inc"; + qreg q1[2]; + qreg q2[2]; + {qasm_gate} q1[0], q1[1]; + {qasm_gate} q1, q2[0]; + {qasm_gate} q2, q1; """ parser = QasmParser() - q1_0 = cirq.NamedQubit('q1_0') - q1_1 = cirq.NamedQubit('q1_1') - q2_0 = cirq.NamedQubit('q2_0') - q2_1 = cirq.NamedQubit('q2_1') + q1_0 = cirq.NamedQubit("q1_0") + q1_1 = cirq.NamedQubit("q1_1") + q2_0 = cirq.NamedQubit("q2_0") + q2_1 = cirq.NamedQubit("q2_1") expected_circuit = Circuit() # CX q1[0], q1[1]; @@ -958,14 +966,88 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): assert parsed_qasm.qelib1Include ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {'q1': 2, 'q2': 2} + assert parsed_qasm.qregs == {"q1": 2, "q2": 2} -@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) +@pytest.mark.parametrize( + "qasm_gate,cirq_gate,num_params", + [ + (gate_map[0], gate_map[1], num_param) + for gate_map, num_param in two_qubit_param_gates.items() + ], +) +def test_two_qubit_param_gates( + qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate, num_params: int +): + params = "(0.1, 0.2, 0.3)" if num_params == 3 else "(0.1)" + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q1[2]; + qreg q2[2]; + {qasm_gate}{params} q1[0], q1[1]; + {qasm_gate}{params} q1, q2[0]; + {qasm_gate}{params} q2, q1; + """ + parser = QasmParser() + + q1_0 = cirq.NamedQubit("q1_0") + q1_1 = cirq.NamedQubit("q1_1") + q2_0 = cirq.NamedQubit("q2_0") + q2_1 = cirq.NamedQubit("q2_1") + + expected_circuit = cirq.Circuit() + expected_circuit.append(cirq_gate.on(q1_0, q1_1)) + expected_circuit.append(cirq_gate.on(q1_0, q2_0)) + expected_circuit.append(cirq_gate.on(q1_1, q2_0)) + expected_circuit.append(cirq_gate.on(q2_0, q1_0)) + expected_circuit.append(cirq_gate.on(q2_1, q1_1)) + parsed_qasm = parser.parse(qasm) + + assert parsed_qasm.supportedFormat + assert parsed_qasm.qelib1Include + + ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) + assert parsed_qasm.qregs == {"q1": 2, "q2": 2} + + +@pytest.mark.parametrize( + "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] +) +def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): + if qasm_gate in ("cu1", "crz"): + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(0.1) q[0]; + """ + elif qasm_gate == "cu3": + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(0.1, 0.2, 0.3) q[0]; + """ + else: + qasm = f""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate} q[0]; + """ + + parser = QasmParser() + + with pytest.raises(QasmException, match=rf".*{qasm_gate}.* takes 2 arg\(s\).*got.*1.*line 5"): + parser.parse(qasm) + + +@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_param_gates.keys()]) def test_two_qubit_gates_not_enough_args(qasm_gate: str): qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; + OPENQASM 2.0; + include "qelib1.inc"; qreg q[2]; {qasm_gate} q[0]; """ @@ -976,19 +1058,27 @@ def test_two_qubit_gates_not_enough_args(qasm_gate: str): parser.parse(qasm) -@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates]) +@pytest.mark.parametrize( + "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] +) def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str): + if qasm_gate in ("cu1", "cu3", "crz"): + num_params_needed = 3 if qasm_gate == "cu3" else 1 + else: + num_params_needed = 0 + qasm = f""" - OPENQASM 2.0; - include "qelib1.inc"; - qreg q[2]; - {qasm_gate}(pi) q[0],q[1]; -""" + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[2]; + {qasm_gate}(pi, pi/2, pi/3, pi/4) q[0],q[1]; + """ parser = QasmParser() with pytest.raises( - QasmException, match=rf".*{qasm_gate}.* takes 0 parameter\(s\).*got.*1.*line 5" + QasmException, + match=rf".*{qasm_gate}*. takes {num_params_needed} parameter\(s\).*got.*4.*line 5", ): parser.parse(qasm) From af90066b78c634386358818d6b64ed96d90eaf09 Mon Sep 17 00:00:00 2001 From: Bharath Date: Mon, 9 Dec 2024 10:55:09 -0600 Subject: [PATCH 11/13] use single-quotes for consistency (1) Signed-off-by: Bharath --- cirq-core/cirq/contrib/qasm_import/_parser.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser.py b/cirq-core/cirq/contrib/qasm_import/_parser.py index fc6ef571866..3e13f011778 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser.py @@ -243,20 +243,20 @@ def __init__(self) -> None: 'ch': QasmGateStatement( qasm_gate='ch', cirq_gate=ops.ControlledGate(ops.H), num_params=0, num_args=2 ), - "cu1": QasmGateStatement( - qasm_gate="cu1", + 'cu1': QasmGateStatement( + qasm_gate='cu1', num_params=1, num_args=2, cirq_gate=(lambda params: ops.ControlledGate(QasmUGate(0, 0, params[0] / np.pi))), ), - "cu3": QasmGateStatement( - qasm_gate="cu3", + 'cu3': QasmGateStatement( + qasm_gate='cu3', num_params=3, num_args=2, cirq_gate=(lambda params: ops.ControlledGate(QasmUGate(*[p / np.pi for p in params]))), ), - "crz": QasmGateStatement( - qasm_gate="crz", + 'crz': QasmGateStatement( + qasm_gate='crz', num_params=1, num_args=2, cirq_gate=(lambda params: ops.ControlledGate(ops.rz(params[0]))), From 9fb604dacb11bf83d1320883f8260be9c79174ad Mon Sep 17 00:00:00 2001 From: Bharath Date: Mon, 9 Dec 2024 11:01:12 -0600 Subject: [PATCH 12/13] use single-quotes for consistency (2) Signed-off-by: Bharath --- .../cirq/contrib/qasm_import/_parser_test.py | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/cirq-core/cirq/contrib/qasm_import/_parser_test.py b/cirq-core/cirq/contrib/qasm_import/_parser_test.py index 80262f01b9a..3325bcd225a 100644 --- a/cirq-core/cirq/contrib/qasm_import/_parser_test.py +++ b/cirq-core/cirq/contrib/qasm_import/_parser_test.py @@ -926,13 +926,13 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int): # Mapping of two-qubit gates and `num_params` two_qubit_param_gates = { - ("cu1", cirq.ControlledGate(QasmUGate(0, 0, 0.1 / np.pi))): 1, - ("cu3", cirq.ControlledGate(QasmUGate(0.1 / np.pi, 0.2 / np.pi, 0.3 / np.pi))): 3, - ("crz", cirq.ControlledGate(cirq.rz(0.1))): 1, + ('cu1', cirq.ControlledGate(QasmUGate(0, 0, 0.1 / np.pi))): 1, + ('cu3', cirq.ControlledGate(QasmUGate(0.1 / np.pi, 0.2 / np.pi, 0.3 / np.pi))): 3, + ('crz', cirq.ControlledGate(cirq.rz(0.1))): 1, } -@pytest.mark.parametrize("qasm_gate,cirq_gate", two_qubit_gates) +@pytest.mark.parametrize('qasm_gate,cirq_gate', two_qubit_gates) def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): qasm = f""" OPENQASM 2.0; @@ -945,10 +945,10 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): """ parser = QasmParser() - q1_0 = cirq.NamedQubit("q1_0") - q1_1 = cirq.NamedQubit("q1_1") - q2_0 = cirq.NamedQubit("q2_0") - q2_1 = cirq.NamedQubit("q2_1") + q1_0 = cirq.NamedQubit('q1_0') + q1_1 = cirq.NamedQubit('q1_1') + q2_0 = cirq.NamedQubit('q2_0') + q2_1 = cirq.NamedQubit('q2_1') expected_circuit = Circuit() # CX q1[0], q1[1]; @@ -966,11 +966,11 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): assert parsed_qasm.qelib1Include ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {"q1": 2, "q2": 2} + assert parsed_qasm.qregs == {'q1': 2, 'q2': 2} @pytest.mark.parametrize( - "qasm_gate,cirq_gate,num_params", + 'qasm_gate,cirq_gate,num_params', [ (gate_map[0], gate_map[1], num_param) for gate_map, num_param in two_qubit_param_gates.items() @@ -979,7 +979,7 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate): def test_two_qubit_param_gates( qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate, num_params: int ): - params = "(0.1, 0.2, 0.3)" if num_params == 3 else "(0.1)" + params = '(0.1, 0.2, 0.3)' if num_params == 3 else '(0.1)' qasm = f""" OPENQASM 2.0; include "qelib1.inc"; @@ -991,10 +991,10 @@ def test_two_qubit_param_gates( """ parser = QasmParser() - q1_0 = cirq.NamedQubit("q1_0") - q1_1 = cirq.NamedQubit("q1_1") - q2_0 = cirq.NamedQubit("q2_0") - q2_1 = cirq.NamedQubit("q2_1") + q1_0 = cirq.NamedQubit('q1_0') + q1_1 = cirq.NamedQubit('q1_1') + q2_0 = cirq.NamedQubit('q2_0') + q2_1 = cirq.NamedQubit('q2_1') expected_circuit = cirq.Circuit() expected_circuit.append(cirq_gate.on(q1_0, q1_1)) @@ -1008,21 +1008,21 @@ def test_two_qubit_param_gates( assert parsed_qasm.qelib1Include ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit) - assert parsed_qasm.qregs == {"q1": 2, "q2": 2} + assert parsed_qasm.qregs == {'q1': 2, 'q2': 2} @pytest.mark.parametrize( - "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] + 'qasm_gate', [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] ) def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): - if qasm_gate in ("cu1", "crz"): + if qasm_gate in ('cu1', 'crz'): qasm = f""" OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; {qasm_gate}(0.1) q[0]; """ - elif qasm_gate == "cu3": + elif qasm_gate == 'cu3': qasm = f""" OPENQASM 2.0; include "qelib1.inc"; @@ -1043,7 +1043,7 @@ def test_two_qubit_gates_not_enough_qubits(qasm_gate: str): parser.parse(qasm) -@pytest.mark.parametrize("qasm_gate", [g[0] for g in two_qubit_param_gates.keys()]) +@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_param_gates.keys()]) def test_two_qubit_gates_not_enough_args(qasm_gate: str): qasm = f""" OPENQASM 2.0; @@ -1059,11 +1059,11 @@ def test_two_qubit_gates_not_enough_args(qasm_gate: str): @pytest.mark.parametrize( - "qasm_gate", [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] + 'qasm_gate', [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()] ) def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str): - if qasm_gate in ("cu1", "cu3", "crz"): - num_params_needed = 3 if qasm_gate == "cu3" else 1 + if qasm_gate in ('cu1', 'cu3', 'crz'): + num_params_needed = 3 if qasm_gate == 'cu3' else 1 else: num_params_needed = 0 From a27df98084ca044f707f9c276a54c9653739231c Mon Sep 17 00:00:00 2001 From: Bharath Date: Mon, 9 Dec 2024 12:08:47 -0600 Subject: [PATCH 13/13] update docs Signed-off-by: Bharath --- docs/build/interop.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/build/interop.ipynb b/docs/build/interop.ipynb index 26030a28c44..f38555e6fbd 100644 --- a/docs/build/interop.ipynb +++ b/docs/build/interop.ipynb @@ -315,9 +315,9 @@ "|`swap`|`cirq.SWAP`|| \n", "|`ccx`|`cirq.CCX`|| \n", "|`cswap`|`cirq.CSWAP`|| \n", - "|`crz`| NOT supported || \n", - "|`cu1`| NOT supported|| \n", - "|`cu3`| NOT supported|| \n", + "|`crz`|`cirq.ControlledGate(cirq.Rz(θ))`|| \n", + "|`cu1`|`cirq.ControlledGate(u3(0,0,λ))`|| \n", + "|`cu3`|`cirq.ControlledGate(u3(θ,φ,λ))`|| \n", "|`rzz`| NOT supported|| " ] },