#
# Copyright © 2022-2023 University of Strasbourg. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import mimiqcircuits.operations.control as mctrl
from mimiqcircuits.operations.gates.standard.cpauli import GateCX
from mimiqcircuits.operations.gates.standard.u import GateU
from mimiqcircuits.operations.gates.standard.phase import GateP
[docs]
class GateCU(mctrl.Control):
r"""Two qubit controlled unitary gate.
**Matrix representation:**
.. math::
\operatorname{CU}(\theta, \phi, \lambda, \gamma) = \frac{1}{2} e^{i\gamma} \begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & e^{i\gamma} \cos\left(\frac{\theta}{2}\right) & -e^{i\gamma} e^{i\lambda}\sin\left(\frac{\theta}{2}\right) \\
0 & 0 & e^{i\gamma} \mathrm{e}^{i\phi}\sin\left(\frac{\theta}{2}\right) & e^{i\gamma} \mathrm{e}^{i(\phi+\lambda)}\cos\left(\frac{\theta}{2}\right)
\end{pmatrix}
Parameters:
theta (float): Euler angle 1 in radians.
phi (float): Euler angle 2 in radians.
lmbda (float): Euler angle 3 in radians.
gamma (float): Global phase of the CU gate.
Examples:
>>> from mimiqcircuits import *
>>> from symengine import *
>>> theta, phi, lmbda, gamma = symbols('theta phi lambda gamma')
>>> GateCU(theta, phi, lmbda, gamma), GateCU(theta, phi, lmbda, gamma).num_controls, GateCU(theta, phi, lmbda, gamma).num_targets, GateCU(theta, phi, lmbda, gamma).num_qubits
(CU(theta, phi, lambda, gamma), 1, 1, 2)
>>> GateCU(theta, phi, lmbda, gamma).matrix()
[1.0, 0, 0, 0]
[0, 1.0, 0, 0]
[0, 0, exp(I*gamma)*cos((1/2)*theta), -exp(I*(gamma + lambda))*sin((1/2)*theta)]
[0, 0, exp(I*(gamma + phi))*sin((1/2)*theta), exp(I*(gamma + lambda + phi))*cos((1/2)*theta)]
<BLANKLINE>
>>> c = Circuit().push(GateCU(theta, phi, lmbda, gamma), 0, 1)
>>> c
2-qubit circuit with 1 instructions:
└── CU(theta, phi, lambda, gamma) @ q[0], q[1]
<BLANKLINE>
>>> GateCU(theta, phi, lmbda, gamma).power(2), GateCU(theta, phi, lmbda, gamma).inverse()
(C(U(theta, phi, lambda, gamma)**2), CU(-theta, -lambda, -phi, -gamma))
>>> GateCU(theta, phi, lmbda, gamma).decompose()
2-qubit circuit with 7 instructions:
├── P(gamma) @ q[0]
├── P((1/2)*(lambda + phi)) @ q[0]
├── P((1/2)*(lambda - phi)) @ q[1]
├── CX @ q[0], q[1]
├── U((-1/2)*theta, 0, (-1/2)*(lambda + phi), 0.0) @ q[1]
├── CX @ q[0], q[1]
└── U((1/2)*theta, phi, 0, 0.0) @ q[1]
<BLANKLINE>
"""
def __init__(self, *args, **kwargs):
super().__init__(1, GateU(*args, **kwargs))
self.theta = args[0]
self.phi = args[1]
self.lmbda = args[2]
self.gamma = args[3]
def _decompose(self, circ, qubits, bits):
c, t = qubits
theta = self.op.theta
phi = self.op.phi
lmbda = self.op.lmbda
gamma = self.op.gamma
circ.push(GateP(gamma), c)
circ.push(GateP((lmbda + phi) / 2), c)
circ.push(GateP((lmbda - phi) / 2), t)
circ.push(GateCX(), c, t)
circ.push(GateU(-theta / 2, 0, -(lmbda + phi) / 2), t)
circ.push(GateCX(), c, t)
circ.push(GateU(theta / 2, phi, 0), t)
return circ