Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions qiskit/circuit/gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

"""Unitary gate."""

import math
import cmath
from typing import List, Optional, Union, Tuple
import numpy as np
from scipy.linalg import schur
Expand All @@ -26,27 +28,46 @@ class Gate(Instruction):
"""Unitary gate."""

def __init__(self, name: str, num_qubits: int, params: List,
phase: Optional[float] = 0,
label: Optional[str] = None) -> None:
"""Create a new gate.

Args:
name: The Qobj name of the gate.
num_qubits: The number of qubits the gate acts on.
params: A list of parameters.
phase: Phase of the gate.
label: An optional label for the gate.
"""
self._phase = phase
self._label = label
self.definition = None
super().__init__(name, num_qubits, 0, params)

def _matrix_definition(self):
"""Return the canonical matrix definition of the gate with phase = 0."""
# This should be set in classes that derive from Gate.
return None

def to_matrix(self) -> np.ndarray:
"""Return a Numpy.array for the gate unitary matrix.

Returns:
np.ndarray: the matrix representaiton of the gate.

Raises:
CircuitError: If a Gate subclass does not implement this method an
exception will be raised when this base class method is called.
CircuitError: If a Gate subclass does not have a _matrix_definition.
"""
raise CircuitError("to_matrix not defined for this {}".format(type(self)))
# pylint: disable=assignment-from-none
mat = self._matrix_definition()
if mat is None:
raise CircuitError("to_matrix not defined for this {}".format(type(self)))
# Call float to enable conversion of bound ParameterExpressions
phase = float(self._phase)
if phase == 0:
# Case for default value to avoid numerical error
return mat
return cmath.exp(1j * phase) * mat

def power(self, exponent: float):
"""Creates a unitary gate as `gate^exponent`.
Expand Down Expand Up @@ -80,7 +101,7 @@ def power(self, exponent: float):

def _return_repeat(self, exponent: float) -> 'Gate':
return Gate(name="%s*%s" % (self.name, exponent), num_qubits=self.num_qubits,
params=self.params)
params=self.params, phase=exponent * self._phase)

def assemble(self) -> 'Instruction':
"""Assemble a QasmQobjInstruction"""
Expand All @@ -89,6 +110,23 @@ def assemble(self) -> 'Instruction':
instruction.label = self.label
return instruction

@property
def phase(self) -> float:
"""Return the phase of the gate."""
return self._phase

@phase.setter
def phase(self, angle: float):
"""Set the phase of the gate."""
# Set the phase to the [-2 * pi, 2 * pi] interval
angle = float(angle)
if not angle:
self._phase = 0
elif angle < 0:
self._phase = angle % (-2 * math.pi)
else:
self._phase = angle % (2 * math.pi)

@property
def label(self) -> str:
"""Return gate label"""
Expand Down
16 changes: 6 additions & 10 deletions qiskit/circuit/library/standard_gates/r.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,30 @@
class RGate(Gate):
"""Rotation θ around the cos(φ)x + sin(φ)y axis."""

def __init__(self, theta, phi):
def __init__(self, theta, phi, phase=0):
"""Create new r single-qubit gate."""
super().__init__('r', 1, [theta, phi])
super().__init__('r', 1, [theta, phi], phase=phase)

def _define(self):
"""
gate r(θ, φ) a {u3(θ, φ - π/2, -φ + π/2) a;}
"""
from .u3 import U3Gate
definition = []
q = QuantumRegister(1, 'q')
theta = self.params[0]
phi = self.params[1]
rule = [
(U3Gate(theta, phi - pi / 2, -phi + pi / 2), [q[0]], [])
self.definition = [
(U3Gate(theta, phi - pi / 2, -phi + pi / 2, phase=self.phase), [q[0]], [])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont think it is a good idea to make phase change. For R it is defined with phase 0

]
for inst in rule:
definition.append(inst)
self.definition = definition

def inverse(self):
"""Invert this gate.

r(θ, φ)^dagger = r(-θ, φ)
"""
return RGate(-self.params[0], self.params[1])
return RGate(-self.params[0], self.params[1], phase=-self.phase)

def to_matrix(self):
def _matrix_definition(self):
"""Return a numpy.array for the R gate."""
cos = math.cos(self.params[0] / 2)
sin = math.sin(self.params[0] / 2)
Expand Down
18 changes: 7 additions & 11 deletions qiskit/circuit/library/standard_gates/rx.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,19 @@ class RXGate(Gate):
\end{pmatrix}
"""

def __init__(self, theta, label=None):
def __init__(self, theta, phase=0, label=None):
"""Create new RX gate."""
super().__init__('rx', 1, [theta], label=label)
super().__init__('rx', 1, [theta], phase=phase, label=label)

