Skip to content

Commit e9fbabc

Browse files
Support "cu1", "cu3", and "crz" in QasmParser (#6820)
1 parent def1b08 commit e9fbabc

File tree

3 files changed

+128
-20
lines changed

3 files changed

+128
-20
lines changed

cirq-core/cirq/contrib/qasm_import/_parser.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,24 @@ def __init__(self) -> None:
243243
'ch': QasmGateStatement(
244244
qasm_gate='ch', cirq_gate=ops.ControlledGate(ops.H), num_params=0, num_args=2
245245
),
246+
'cu1': QasmGateStatement(
247+
qasm_gate='cu1',
248+
num_params=1,
249+
num_args=2,
250+
cirq_gate=(lambda params: ops.ControlledGate(QasmUGate(0, 0, params[0] / np.pi))),
251+
),
252+
'cu3': QasmGateStatement(
253+
qasm_gate='cu3',
254+
num_params=3,
255+
num_args=2,
256+
cirq_gate=(lambda params: ops.ControlledGate(QasmUGate(*[p / np.pi for p in params]))),
257+
),
258+
'crz': QasmGateStatement(
259+
qasm_gate='crz',
260+
num_params=1,
261+
num_args=2,
262+
cirq_gate=(lambda params: ops.ControlledGate(ops.rz(params[0]))),
263+
),
246264
'swap': QasmGateStatement(qasm_gate='swap', cirq_gate=ops.SWAP, num_params=0, num_args=2),
247265
'cswap': QasmGateStatement(
248266
qasm_gate='cswap', num_params=0, num_args=3, cirq_gate=ops.CSWAP

cirq-core/cirq/contrib/qasm_import/_parser_test.py

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -924,16 +924,24 @@ def test_standard_gates_wrong_params_error(qasm_gate: str, num_params: int):
924924
]
925925

926926

927+
# Mapping of two-qubit gates and `num_params`
928+
two_qubit_param_gates = {
929+
('cu1', cirq.ControlledGate(QasmUGate(0, 0, 0.1 / np.pi))): 1,
930+
('cu3', cirq.ControlledGate(QasmUGate(0.1 / np.pi, 0.2 / np.pi, 0.3 / np.pi))): 3,
931+
('crz', cirq.ControlledGate(cirq.rz(0.1))): 1,
932+
}
933+
934+
927935
@pytest.mark.parametrize('qasm_gate,cirq_gate', two_qubit_gates)
928936
def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate):
929937
qasm = f"""
930-
OPENQASM 2.0;
931-
include "qelib1.inc";
932-
qreg q1[2];
933-
qreg q2[2];
934-
{qasm_gate} q1[0], q1[1];
935-
{qasm_gate} q1, q2[0];
936-
{qasm_gate} q2, q1;
938+
OPENQASM 2.0;
939+
include "qelib1.inc";
940+
qreg q1[2];
941+
qreg q2[2];
942+
{qasm_gate} q1[0], q1[1];
943+
{qasm_gate} q1, q2[0];
944+
{qasm_gate} q2, q1;
937945
"""
938946
parser = QasmParser()
939947

@@ -961,11 +969,85 @@ def test_two_qubit_gates(qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate):
961969
assert parsed_qasm.qregs == {'q1': 2, 'q2': 2}
962970

963971

