I’m having some trouble with using private static methods in my class definitions to help break down the decomposition in a simpler way.
class U8Gate(Operation):
'''
U8 gate, an 82-parameter generalized 3-qubit gate.
'''
num_params = 1 # for pennylane internals, see nparams for actual number of parameters
nparams = 82 # number of parameters
num_wires = 3
grad_method = "A"
name = "U8"
def __init__(self, theta, wires):
if len(theta) != 82:
raise ValueError("U8gate expects 82 parameters")
super().__init__(theta, wires)
@staticmethod
def _ngate(theta, wires):
'''
Returns the N gate, a 3-parameter specialized 3-qubit gate.
'''
yield from [
qml.RZ(-pnp.pi/2, wires=wires[1]),
qml.Hadamard(wires=wires[2]),
qml.CNOT(wires=wires[1::-1]),
qml.CNOT(wires=wires[1:]),
qml.RY(2*theta[0], wires=wires[1]),
qml.CNOT(wires=wires[:2]),
qml.RY(-2*theta[1], wires=wires[1]),
qml.CNOT(wires=wires[:2]),
qml.CNOT(wires=wires[1:]),
qml.Hadamard(wires=wires[2]),
qml.RZ(pnp.pi/2, wires=wires[1]),
qml.CNOT(wires=wires[1::-1]),
qml.CNOT(wires=wires[::2]),
qml.CNOT(wires=wires[1:]),
qml.RZ(2*theta[2], wires=wires[2]),
qml.CNOT(wires=wires[1:]),
qml.CNOT(wires=wires[::2])
]
@staticmethod
def _mgate(theta, wires):
'''
Returns the M gate, a 4-parameter specialized 3-qubit gate.
'''
yield from [
qml.CNOT(wires=wires[2::-2]),
qml.CNOT(wires=wires[:2]),
qml.CNOT(wires=wires[2:0:-1]),
qml.RZ(-pnp.pi/2, wires=wires[2]),
qml.RY(2*theta[0], wires=wires[2]),
qml.CNOT(wires=wires[1:]),
qml.RY(-2*theta[1], wires=wires[2]),
qml.CNOT(wires=wires[1:]),
qml.RZ(pnp.pi/2, wires=wires[2]),
qml.CNOT(wires=wires[2::-2]),
qml.CNOT(wires=wires[:2]),
qml.CNOT(wires=wires[1::-1]),
qml.Hadamard(wires=wires[2]),
qml.CNOT(wires=wires[::2]),
qml.RZ(2*theta[2], wires=wires[2]),
qml.CNOT(wires=wires[::2]),
qml.RZ(2 * theta[3], wires=wires[2]),
qml.CNOT(wires=wires[1::-1]),
qml.Hadamard(wires=wires[2])
]
def decomposition(self):
'''
Returns the decomposition of the U8 gate, as described in https://doi.org/10.48550/arXiv.quant-ph/0401178
'''
theta = self.parameters[0]
wires = self.wires
yield from [
U4Gate(theta[:15], wires=wires[:2]),
qml.U3(theta[15], theta[16], theta[17], wires=wires[2]),
self._ngate(theta[18:21], wires=wires),
U4Gate(theta[21:36], wires=wires[:2]),
qml.U3(theta[36], theta[37], theta[38], wires=wires[2]),
self._mgate(theta[39:43], wires=wires),
U4Gate(theta[43:58], wires=wires[:2]),
qml.U3(theta[58], theta[59], theta[60], wires=wires[2]),
self._ngate(theta[61:64], wires=wires),
U4Gate(theta[64:79], wires=wires[:2]),
qml.U3(theta[79], theta[80], theta[81], wires=wires[2])
]
When i try to call this code in a circuit, i get an attribute error(generator has no attribute name) in this part of default_qubit.py:
def stopping_condition(op: qml.operation.Operator) -> bool:
"""Specify whether or not an Operator object is supported by the device."""
if op.name == "QFT" and len(op.wires) >= 6:
return False
if op.name == "GroverOperator" and len(op.wires) >= 13:
return False
if op.name == "Snapshot":
return True
if op.__class__.__name__ == "Pow" and qml.operation.is_trainable(op):
return False
return op.has_matrix
when op = <generator object U8Gate._ngate at 0x7f6c763ba150>
, since I haven’t written a whole different class for ngate and mgate. I’m wondering if this is intended behaviour since this is the only use of op.name i’ve seen in the source code like this, or if there’s a way to go about this without creating a whole new class.