def _define(self):
"""
gate rx(theta) a {r(theta, 0) a;}
"""
from .r import RGate
definition = []
q = QuantumRegister(1, 'q')
rule = [
(RGate(self.params[0], 0), [q[0]], [])
self.definition = [
(RGate(self.params[0], 0, phase=self.phase), [q[0]], [])
]
for inst in rule:
definition.append(inst)
self.definition = definition

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Return a (mutli-)controlled-RX gate.
Expand All @@ -76,7 +72,7 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
Returns:
ControlledGate: controlled version of this gate.
"""
if num_ctrl_qubits == 1:
if num_ctrl_qubits == 1 and self.phase == 0:
gate = CRXGate(self.params[0], label=label, ctrl_state=ctrl_state)
gate.base_gate.label = self.label
return gate
Expand All @@ -87,9 +83,9 @@ def inverse(self):

:math:`RX(\lambda)^{\dagger} = RX(-\lambda)`
"""
return RXGate(-self.params[0])
return RXGate(-self.params[0], phase=-self.phase)

def to_matrix(self):
def _matrix_definition(self):
"""Return a numpy.array for the RX gate."""
cos = math.cos(self.params[0] / 2)
sin = math.sin(self.params[0] / 2)
Expand Down
2 changes: 1 addition & 1 deletion qiskit/circuit/library/standard_gates/rxx.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def _define(self):
(HGate(), [q[0]], []),
(HGate(), [q[1]], []),
(CXGate(), [q[0], q[1]], []),
(U1Gate(theta), [q[1]], []),
(U1Gate(theta), [q[1]], []), # Should be RZGate
(CXGate(), [q[0], q[1]], []),
(HGate(), [q[1]], []),
(HGate(), [q[0]], []),
Expand Down
18 changes: 7 additions & 11 deletions qiskit/circuit/library/standard_gates/ry.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,19 @@ class RYGate(Gate):
\end{pmatrix}
"""

def __init__(self, theta, label=None):
def __init__(self, theta, phase=0, label=None):
"""Create new RY gate."""
super().__init__('ry', 1, [theta], label=label)
super().__init__('ry', 1, [theta], phase=phase, label=label)

def _define(self):
"""
gate ry(theta) a { r(theta, pi/2) a; }
"""
from .r import RGate
definition = []
q = QuantumRegister(1, 'q')
rule = [
(RGate(self.params[0], pi / 2), [q[0]], [])
self.definition = [
(RGate(self.params[0], pi / 2, phase=self.phase), [q[0]], [])
]
for inst in rule:
definition.append(inst)
self.definition = definition

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Return a (mutli-)controlled-RY gate.
Expand All @@ -76,7 +72,7 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
Returns:
ControlledGate: controlled version of this gate.
"""
if num_ctrl_qubits == 1:
if num_ctrl_qubits == 1 and self.phase == 0:
gate = CRYGate(self.params[0], label=label, ctrl_state=ctrl_state)
gate.base_gate.label = self.label
return gate
Expand All @@ -87,9 +83,9 @@ def inverse(self):

:math:`RY(\lambda){\dagger} = RY(-\lambda)`
"""
return RYGate(-self.params[0])
return RYGate(-self.params[0], phase=-self.phase)

def to_matrix(self):
def _matrix_definition(self):
"""Return a numpy.array for the RY gate."""
cos = math.cos(self.params[0] / 2)
sin = math.sin(self.params[0] / 2)
Expand Down
4 changes: 2 additions & 2 deletions qiskit/circuit/library/standard_gates/ryy.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _define(self):
"""Calculate a subcircuit that implements this unitary."""
from .x import CXGate
from .rx import RXGate
from .rz import RZGate
from .u1 import U1Gate

definition = []
q = QuantumRegister(2, 'q')
Expand All @@ -86,7 +86,7 @@ def _define(self):
(RXGate(np.pi / 2), [q[0]], []),
(RXGate(np.pi / 2), [q[1]], []),
(CXGate(), [q[0], q[1]], []),
(RZGate(theta), [q[1]], []),
(U1Gate(theta), [q[1]], []), # Should be RZGate
(CXGate(), [q[0], q[1]], []),
(RXGate(-np.pi / 2), [q[0]], []),
(RXGate(-np.pi / 2), [q[1]], []),
Expand Down
33 changes: 15 additions & 18 deletions qiskit/circuit/library/standard_gates/rz.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

"""Rotation around the Z axis."""

import numpy as np

from qiskit.circuit.gate import Gate
from qiskit.circuit.controlledgate import ControlledGate
from qiskit.circuit.quantumregister import QuantumRegister
Expand Down Expand Up @@ -56,23 +58,20 @@ class RZGate(Gate):
`1612.00858 <https://arxiv.org/abs/1612.00858>`_
"""

def __init__(self, phi, label=None):
def __init__(self, phi, phase=0, label=None):
"""Create new RZ gate."""
super().__init__('rz', 1, [phi], label=label)
super().__init__('rz', 1, [phi], phase=phase, label=label)

def _define(self):
"""
gate rz(phi) a { u1(phi) a; }
"""
from .u1 import U1Gate
definition = []
q = QuantumRegister(1, 'q')
rule = [
(U1Gate(self.params[0]), [q[0]], [])
phase = self.phase - 0.5 * self.params[0]
self.definition = [
(U1Gate(self.params[0], phase=phase), [q[0]], [])
]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is where i would make it from a U1 but set it to be a phase that to make it Rz

for inst in rule:
definition.append(inst)
self.definition = definition

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Return a (mutli-)controlled-RZ gate.
Expand All @@ -86,7 +85,7 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
Returns:
ControlledGate: controlled version of this gate.
"""
if num_ctrl_qubits == 1:
if num_ctrl_qubits == 1 and self.phase == 0:
gate = CRZGate(self.params[0], label=label, ctrl_state=ctrl_state)
gate.base_gate.label = self.label
return gate
Expand All @@ -97,15 +96,13 @@ def inverse(self):

:math:`RZ(\lambda){\dagger} = RZ(-\lambda)`
"""
return RZGate(-self.params[0])

# TODO: this is the correct matrix however the control mechanism
# cannot distinguish U1 and RZ yet.
# def to_matrix(self):
# """Return a numpy.array for the RZ gate."""
# lam = float(self.params[0])
# return np.array([[np.exp(-1j * lam / 2), 0],
# [0, np.exp(1j * lam / 2)]], dtype=complex)
return RZGate(-self.params[0], phase=-self.phase)

def _matrix_definition(self):
"""Return a numpy.array for the RZ gate."""
lam = float(self.params[0])
return np.array([[np.exp(-1j * lam / 2), 0],
[0, np.exp(1j * lam / 2)]], dtype=complex)


class CRZMeta(type):
Expand Down
4 changes: 2 additions & 2 deletions qiskit/circuit/library/standard_gates/rzx.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister
from .rz import RZGate
from .u1 import U1Gate
from .h import HGate
from .x import CXGate

Expand Down Expand Up @@ -129,7 +129,7 @@ def _define(self):
self.definition = [
(HGate(), [q[1]], []),
(CXGate(), [q[0], q[1]], []),
(RZGate(self.params[0]), [q[1]], []),
(U1Gate(self.params[0]), [q[1]], []), # Should be RZGate
(CXGate(), [q[0], q[1]], []),
(HGate(), [q[1]], [])
]
Expand Down
2 changes: 1 addition & 1 deletion qiskit/circuit/library/standard_gates/rzz.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def _define(self):
q = QuantumRegister(2, 'q')
rule = [
(CXGate(), [q[0], q[1]], []),
(U1Gate(self.params[0]), [q[1]], []),
(U1Gate(self.params[0]), [q[1]], []), # Should be RZGate
(CXGate(), [q[0], q[1]], [])
]
for inst in rule:
Expand Down
16 changes: 6 additions & 10 deletions qiskit/circuit/library/standard_gates/u1.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,16 @@ class U1Gate(Gate):
`1612.00858 <https://arxiv.org/abs/1612.00858>`_
"""

def __init__(self, theta, label=None):
def __init__(self, theta, phase=0, label=None):
"""Create new U1 gate."""
super().__init__('u1', 1, [theta], label=label)
super().__init__('u1', 1, [theta], phase=phase, label=label)

def _define(self):
from .u3 import U3Gate # pylint: disable=cyclic-import
definition = []
q = QuantumRegister(1, 'q')
rule = [
(U3Gate(0, 0, self.params[0]), [q[0]], [])
self.definition = [
(U3Gate(0, 0, self.params[0], phase=self.phase), [q[0]], [])
]
for inst in rule:
definition.append(inst)
self.definition = definition

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
"""Return a (mutli-)controlled-U1 gate.
Expand All @@ -114,9 +110,9 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):

def inverse(self):
r"""Return inverted U1 gate (:math:`U1(\lambda){\dagger} = U1(-\lambda)`)"""
return U1Gate(-self.params[0])
return U1Gate(-self.params[0], phase=-self.phase)

def to_matrix(self):
def _matrix_definition(self):
"""Return a numpy.array for the U1 gate."""
lam = self.params[0]
lam = float(lam)
Expand Down
Loading