mirror of https://github.com/Qiskit/qiskit.git
ast_to_dag support for opaque gates (#2343)
* support for opaque gates * custom gate * cleaning up * remove test_custom_gate * lint * lint! * do not process standard lib
This commit is contained in:
parent
43cbe08f71
commit
8aa1081515
|
@ -18,8 +18,7 @@ AST (abstract syntax tree) to DAG (directed acyclic graph) converter.
|
|||
Acts as an OpenQASM interpreter.
|
||||
"""
|
||||
from collections import OrderedDict
|
||||
from qiskit.circuit import QuantumRegister
|
||||
from qiskit.circuit import ClassicalRegister
|
||||
from qiskit.circuit import QuantumRegister, ClassicalRegister, Gate
|
||||
from qiskit.dagcircuit import DAGCircuit
|
||||
from qiskit.exceptions import QiskitError
|
||||
|
||||
|
@ -78,6 +77,34 @@ def ast_to_dag(ast):
|
|||
class AstInterpreter:
|
||||
"""Interprets an OpenQASM by expanding subroutines and unrolling loops."""
|
||||
|
||||
standard_extension = {"u0": U0Gate,
|
||||
"u1": U1Gate,
|
||||
"u2": U2Gate,
|
||||
"u3": U3Gate,
|
||||
"x": XGate,
|
||||
"y": YGate,
|
||||
"z": ZGate,
|
||||
"t": TGate,
|
||||
"tdg": TdgGate,
|
||||
"s": SGate,
|
||||
"sdg": SdgGate,
|
||||
"swap": SwapGate,
|
||||
"rx": RXGate,
|
||||
"ry": RYGate,
|
||||
"rz": RZGate,
|
||||
"rzz": RZZGate,
|
||||
"id": IdGate,
|
||||
"h": HGate,
|
||||
"cx": CnotGate,
|
||||
"cy": CyGate,
|
||||
"cz": CzGate,
|
||||
"ch": CHGate,
|
||||
"crz": CrzGate,
|
||||
"cu1": Cu1Gate,
|
||||
"cu3": Cu3Gate,
|
||||
"ccx": ToffoliGate,
|
||||
"cswap": FredkinGate}
|
||||
|
||||
def __init__(self, dag):
|
||||
"""Initialize interpreter's data."""
|
||||
# DAG object to populate
|
||||
|
@ -144,7 +171,7 @@ class AstInterpreter:
|
|||
self.arg_stack.append({gargs[j]: args[j]
|
||||
for j in range(len(gargs))})
|
||||
# Only index into register arguments.
|
||||
element = [idx*x for x in
|
||||
element = [idx * x for x in
|
||||
[len(bits[j]) > 1 for j in range(len(bits))]]
|
||||
self.bit_stack.append({gbits[j]: bits[j][element[j]]
|
||||
for j in range(len(gbits))})
|
||||
|
@ -173,6 +200,8 @@ class AstInterpreter:
|
|||
else:
|
||||
de_gate["args"] = []
|
||||
de_gate["bits"] = [c.name for c in node.bitlist.children]
|
||||
if node.name in self.standard_extension:
|
||||
return
|
||||
if opaque:
|
||||
de_gate["body"] = None
|
||||
else:
|
||||
|
@ -182,7 +211,7 @@ class AstInterpreter:
|
|||
"""Process a CNOT gate node."""
|
||||
id0 = self._process_bit_id(node.children[0])
|
||||
id1 = self._process_bit_id(node.children[1])
|
||||
if not(len(id0) == len(id1) or len(id0) == 1 or len(id1) == 1):
|
||||
if not (len(id0) == len(id1) or len(id0) == 1 or len(id1) == 1):
|
||||
raise QiskitError("internal error: qreg size mismatch",
|
||||
"line=%s" % node.line, "file=%s" % node.file)
|
||||
maxidx = max([len(id0), len(id1)])
|
||||
|
@ -322,63 +351,17 @@ class AstInterpreter:
|
|||
Raises:
|
||||
QiskitError: if encountering a non-basis opaque gate
|
||||
"""
|
||||
if name == "u0":
|
||||
op_class = U0Gate
|
||||
elif name == "u1":
|
||||
op_class = U1Gate
|
||||
elif name == "u2":
|
||||
op_class = U2Gate
|
||||
elif name == "u3":
|
||||
op_class = U3Gate
|
||||
elif name == "x":
|
||||
op_class = XGate
|
||||
elif name == "y":
|
||||
op_class = YGate
|
||||
elif name == "z":
|
||||
op_class = ZGate
|
||||
elif name == "t":
|
||||
op_class = TGate
|
||||
elif name == "tdg":
|
||||
op_class = TdgGate
|
||||
elif name == "s":
|
||||
op_class = SGate
|
||||
elif name == "sdg":
|
||||
op_class = SdgGate
|
||||
elif name == "swap":
|
||||
op_class = SwapGate
|
||||
elif name == "rx":
|
||||
op_class = RXGate
|
||||
elif name == "ry":
|
||||
op_class = RYGate
|
||||
elif name == "rz":
|
||||
op_class = RZGate
|
||||
elif name == "rzz":
|
||||
op_class = RZZGate
|
||||
elif name == "id":
|
||||
op_class = IdGate
|
||||
elif name == "h":
|
||||
op_class = HGate
|
||||
elif name == "cx":
|
||||
op_class = CnotGate
|
||||
elif name == "cy":
|
||||
op_class = CyGate
|
||||
elif name == "cz":
|
||||
op_class = CzGate
|
||||
elif name == "ch":
|
||||
op_class = CHGate
|
||||
elif name == "crz":
|
||||
op_class = CrzGate
|
||||
elif name == "cu1":
|
||||
op_class = Cu1Gate
|
||||
elif name == "cu3":
|
||||
op_class = Cu3Gate
|
||||
elif name == "ccx":
|
||||
op_class = ToffoliGate
|
||||
elif name == "cswap":
|
||||
op_class = FredkinGate
|
||||
|
||||
if name in self.standard_extension:
|
||||
op = self.standard_extension[name](*params)
|
||||
elif name in self.gates:
|
||||
if self.gates[name]['opaque']:
|
||||
# call an opaque gate
|
||||
op = Gate(name=name, num_qubits=self.gates[name]['n_bits'], params=params)
|
||||
else:
|
||||
# call a custom gate
|
||||
raise QiskitError('Custom non-opaque gates are not supported by as_to_dag module')
|
||||
else:
|
||||
raise QiskitError("unknown operation for ast node name %s" % name)
|
||||
|
||||
op = op_class(*params)
|
||||
|
||||
self.dag.apply_operation_back(op, qargs, [], condition=self.condition)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
from qiskit import QiskitError
|
||||
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
||||
from qiskit.circuit import Gate
|
||||
from qiskit.test import QiskitTestCase, Path
|
||||
|
||||
|
||||
|
@ -123,6 +124,23 @@ class LoadFromQasmTest(QiskitTestCase):
|
|||
self.assertEqual(len(q_circuit.qregs), 1)
|
||||
self.assertEqual(q_circuit, ref)
|
||||
|
||||
def test_opaque_gate(self):
|
||||
"""Test parse an opaque gate
|
||||
See https://github.com/Qiskit/qiskit-terra/issues/1566"""
|
||||
|
||||
qasm_string = '\n'.join(["OPENQASM 2.0;",
|
||||
"include \"qelib1.inc\";",
|
||||
"opaque my_gate(theta,phi,lambda) a,b;",
|
||||
"qreg q[3];",
|
||||
"my_gate(1,2,3) q[1],q[2];"]) + '\n'
|
||||
circuit = QuantumCircuit.from_qasm_str(qasm_string)
|
||||
|
||||
qr = QuantumRegister(3, 'q')
|
||||
expected = QuantumCircuit(qr)
|
||||
expected.append(Gate(name='my_gate', num_qubits=2, params=[1, 2, 3]), [qr[1], qr[2]])
|
||||
|
||||
self.assertEqual(circuit, expected)
|
||||
|
||||
def test_qasm_example_file(self):
|
||||
"""Loads qasm/example.qasm.
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue