Skip to content

Commit

Permalink
Add efficient gate power methods (#9318)
Browse files Browse the repository at this point in the history
* add efficient gate power methods

* fix imports

* override some more methods

* use scipy.linalg.fractional_matrix_power

* use assertIsInstance and add isinstance check

* lint

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
kevinsung and mergify[bot] authored Jan 10, 2023
1 parent c343042 commit d3243e9
Show file tree
Hide file tree
Showing 18 changed files with 231 additions and 38 deletions.
4 changes: 4 additions & 0 deletions qiskit/circuit/library/standard_gates/i.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,7 @@ def inverse(self):
def __array__(self, dtype=None):
"""Return a numpy.array for the identity gate."""
return numpy.array([[1, 0], [0, 1]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
return IGate()
9 changes: 9 additions & 0 deletions qiskit/circuit/library/standard_gates/iswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
"""iSWAP gate."""

from typing import Optional

import numpy as np

from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister

from .xx_plus_yy import XXPlusYYGate


class iSwapGate(Gate):
r"""iSWAP gate.
Expand Down Expand Up @@ -96,6 +100,7 @@ def _define(self):
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit

from .h import HGate
from .s import SGate
from .x import CXGate
Expand All @@ -118,3 +123,7 @@ def _define(self):
def __array__(self, dtype=None):
"""Return a numpy.array for the iSWAP gate."""
return np.array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
return XXPlusYYGate(-np.pi * exponent)
10 changes: 10 additions & 0 deletions qiskit/circuit/library/standard_gates/p.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ def __array__(self, dtype=None):
lam = float(self.params[0])
return numpy.array([[1, 0], [0, exp(1j * lam)]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return PhaseGate(exponent * theta)


class CPhaseGate(ControlledGate):
r"""Controlled-Phase gate.
Expand Down Expand Up @@ -244,6 +249,11 @@ def __array__(self, dtype=None):
)
return numpy.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, eith, 0], [0, 0, 0, 1]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return CPhaseGate(exponent * theta)


class MCPhaseGate(ControlledGate):
r"""Multi-controlled-Phase gate.
Expand Down
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/r.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,8 @@ def __array__(self, dtype=None):
exp_m = exp(-1j * phi)
exp_p = exp(1j * phi)
return numpy.array([[cos, -1j * exp_m * sin], [-1j * exp_p * sin, cos]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
theta, phi = self.params
return RGate(exponent * theta, phi)
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/rx.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ def __array__(self, dtype=None):
sin = math.sin(self.params[0] / 2)
return numpy.array([[cos, -1j * sin], [-1j * sin, cos]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return RXGate(exponent * theta)


class CRXGate(ControlledGate):
r"""Controlled-RX gate.
Expand Down
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/rxx.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,8 @@ def __array__(self, dtype=None):
[[cos, 0, 0, -isin], [0, cos, -isin, 0], [0, -isin, cos, 0], [-isin, 0, 0, cos]],
dtype=dtype,
)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return RXXGate(exponent * theta)
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/ry.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ def __array__(self, dtype=None):
sin = math.sin(self.params[0] / 2)
return numpy.array([[cos, -sin], [sin, cos]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return RYGate(exponent * theta)


class CRYGate(ControlledGate):
r"""Controlled-RY gate.
Expand Down
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/ryy.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,8 @@ def __array__(self, dtype=None):
[[cos, 0, 0, isin], [0, cos, -isin, 0], [0, -isin, cos, 0], [isin, 0, 0, cos]],
dtype=dtype,
)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return RYYGate(exponent * theta)
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/rz.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ def __array__(self, dtype=None):
ilam2 = 0.5j * float(self.params[0])
return np.array([[exp(-ilam2), 0], [0, exp(ilam2)]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return RZGate(exponent * theta)


class CRZGate(ControlledGate):
r"""Controlled-RZ gate.
Expand Down
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/rzx.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,8 @@ def __array__(self, dtype=None):
[[cos, 0, -isin, 0], [0, cos, 0, isin], [-isin, 0, cos, 0], [0, isin, 0, cos]],
dtype=dtype,
)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return RZXGate(exponent * theta)
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/rzz.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,8 @@ def __array__(self, dtype=None):
],
dtype=dtype,
)

