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:
Luciano 2019-05-10 08:04:25 -04:00 committed by GitHub
parent 43cbe08f71
commit 8aa1081515
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 60 deletions

View File

@ -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)

View File

@ -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.
"""