Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix C3SXGate roundtrip in OpenQASM 2 #9183

Merged
merged 6 commits into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions qiskit/circuit/library/standard_gates/x.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,20 @@ def _define(self):

self.definition = qc

def qasm(self):
# Gross hack to override the Qiskit name with the name this gate has in Terra's version of
# 'qelib1.inc'. In general, the larger exporter mechanism should know about this to do the
# mapping itself, but right now that's not possible without a complete rewrite of the OQ2
# exporter code (low priority), or we would need to modify 'qelib1.inc' which would be
# needlessly disruptive this late in OQ2's lifecycle. The current OQ2 exporter _always_
# outputs the `include 'qelib1.inc' line. ---Jake, 2022-11-21.
try:
old_name = self.name
self.name = "c3sqrtx"
return super().qasm()
finally:
self.name = old_name
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved


class C3XGate(ControlledGate):
r"""The X gate controlled on 3 qubits.
Expand Down
2 changes: 1 addition & 1 deletion qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1638,7 +1638,7 @@ def qasm(
"rccx",
"rc3x",
"c3x",
"c3sx",
"c3sx", # This is the Qiskit gate name, but the qelib1.inc name is 'c3sqrtx'.
"c4x",
]

Expand Down
116 changes: 43 additions & 73 deletions qiskit/converters/ast_to_dag.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,42 +25,7 @@
from qiskit.circuit.reset import Reset
from qiskit.circuit.barrier import Barrier
from qiskit.circuit.delay import Delay
from qiskit.circuit.library.standard_gates.x import CCXGate
from qiskit.circuit.library.standard_gates.swap import CSwapGate
from qiskit.circuit.library.standard_gates.x import CXGate
from qiskit.circuit.library.standard_gates.y import CYGate
from qiskit.circuit.library.standard_gates.z import CZGate
from qiskit.circuit.library.standard_gates.swap import SwapGate
from qiskit.circuit.library.standard_gates.h import HGate
from qiskit.circuit.library.standard_gates.i import IGate
from qiskit.circuit.library.standard_gates.s import SGate
from qiskit.circuit.library.standard_gates.s import SdgGate
from qiskit.circuit.library.standard_gates.sx import SXGate
from qiskit.circuit.library.standard_gates.sx import SXdgGate
from qiskit.circuit.library.standard_gates.t import TGate
from qiskit.circuit.library.standard_gates.t import TdgGate
from qiskit.circuit.library.standard_gates.p import PhaseGate
from qiskit.circuit.library.standard_gates.u1 import U1Gate
from qiskit.circuit.library.standard_gates.u2 import U2Gate
from qiskit.circuit.library.standard_gates.u3 import U3Gate
from qiskit.circuit.library.standard_gates.u import UGate
from qiskit.circuit.library.standard_gates.x import XGate
from qiskit.circuit.library.standard_gates.y import YGate
from qiskit.circuit.library.standard_gates.z import ZGate
from qiskit.circuit.library.standard_gates.rx import RXGate
from qiskit.circuit.library.standard_gates.ry import RYGate
from qiskit.circuit.library.standard_gates.rz import RZGate
from qiskit.circuit.library.standard_gates.rxx import RXXGate
from qiskit.circuit.library.standard_gates.rzz import RZZGate
from qiskit.circuit.library.standard_gates.p import CPhaseGate
from qiskit.circuit.library.standard_gates.u import CUGate
from qiskit.circuit.library.standard_gates.u1 import CU1Gate
from qiskit.circuit.library.standard_gates.u3 import CU3Gate
from qiskit.circuit.library.standard_gates.h import CHGate
from qiskit.circuit.library.standard_gates.rx import CRXGate
from qiskit.circuit.library.standard_gates.ry import CRYGate
from qiskit.circuit.library.standard_gates.rz import CRZGate
from qiskit.circuit.library.standard_gates.sx import CSXGate
from qiskit.circuit.library import standard_gates as std


def ast_to_dag(ast):
Expand Down Expand Up @@ -105,43 +70,48 @@ class AstInterpreter:
"""Interprets an OpenQASM by expanding subroutines and unrolling loops."""

standard_extension = {
"u1": U1Gate,
"u2": U2Gate,
"u3": U3Gate,
"u": UGate,
"p": PhaseGate,
"x": XGate,
"y": YGate,
"z": ZGate,
"t": TGate,
"tdg": TdgGate,
"s": SGate,
"sdg": SdgGate,
"sx": SXGate,
"sxdg": SXdgGate,
"swap": SwapGate,
"rx": RXGate,
"rxx": RXXGate,
"ry": RYGate,
"rz": RZGate,
"rzz": RZZGate,
"id": IGate,
"h": HGate,
"cx": CXGate,
"cy": CYGate,
"cz": CZGate,
"ch": CHGate,
"crx": CRXGate,
"cry": CRYGate,
"crz": CRZGate,
"csx": CSXGate,
"cu1": CU1Gate,
"cp": CPhaseGate,
"cu": CUGate,
"cu3": CU3Gate,
"ccx": CCXGate,
"cswap": CSwapGate,
"u1": std.U1Gate,
"u2": std.U2Gate,
"u3": std.U3Gate,
"u": std.UGate,
"p": std.PhaseGate,
"x": std.XGate,
"y": std.YGate,
"z": std.ZGate,
"t": std.TGate,
"tdg": std.TdgGate,
"s": std.SGate,
"sdg": std.SdgGate,
"sx": std.SXGate,
"sxdg": std.SXdgGate,
"swap": std.SwapGate,
"rx": std.RXGate,
"rxx": std.RXXGate,
"ry": std.RYGate,
"rz": std.RZGate,
"rzz": std.RZZGate,
"id": std.IGate,
"h": std.HGate,
"cx": std.CXGate,
"cy": std.CYGate,
"cz": std.CZGate,
"ch": std.CHGate,
"crx": std.CRXGate,
"cry": std.CRYGate,
"crz": std.CRZGate,
"csx": std.CSXGate,
"cu1": std.CU1Gate,
"cp": std.CPhaseGate,
"cu": std.CUGate,
"cu3": std.CU3Gate,
"ccx": std.CCXGate,
"cswap": std.CSwapGate,
"delay": Delay,
"rccx": std.RCCXGate,
"rc3x": std.RC3XGate,
"c3x": std.C3XGate,
"c3sqrtx": std.C3SXGate,
"c4x": std.C4XGate,
}

def __init__(self, dag):
Expand Down Expand Up @@ -266,7 +236,7 @@ def _process_cnot(self, node):
)
maxidx = max([len(id0), len(id1)])
for idx in range(maxidx):
cx_gate = CXGate()
cx_gate = std.CXGate()
cx_gate.condition = self.condition
if len(id0) > 1 and len(id1) > 1:
self.dag.apply_operation_back(cx_gate, [id0[idx], id1[idx]], [])
Expand Down
5 changes: 5 additions & 0 deletions releasenotes/notes/fix-qasm2-c3sxgate-47171c9d17876219.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
fixes:
- |
Circuits containing :class:`.C3SXGate` can now be output and read in again safely from the
OpenQASM 2.0 exporter (:meth:`.QuantumCircuit.qasm`) and parser (:meth:`.QuantumCircuit.from_qasm_str`).
17 changes: 17 additions & 0 deletions test/python/circuit/test_circuit_qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit.test import QiskitTestCase
from qiskit.circuit import Parameter, Qubit, Clbit
from qiskit.circuit.library import C3SXGate
from qiskit.qasm.exceptions import QasmError

# Regex pattern to match valid OpenQASM identifiers
Expand Down Expand Up @@ -246,6 +247,22 @@ def test_circuit_qasm_with_composite_circuit_with_many_params_and_qubits(self):

self.assertEqual(original_str, qc.qasm())

def test_c3sxgate_roundtrips(self):
"""Test that C3SXGate correctly round trips. Qiskit gives this gate a different name
('c3sx') to the name in Qiskit's version of qelib1.inc ('c3sqrtx') gate, which can lead to
resolution issues."""
qc = QuantumCircuit(4)
qc.append(C3SXGate(), qc.qubits, [])
qasm = qc.qasm()
expected = """OPENQASM 2.0;
include "qelib1.inc";
qreg q[4];
c3sqrtx q[0],q[1],q[2],q[3];
"""
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
self.assertEqual(qasm, expected)
parsed = QuantumCircuit.from_qasm_str(qasm)
self.assertIsInstance(parsed.data[0].operation, C3SXGate)
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved

def test_unbound_circuit_raises(self):
"""Test circuits with unbound parameters raises."""
qc = QuantumCircuit(1)
Expand Down