964-
@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates])
972+
@pytest.mark.parametrize(
973+
'qasm_gate,cirq_gate,num_params',
974+
[
975+
(gate_map[0], gate_map[1], num_param)
976+
for gate_map, num_param in two_qubit_param_gates.items()
977+
],
978+
)
979+
def test_two_qubit_param_gates(
980+
qasm_gate: str, cirq_gate: cirq.testing.TwoQubitGate, num_params: int
981+
):
982+
params = '(0.1, 0.2, 0.3)' if num_params == 3 else '(0.1)'
983+
qasm = f"""
984+
OPENQASM 2.0;
985+
include "qelib1.inc";
986+
qreg q1[2];
987+
qreg q2[2];
988+
{qasm_gate}{params} q1[0], q1[1];
989+
{qasm_gate}{params} q1, q2[0];
990+
{qasm_gate}{params} q2, q1;
991+
"""
992+
parser = QasmParser()
993+
994+
q1_0 = cirq.NamedQubit('q1_0')
995+
q1_1 = cirq.NamedQubit('q1_1')
996+
q2_0 = cirq.NamedQubit('q2_0')
997+
q2_1 = cirq.NamedQubit('q2_1')
998+
999+
expected_circuit = cirq.Circuit()
1000+
expected_circuit.append(cirq_gate.on(q1_0, q1_1))
1001+
expected_circuit.append(cirq_gate.on(q1_0, q2_0))
1002+
expected_circuit.append(cirq_gate.on(q1_1, q2_0))
1003+
expected_circuit.append(cirq_gate.on(q2_0, q1_0))
1004+
expected_circuit.append(cirq_gate.on(q2_1, q1_1))
1005+
parsed_qasm = parser.parse(qasm)
1006+
1007+
assert parsed_qasm.supportedFormat
1008+
assert parsed_qasm.qelib1Include
1009+
1010+
ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit)
1011+
assert parsed_qasm.qregs == {'q1': 2, 'q2': 2}
1012+
1013+
1014+
@pytest.mark.parametrize(
1015+
'qasm_gate', [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()]
1016+
)
1017+
def test_two_qubit_gates_not_enough_qubits(qasm_gate: str):
1018+
if qasm_gate in ('cu1', 'crz'):
1019+
qasm = f"""
1020+
OPENQASM 2.0;
1021+
include "qelib1.inc";
1022+
qreg q[2];
1023+
{qasm_gate}(0.1) q[0];
1024+
"""
1025+
elif qasm_gate == 'cu3':
1026+
qasm = f"""
1027+
OPENQASM 2.0;
1028+
include "qelib1.inc";
1029+
qreg q[2];
1030+
{qasm_gate}(0.1, 0.2, 0.3) q[0];
1031+
"""
1032+
else:
1033+
qasm = f"""
1034+
OPENQASM 2.0;
1035+
include "qelib1.inc";
1036+
qreg q[2];
1037+
{qasm_gate} q[0];
1038+
"""
1039+
1040+
parser = QasmParser()
1041+
1042+
with pytest.raises(QasmException, match=rf".*{qasm_gate}.* takes 2 arg\(s\).*got.*1.*line 5"):
1043+
parser.parse(qasm)
1044+
1045+
1046+
@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_param_gates.keys()])
9651047
def test_two_qubit_gates_not_enough_args(qasm_gate: str):
9661048
qasm = f"""
967-
OPENQASM 2.0;
968-
include "qelib1.inc";
1049+
OPENQASM 2.0;
1050+
include "qelib1.inc";
9691051
qreg q[2];
9701052
{qasm_gate} q[0];
9711053
"""
@@ -976,19 +1058,27 @@ def test_two_qubit_gates_not_enough_args(qasm_gate: str):
9761058
parser.parse(qasm)
9771059

9781060

979-
@pytest.mark.parametrize('qasm_gate', [g[0] for g in two_qubit_gates])
1061+
@pytest.mark.parametrize(
1062+
'qasm_gate', [g[0] for g in two_qubit_gates] + [g[0] for g in two_qubit_param_gates.keys()]
1063+
)
9801064
def test_two_qubit_gates_with_too_much_parameters(qasm_gate: str):
1065+
if qasm_gate in ('cu1', 'cu3', 'crz'):
1066+
num_params_needed = 3 if qasm_gate == 'cu3' else 1
1067+
else:
1068+
num_params_needed = 0
1069+
9811070
qasm = f"""
982-
OPENQASM 2.0;
983-
include "qelib1.inc";
984-
qreg q[2];
985-
{qasm_gate}(pi) q[0],q[1];
986-
"""
1071+
OPENQASM 2.0;
1072+
include "qelib1.inc";
1073+
qreg q[2];
1074+
{qasm_gate}(pi, pi/2, pi/3, pi/4) q[0],q[1];
1075+
"""
9871076

9881077
parser = QasmParser()
9891078

9901079
with pytest.raises(
991-
QasmException, match=rf".*{qasm_gate}.* takes 0 parameter\(s\).*got.*1.*line 5"
1080+
QasmException,
1081+
match=rf".*{qasm_gate}*. takes {num_params_needed} parameter\(s\).*got.*4.*line 5",
9921082
):
9931083
parser.parse(qasm)
9941084

docs/build/interop.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,9 @@
315315
"|`swap`|`cirq.SWAP`|| \n",
316316
"|`ccx`|`cirq.CCX`|| \n",
317317
"|`cswap`|`cirq.CSWAP`|| \n",
318-
"|`crz`| NOT supported || \n",
319-
"|`cu1`| NOT supported|| \n",
320-
"|`cu3`| NOT supported|| \n",
318+
"|`crz`|`cirq.ControlledGate(cirq.Rz(θ))`|| \n",
319+
"|`cu1`|`cirq.ControlledGate(u3(0,0,λ))`|| \n",
320+
"|`cu3`|`cirq.ControlledGate(u3(θ,φ,λ))`|| \n",
321321
"|`rzz`| NOT supported|| "
322322
]
323323
},

0 commit comments

Comments
 (0)