def power(self, exponent: float):
"""Raise gate to a power."""
(theta,) = self.params
return RZZGate(exponent * theta)
29 changes: 22 additions & 7 deletions qiskit/circuit/library/standard_gates/s.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
"""The S, Sdg, CS and CSdg gates."""

from typing import Optional, Union

import numpy
from qiskit.qasm import pi

from qiskit.circuit.controlledgate import ControlledGate
from qiskit.circuit.gate import Gate
from qiskit.circuit.library.standard_gates.p import CPhaseGate, PhaseGate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.qasm import pi


class SGate(Gate):
Expand Down Expand Up @@ -60,6 +63,7 @@ def _define(self):
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit

from .u1 import U1Gate

q = QuantumRegister(1, "q")
Expand All @@ -78,6 +82,10 @@ def __array__(self, dtype=None):
"""Return a numpy.array for the S gate."""
return numpy.array([[1, 0], [0, 1j]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
return PhaseGate(0.5 * numpy.pi * exponent)


class SdgGate(Gate):
r"""Single qubit S-adjoint gate (~Z**0.5).
Expand Down Expand Up @@ -119,6 +127,7 @@ def _define(self):
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit

from .u1 import U1Gate

q = QuantumRegister(1, "q")
Expand All @@ -137,6 +146,10 @@ def __array__(self, dtype=None):
"""Return a numpy.array for the Sdg gate."""
return numpy.array([[1, 0], [0, -1j]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
return PhaseGate(-0.5 * numpy.pi * exponent)


class CSGate(ControlledGate):
r"""Controlled-S gate.
Expand Down Expand Up @@ -194,9 +207,6 @@ def _define(self):
"""
gate cs a,b { h b; cp(pi/2) a,b; h b; }
"""
# pylint: disable=cyclic-import
from .p import CPhaseGate

self.definition = CPhaseGate(theta=pi / 2).definition

def inverse(self):
Expand All @@ -210,6 +220,10 @@ def __array__(self, dtype=None):
return numpy.asarray(mat, dtype=dtype)
return mat

def power(self, exponent: float):
"""Raise gate to a power."""
return CPhaseGate(0.5 * numpy.pi * exponent)


class CSdgGate(ControlledGate):
r"""Controlled-S^\dagger gate.
Expand Down Expand Up @@ -273,9 +287,6 @@ def _define(self):
"""
gate csdg a,b { h b; cp(-pi/2) a,b; h b; }
"""
# pylint: disable=cyclic-import
from .p import CPhaseGate

self.definition = CPhaseGate(theta=-pi / 2).definition

def inverse(self):
Expand All @@ -288,3 +299,7 @@ def __array__(self, dtype=None):
if dtype is not None:
return numpy.asarray(mat, dtype=dtype)
return mat

def power(self, exponent: float):
"""Raise gate to a power."""
return CPhaseGate(-0.5 * numpy.pi * exponent)
15 changes: 14 additions & 1 deletion qiskit/circuit/library/standard_gates/t.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
"""T and Tdg gate."""
import math
from typing import Optional

import numpy
from qiskit.qasm import pi

from qiskit.circuit.gate import Gate
from qiskit.circuit.library.standard_gates.p import PhaseGate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.qasm import pi


class TGate(Gate):
Expand Down Expand Up @@ -60,6 +63,7 @@ def _define(self):
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit

from .u1 import U1Gate

q = QuantumRegister(1, "q")
Expand All @@ -78,6 +82,10 @@ def __array__(self, dtype=None):
"""Return a numpy.array for the T gate."""
return numpy.array([[1, 0], [0, (1 + 1j) / numpy.sqrt(2)]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
return PhaseGate(0.25 * numpy.pi * exponent)


class TdgGate(Gate):
r"""Single qubit T-adjoint gate (~Z**0.25).
Expand Down Expand Up @@ -119,6 +127,7 @@ def _define(self):
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit

from .u1 import U1Gate

q = QuantumRegister(1, "q")
Expand All @@ -136,3 +145,7 @@ def inverse(self):
def __array__(self, dtype=None):
"""Return a numpy.array for the inverse T gate."""
return numpy.array([[1, 0], [0, (1 - 1j) / math.sqrt(2)]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
return PhaseGate(-0.25 * numpy.pi * exponent)
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/xx_minus_yy.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,8 @@ def __array__(self, dtype=complex):
],
dtype=dtype,
)

def power(self, exponent: float):
"""Raise gate to a power."""
theta, beta = self.params
return XXMinusYYGate(exponent * theta, beta)
5 changes: 5 additions & 0 deletions qiskit/circuit/library/standard_gates/xx_plus_yy.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,8 @@ def __array__(self, dtype=complex):
],
dtype=dtype,
)

