diff --git a/qiskit/circuit/gate.py b/qiskit/circuit/gate.py index a6debab861d4..b01e27c27020 100644 --- a/qiskit/circuit/gate.py +++ b/qiskit/circuit/gate.py @@ -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 @@ -26,6 +28,7 @@ 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. @@ -33,20 +36,38 @@ def __init__(self, name: str, num_qubits: int, params: List, 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`. @@ -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""" @@ -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""" diff --git a/qiskit/circuit/library/standard_gates/r.py b/qiskit/circuit/library/standard_gates/r.py index 342d124581bd..a439fbe0c9e7 100644 --- a/qiskit/circuit/library/standard_gates/r.py +++ b/qiskit/circuit/library/standard_gates/r.py @@ -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]], []) ] - 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) diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index 0023ef405291..2d3fe847b705 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -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. @@ -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 @@ -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) diff --git a/qiskit/circuit/library/standard_gates/rxx.py b/qiskit/circuit/library/standard_gates/rxx.py index 273afe1397b0..cd7c88de00f4 100644 --- a/qiskit/circuit/library/standard_gates/rxx.py +++ b/qiskit/circuit/library/standard_gates/rxx.py @@ -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]], []), diff --git a/qiskit/circuit/library/standard_gates/ry.py b/qiskit/circuit/library/standard_gates/ry.py index ff9140c6e429..301693f561cc 100644 --- a/qiskit/circuit/library/standard_gates/ry.py +++ b/qiskit/circuit/library/standard_gates/ry.py @@ -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. @@ -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 @@ -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) diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index b039b0fa4d6b..570e23a41221 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -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') @@ -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]], []), diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index d55bfc449c62..ea54583742ea 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -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 @@ -56,23 +58,20 @@ class RZGate(Gate): `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]], []) ] - 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. @@ -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 @@ -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): diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index 8ae3da4caa6c..37985b7694f6 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -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 @@ -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]], []) ] diff --git a/qiskit/circuit/library/standard_gates/rzz.py b/qiskit/circuit/library/standard_gates/rzz.py index cfb75b169559..77a7a5ee7e50 100644 --- a/qiskit/circuit/library/standard_gates/rzz.py +++ b/qiskit/circuit/library/standard_gates/rzz.py @@ -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: diff --git a/qiskit/circuit/library/standard_gates/u1.py b/qiskit/circuit/library/standard_gates/u1.py index c3a083c2fc0f..4b58d3cd5827 100644 --- a/qiskit/circuit/library/standard_gates/u1.py +++ b/qiskit/circuit/library/standard_gates/u1.py @@ -75,20 +75,16 @@ class U1Gate(Gate): `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. @@ -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) diff --git a/qiskit/circuit/library/standard_gates/u2.py b/qiskit/circuit/library/standard_gates/u2.py index aa34ba1ff5e7..75f05a6daf74 100644 --- a/qiskit/circuit/library/standard_gates/u2.py +++ b/qiskit/circuit/library/standard_gates/u2.py @@ -59,27 +59,25 @@ class U2Gate(Gate): using two X90 pulses. """ - def __init__(self, phi, lam, label=None): + def __init__(self, phi, lam, phase=0, label=None): """Create new U2 gate.""" - super().__init__('u2', 1, [phi, lam], label=label) + super().__init__('u2', 1, [phi, lam], phase=0, label=label) def _define(self): from .u3 import U3Gate - definition = [] q = QuantumRegister(1, 'q') - rule = [(U3Gate(pi / 2, self.params[0], self.params[1]), [q[0]], [])] - for inst in rule: - definition.append(inst) - self.definition = definition + self.definition = [ + (U3Gate(pi / 2, self.params[0], self.params[1], phase=self.phase), [q[0]], []) + ] def inverse(self): r"""Return inverted U2 gate. :math:`U2(\phi, \lambda)^{\dagger} =U2(-\lambda-\pi, -\phi+\pi)`) """ - return U2Gate(-self.params[1] - pi, -self.params[0] + pi) + return U2Gate(-self.params[1] - pi, -self.params[0] + pi, phase=-self.phase) - def to_matrix(self): + def _matrix_definition(self): """Return a Numpy.array for the U2 gate.""" isqrt2 = 1 / numpy.sqrt(2) phi, lam = self.params diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index 087355ab38f6..8447b19e8850 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -59,16 +59,16 @@ class U3Gate(Gate): U3(\theta, 0, 0) = RY(\theta) """ - def __init__(self, theta, phi, lam, label=None): + def __init__(self, theta, phi, lam, phase=0, label=None): """Create new U3 gate.""" - super().__init__('u3', 1, [theta, phi, lam], label=label) + super().__init__('u3', 1, [theta, phi, lam], phase=phase, label=label) 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]) + return U3Gate(-self.params[0], -self.params[2], -self.params[1], phase=-self.phase) def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-U3 gate. @@ -82,13 +82,13 @@ 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 = 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) - def to_matrix(self): + def _matrix_definition(self): """Return a Numpy.array for the U3 gate.""" theta, phi, lam = self.params theta, phi, lam = float(theta), float(phi), float(lam) diff --git a/qiskit/quantum_info/synthesis/one_qubit_decompose.py b/qiskit/quantum_info/synthesis/one_qubit_decompose.py index fa681af2bd41..281226373eab 100644 --- a/qiskit/quantum_info/synthesis/one_qubit_decompose.py +++ b/qiskit/quantum_info/synthesis/one_qubit_decompose.py @@ -119,8 +119,8 @@ def __call__(self, if not is_unitary_matrix(unitary): raise QiskitError("OneQubitEulerDecomposer: " "input matrix is not unitary.") - theta, phi, lam, _ = self._params(unitary) - circuit = self._circuit(theta, phi, lam, + theta, phi, lam, phase = self._params(unitary) + circuit = self._circuit(theta, phi, lam, phase=phase, simplify=simplify, atol=atol) return circuit @@ -236,16 +236,17 @@ def _params_u1x(mat): def _circuit_zyz(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): circuit = QuantumCircuit(1) if simplify and np.isclose(theta, 0.0, atol=atol): - circuit.append(RZGate(phi + lam), [0]) + circuit.append(RZGate(phi + lam, phase=phase), [0]) return circuit if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RZGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RYGate(theta), [0]) + circuit.append(RYGate(theta, phase=phase), [0]) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RZGate(phi), [0]) return circuit @@ -254,17 +255,18 @@ def _circuit_zyz(theta, def _circuit_zxz(theta, phi, lam, + phase=0, simplify=False, atol=DEFAULT_ATOL): if simplify and np.isclose(theta, 0.0, atol=atol): circuit = QuantumCircuit(1) - circuit.append(RZGate(phi + lam), [0]) + circuit.append(RZGate(phi + lam, phase=phase), [0]) return circuit circuit = QuantumCircuit(1) if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RZGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RXGate(theta), [0]) + circuit.append(RXGate(theta, phase=phase), [0]) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RZGate(phi), [0]) return circuit @@ -273,16 +275,17 @@ def _circuit_zxz(theta, def _circuit_xyx(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): circuit = QuantumCircuit(1) if simplify and np.isclose(theta, 0.0, atol=atol): - circuit.append(RXGate(phi + lam), [0]) + circuit.append(RXGate(phi + lam, phase=phase), [0]) return circuit if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RXGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RYGate(theta), [0]) + circuit.append(RYGate(theta, phase=phase), [0]) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RXGate(phi), [0]) return circuit @@ -291,17 +294,19 @@ def _circuit_xyx(theta, def _circuit_u3(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): # pylint: disable=unused-argument circuit = QuantumCircuit(1) - circuit.append(U3Gate(theta, phi, lam), [0]) + circuit.append(U3Gate(theta, phi, lam, phase=phase), [0]) return circuit @staticmethod def _circuit_u1x(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): # Shift theta and phi so decomposition is @@ -312,18 +317,18 @@ def _circuit_u1x(theta, if simplify and np.isclose(abs(theta), np.pi, atol=atol): # Zero X90 gate decomposition circuit = QuantumCircuit(1) - circuit.append(U1Gate(lam + phi + theta), [0]) + circuit.append(U1Gate(lam + phi + theta, phase=phase), [0]) return circuit if simplify and np.isclose(abs(theta), np.pi/2, atol=atol): # Single X90 gate decomposition circuit = QuantumCircuit(1) - circuit.append(U1Gate(lam + theta), [0]) + circuit.append(U1Gate(lam + theta, phase=phase), [0]) circuit.append(RXGate(np.pi / 2), [0]) circuit.append(U1Gate(phi + theta), [0]) return circuit # General two-X90 gate decomposition circuit = QuantumCircuit(1) - circuit.append(U1Gate(lam), [0]) + circuit.append(U1Gate(lam, phase=phase), [0]) circuit.append(RXGate(np.pi / 2), [0]) circuit.append(U1Gate(theta), [0]) circuit.append(RXGate(np.pi / 2), [0]) @@ -334,10 +339,11 @@ def _circuit_u1x(theta, def _circuit_rr(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): circuit = QuantumCircuit(1) if not simplify or not np.isclose(theta, -np.pi, atol=atol): circuit.append(RGate(theta + np.pi, np.pi / 2 - lam), [0]) - circuit.append(RGate(-np.pi, 0.5 * (phi - lam + np.pi)), [0]) + circuit.append(RGate(-np.pi, 0.5 * (phi - lam + np.pi), phase=phase), [0]) return circuit diff --git a/releasenotes/notes/gate-phase-ff6549a85b545638.yaml b/releasenotes/notes/gate-phase-ff6549a85b545638.yaml new file mode 100644 index 000000000000..71c42688a3ce --- /dev/null +++ b/releasenotes/notes/gate-phase-ff6549a85b545638.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + Adds `phase` attribute to the :class:`qiskit.circuit.Gate` class that can be + used set a custom phase coefficient to a gate. This will be reflected in + the :meth:`~qiskit.circuit.Gate.to_matrix` method which will return the + matrix :math:`e^{-i \theta} U` where :math:`U` is the canonical matrix + definition of the gate. + - | + Updates :class:`qiskit.circuit.library.RZGate` to have correct phase + when unrolled to a :class:`qiskit.circuit.library.U1Gate`. + - | + Updates :class:`qiskit.quantum_info.synthesis.OneQubitEulerDecomposer` to + perform phase correct synthesis of any single-qubit unitary matrix. diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index b2226cf63f01..5f365ae4a3ae 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -114,7 +114,7 @@ class TestOneQubitEulerDecomposer(QiskitTestCase): def check_one_qubit_euler_angles(self, operator, basis='U3', tolerance=1e-12, - phase_equal=False): + phase_equal=True): """Check euler_angles_1q works for the given unitary""" decomposer = OneQubitEulerDecomposer(basis) with self.subTest(operator=operator):