Source code for qiskit.circuit.library.standard_gates.u3

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Two-pulse single-qubit gate."""

import numpy
from qiskit.circuit.controlledgate import ControlledGate
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister


[docs]class U3Gate(Gate): r"""Generic single-qubit rotation gate with 3 Euler angles. Implemented using two X90 pulses on IBM Quantum systems: .. math:: U3(\theta, \phi, \lambda) = RZ(\phi - \pi/2) RX(\pi/2) RZ(\pi - \theta) RX(\pi/2) RZ(\lambda - \pi/2) **Circuit symbol:** .. parsed-literal:: ┌───────────┐ q_0: ┤ U3(ϴ,φ,λ) ├ └───────────┘ **Matrix Representation:** .. math:: \newcommand{\th}{\frac{\theta}{2}} U3(\theta, \phi, \lambda) = \begin{pmatrix} \cos(\th) & -e^{i\lambda}\sin(\th) \\ e^{i\phi}\sin(\th) & e^{i(\phi+\lambda)}\cos(\th) \end{pmatrix} **Examples:** .. math:: U3(\theta, -\frac{\pi}{2}, \frac{pi}{2}) = RX(\theta) .. math:: U3(\theta, 0, 0) = RY(\theta) """ def __init__(self, theta, phi, lam, label=None): """Create new U3 gate.""" super().__init__('u3', 1, [theta, phi, lam], label=label)
[docs] def inverse(self): r"""Return inverted U3 gate. :math:`U3(\theta,\phi,\lambda)^{\dagger} =U3(-\theta,-\phi,-\lambda)`) """ return U3Gate(-self.params[0], -self.params[2], -self.params[1])
[docs] def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-U3 gate. Args: num_ctrl_qubits (int): number of control qubits. label (str or None): An optional label for the gate [Default: None] ctrl_state (int or str or None): control state expressed as integer, string (e.g. '110'), or None. If None, use all 1s. Returns: ControlledGate: controlled version of this gate. """ if num_ctrl_qubits == 1: gate = CU3Gate(*self.params, label=label, ctrl_state=ctrl_state) gate.base_gate.label = self.label return gate return super().control(num_ctrl_qubits=num_ctrl_qubits, label=label, ctrl_state=ctrl_state)
[docs] def to_matrix(self): """Return a Numpy.array for the U3 gate.""" theta, phi, lam = self.params theta, phi, lam = float(theta), float(phi), float(lam) return numpy.array([ [ numpy.cos(theta / 2), -numpy.exp(1j * lam) * numpy.sin(theta / 2) ], [ numpy.exp(1j * phi) * numpy.sin(theta / 2), numpy.exp(1j * (phi + lam)) * numpy.cos(theta / 2) ] ], dtype=complex)
class CU3Meta(type): """A metaclass to ensure that Cu3Gate and CU3Gate are of the same type. Can be removed when Cu3Gate gets removed. """ @classmethod def __instancecheck__(mcs, inst): return type(inst) in {CU3Gate, Cu3Gate} # pylint: disable=unidiomatic-typecheck
[docs]class CU3Gate(ControlledGate, metaclass=CU3Meta): r"""Controlled-U3 gate (3-parameter two-qubit gate). This is a controlled version of the U3 gate (generic single qubit rotation). It is restricted to 3 parameters, and so cannot cover generic two-qubit controlled gates). **Circuit symbol:** .. parsed-literal:: q_0: ──────■────── ┌─────┴─────┐ q_1: ┤ U3(ϴ,φ,λ) ├ └───────────┘ **Matrix representation:** .. math:: \newcommand{\th}{\frac{\theta}{2}} CU3(\theta, \phi, \lambda)\ q_0, q_1 = I \otimes |0\rangle\langle 0| + U3(\theta,\phi,\lambda) \otimes |1\rangle\langle 1| = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\th) & 0 & e^{-i\lambda}\sin(\th) \\ 0 & 0 & 1 & 0 \\ 0 & e^{i\phi}\sin(\th) & 0 & e^{i(\phi+\lambda)\cos(\th)} \end{pmatrix} .. note:: In Qiskit's convention, higher qubit indices are more significant (little endian convention). In many textbooks, controlled gates are presented with the assumption of more significant qubits as control, which in our case would be q_1. Thus a textbook matrix for this gate will be: .. parsed-literal:: ┌───────────┐ q_0: ┤ U3(ϴ,φ,λ) ├ └─────┬─────┘ q_1: ──────■────── .. math:: CU3(\theta, \phi, \lambda)\ q_1, q_0 = |0\rangle\langle 0| \otimes I + |1\rangle\langle 1| \otimes U3(\theta,\phi,\lambda) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \cos(\th) & e^{-i\lambda}\sin(\th) \\ 0 & 0 & e^{i\phi}\sin(\th) & e^{i(\phi+\lambda)\cos(\th)} \end{pmatrix} """ def __init__(self, theta, phi, lam, label=None, ctrl_state=None): """Create new CU3 gate.""" super().__init__('cu3', 2, [theta, phi, lam], num_ctrl_qubits=1, label=label, ctrl_state=ctrl_state) self.base_gate = U3Gate(theta, phi, lam) def _define(self): """ gate cu3(theta,phi,lambda) c, t { u1((lambda+phi)/2) c; u1((lambda-phi)/2) t; cx c,t; u3(-theta/2,0,-(phi+lambda)/2) t; cx c,t; u3(theta/2,phi,0) t; } """ from .u1 import U1Gate from .x import CXGate # pylint: disable=cyclic-import definition = [] q = QuantumRegister(2, 'q') rule = [ (U1Gate((self.params[2] + self.params[1]) / 2), [q[0]], []), (U1Gate((self.params[2] - self.params[1]) / 2), [q[1]], []), (CXGate(), [q[0], q[1]], []), (U3Gate(-self.params[0] / 2, 0, -(self.params[1] + self.params[2]) / 2), [q[1]], []), (CXGate(), [q[0], q[1]], []), (U3Gate(self.params[0] / 2, self.params[1], 0), [q[1]], []) ] for inst in rule: definition.append(inst) self.definition = definition
[docs] def inverse(self): r"""Return inverted CU3 gate. :math:`CU3(\theta,\phi,\lambda)^{\dagger} =CU3(-\theta,-\phi,-\lambda)`) """ return CU3Gate(-self.params[0], -self.params[2], -self.params[1])
class Cu3Gate(CU3Gate, metaclass=CU3Meta): """The deprecated CU3Gate class.""" def __init__(self, theta, phi, lam): import warnings warnings.warn('The class Cu3Gate is deprecated as of 0.14.0, and ' 'will be removed no earlier than 3 months after that release date. ' 'You should use the class CU3Gate instead.', DeprecationWarning, stacklevel=2) super().__init__(theta, phi, lam) def _generate_gray_code(num_bits): """Generate the gray code for ``num_bits`` bits.""" if num_bits <= 0: raise ValueError('Cannot generate the gray code for less than 1 bit.') result = [0] for i in range(num_bits): result += [x + 2**i for x in reversed(result)] return [format(x, '0%sb' % num_bits) for x in result] def _gray_code_chain(q, num_ctrl_qubits, gate): """Apply the gate to the the last qubit in the register ``q``, controlled on all preceding qubits. This function uses the gray code to propagate down to the last qubit. Ported and adapted from Aqua (github.com/Qiskit/qiskit-aqua), commit 769ca8d, file qiskit/aqua/circuits/gates/multi_control_u1_gate.py. """ from .x import CXGate rule = [] q_controls, q_target = q[:num_ctrl_qubits], q[num_ctrl_qubits] gray_code = _generate_gray_code(num_ctrl_qubits) last_pattern = None for pattern in gray_code: if '1' not in pattern: continue if last_pattern is None: last_pattern = pattern # find left most set bit lm_pos = list(pattern).index('1') # find changed bit comp = [i != j for i, j in zip(pattern, last_pattern)] if True in comp: pos = comp.index(True) else: pos = None if pos is not None: if pos != lm_pos: rule.append( (CXGate(), [q_controls[pos], q_controls[lm_pos]], []) ) else: indices = [i for i, x in enumerate(pattern) if x == '1'] for idx in indices[1:]: rule.append( (CXGate(), [q_controls[idx], q_controls[lm_pos]], []) ) # check parity if pattern.count('1') % 2 == 0: # inverse rule.append( (gate.inverse(), [q_controls[lm_pos], q_target], []) ) else: rule.append( (gate, [q_controls[lm_pos], q_target], []) ) last_pattern = pattern return rule