def power(self, exponent: float):
"""Raise gate to a power."""
theta, beta = self.params
return XXPlusYYGate(exponent * theta, beta)
15 changes: 13 additions & 2 deletions qiskit/circuit/library/standard_gates/z.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@
"""Z, CZ and CCZ gates."""

from typing import Optional, Union

import numpy
from qiskit.qasm import pi

from qiskit.circuit._utils import _compute_control_matrix
from qiskit.circuit.controlledgate import ControlledGate
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit._utils import _compute_control_matrix
from qiskit.qasm import pi

from .p import PhaseGate


class ZGate(Gate):
Expand Down Expand Up @@ -74,6 +78,7 @@ def __init__(self, label: Optional[str] = None):
def _define(self):
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit

from .u1 import U1Gate

q = QuantumRegister(1, "q")
Expand Down Expand Up @@ -117,6 +122,10 @@ def __array__(self, dtype=None):
"""Return a numpy.array for the Z gate."""
return numpy.array([[1, 0], [0, -1]], dtype=dtype)

def power(self, exponent: float):
"""Raise gate to a power."""
return PhaseGate(numpy.pi * exponent)


class CZGate(ControlledGate):
r"""Controlled-Z gate.
Expand Down Expand Up @@ -163,6 +172,7 @@ def _define(self):
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit

from .h import HGate
from .x import CXGate

Expand Down Expand Up @@ -241,6 +251,7 @@ def _define(self):
"""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit

from .h import HGate
from .x import CCXGate

Expand Down
25 changes: 25 additions & 0 deletions releasenotes/notes/efficient-gate-power-effa21e3ee4581ee.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
features:
- |
Overrides some gate power methods to make them more efficient and less lossy:
- Powering a :class:`~.CPhaseGate` gives a :class:`~.CPhaseGate`.
- Powering a :class:`~.CSGate` gives a :class:`~.CPhaseGate`.
- Powering a :class:`~.CSdgGate` gives a :class:`~.CPhaseGate`.
- Powering an :class:`~.IGate` gives an :class:`~.IGate`.
- Powering a :class:`~.PhaseGate` gives a :class:`~.PhaseGate`.
- Powering an :class:`~.RGate` gives an :class:`~.RGate`.
- Powering an :class:`~.RXGate` gives an :class:`~.RXGate`.
- Powering an :class:`~.RXXGate` gives an :class:`~.RXXGate`.
- Powering an :class:`~.RYGate` gives an :class:`~.RYGate`.
- Powering an :class:`~.RYYGate` gives an :class:`~.RYYGate`.
- Powering an :class:`~.RZGate` gives an :class:`~.RZGate`.
- Powering an :class:`~.RZXGate` gives an :class:`~.RZXGate`.
- Powering an :class:`~.RZZGate` gives an :class:`~.RZZGate`.
- Powering a :class:`~.SdgGate` gives a :class:`~.PhaseGate`.
- Powering an :class:`~.SGate` gives a :class:`~.PhaseGate`.
- Powering a :class:`~.TdgGate` gives a :class:`~.PhaseGate`.
- Powering a :class:`~.TGate` gives a :class:`~.PhaseGate`.
- Powering an :class:`~.XXMinusYYGate` gives an :class:`~.XXMinusYYGate`.
- Powering an :class:`~.XXPlusYYGate` gives an :class:`~.XXPlusYYGate`.
- Powering a :class:`~.ZGate` gives a :class:`~.PhaseGate`.
- Powering an :class:`~.iSwapGate` gives an :class:`~.XXPlusYYGate`.
Loading

0 comments on commit d3243e9

Please sign in to comment.