Skip to content

Commit

Permalink
Add type hints to gates and QuantumCircuit (Qiskit#6831)
Browse files Browse the repository at this point in the history
* Move QuantumCircuit.measure into QuantumCircuit

* Add type hints to QuantumCircuit

This adds full type hints to all public function entry points in
QuantumCircuit.  This will not cause quantumcircuit.py to pass a mypy
check yet; there are various idioms used within the file which are not
statically type-safe (nor, in some cases, dynamically type safe in the
sense that we sometimes rely on mismatched types to throw exceptions).
These include anything which takes the `inplace` argument, since
`inplace=True` versions do not return, which influences the out types to
    Optional["QuantumCircuit"]
This then means that methods using these functions (e.g.
`QuantumCircuit.__add__`) become unsafe; even though they use the
default `inplace=False`, subclasses could override this while still
maintaining type safety, and so the operation is not safe.

This patch makes no attempt to modify the behaviour of these
non-type-safe functions, only to classify what the current types are.

* Add type hints and label to all standard gates

This completes the standard-library gate documentation overhaul tracked
by Qiskit#3705, and mostly done in Qiskit#4017, by adding type hints to the
initializers.

It also adds the missing `label` option to the iSWAP, R, RXX, RYY, RZX
and RZZ gates, to bring them up to parity with the other gates, tracked
in Qiskit#6780.

* Add parameters to QuantumCircuit gate docstrings

This only adds short documentation to the docstrings of the gate methods
(for example `QuantumCircuit.x`) about the parameters and the return
values.  It does not currently import the matrix representations into
the docstrings themselves, because the gate classes include those.  The
expectation is that you would see the docstring when running
interactively, and even in Jupyter, this typically does not include
displaying maths.  The matrix form is more useful when looking at the
online Sphinx documentation, where the cross-reference gate link will
work more easily.

* Add release note

* Document type aliases in comments, not __doc__

Python 3.6 doesn't allow assigning to the __doc__ field of the `typing`
types, so as long as we support it, we can't do that.

* Include reset in QuantumCircuit

The previous commit stopped `QuantumCircuit.measure` from being
monkey-patched in by `qiskit/circuit/measure.py`, but the similar
`QuantumCircuit.reset` operation was overlooked.  This adds it in for
consistency.
  • Loading branch information
jakelishman authored Aug 13, 2021
1 parent 23774bc commit 2cd42b4
Show file tree
Hide file tree
Showing 31 changed files with 1,662 additions and 396 deletions.
2 changes: 1 addition & 1 deletion qiskit/circuit/gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def _return_repeat(self, exponent: float) -> "Gate":

def control(
self,
num_ctrl_qubits: Optional[int] = 1,
num_ctrl_qubits: int = 1,
label: Optional[str] = None,
ctrl_state: Optional[Union[int, str]] = None,
):
Expand Down
12 changes: 9 additions & 3 deletions qiskit/circuit/library/standard_gates/h.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

"""Hadamard gate."""

from typing import Optional, Union
import numpy
from qiskit.circuit.controlledgate import ControlledGate
from qiskit.circuit.gate import Gate
Expand Down Expand Up @@ -47,7 +48,7 @@ class HGate(Gate):
\end{pmatrix}
"""

def __init__(self, label=None):
def __init__(self, label: Optional[str] = None):
"""Create new H gate."""
super().__init__("h", 1, [], label=label)

Expand All @@ -67,7 +68,12 @@ def _define(self):

self.definition = qc

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
def control(
self,
num_ctrl_qubits: int = 1,
label: Optional[str] = None,
ctrl_state: Optional[Union[int, str]] = None,
):
"""Return a (multi-)controlled-H gate.
One control qubit returns a CH gate.
Expand Down Expand Up @@ -158,7 +164,7 @@ class CHGate(ControlledGate):
dtype=complex,
)

def __init__(self, label=None, ctrl_state=None):
def __init__(self, label: Optional[str] = None, ctrl_state: Optional[Union[int, str]] = None):
"""Create new CH gate."""
super().__init__(
"ch", 2, [], num_ctrl_qubits=1, label=label, ctrl_state=ctrl_state, base_gate=HGate()
Expand Down
3 changes: 2 additions & 1 deletion qiskit/circuit/library/standard_gates/i.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

"""Identity gate."""

from typing import Optional
import numpy
from qiskit.circuit.gate import Gate

Expand Down Expand Up @@ -39,7 +40,7 @@ class IGate(Gate):
└───┘
"""

def __init__(self, label=None):
def __init__(self, label: Optional[str] = None):
"""Create new Identity gate."""
super().__init__("id", 1, [], label=label)

Expand Down
5 changes: 3 additions & 2 deletions qiskit/circuit/library/standard_gates/iswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

"""iSWAP gate."""

from typing import Optional
import numpy as np
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister
Expand Down Expand Up @@ -75,9 +76,9 @@ class iSwapGate(Gate):
\end{pmatrix}
"""

def __init__(self):
def __init__(self, label: Optional[str] = None):
"""Create new iSwap gate."""
super().__init__("iswap", 2, [])
super().__init__("iswap", 2, [], label=label)

def _define(self):
"""
Expand Down
4 changes: 3 additions & 1 deletion qiskit/circuit/library/standard_gates/ms.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@

"""Global Mølmer–Sørensen gate."""

from typing import Optional
import warnings
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit.parameterexpression import ParameterValueType


class MSGate(Gate):
Expand All @@ -30,7 +32,7 @@ class MSGate(Gate):
and is thus reduced to the RXXGate.
"""

def __init__(self, num_qubits, theta, label=None):
def __init__(self, num_qubits: int, theta: ParameterValueType, label: Optional[str] = None):
"""Create new MS gate."""
warnings.warn(
"The qiskit.circuit.library.standard_gates.ms import "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
"""

from math import pi
from typing import Optional, Union, Tuple, List
from qiskit.circuit import QuantumCircuit, QuantumRegister, Qubit
from qiskit.circuit.library.standard_gates.x import MCXGate
from qiskit.circuit.library.standard_gates.u3 import _generate_gray_code
from qiskit.circuit.parameterexpression import ParameterValueType
from qiskit.exceptions import QiskitError


Expand Down Expand Up @@ -74,14 +76,20 @@ def _apply_mcu_graycode(circuit, theta, phi, lam, ctls, tgt, use_basis_gates):
last_pattern = pattern


def mcrx(self, theta, q_controls, q_target, use_basis_gates=False):
def mcrx(
self,
theta: ParameterValueType,
q_controls: Union[QuantumRegister, List[Qubit]],
q_target: Qubit,
use_basis_gates: bool = False,
):
"""
Apply Multiple-Controlled X rotation gate
Args:
self (QuantumCircuit): The QuantumCircuit object to apply the mcrx gate on.
theta (float): angle theta
q_controls (list(Qubit)): The list of control qubits
q_controls (QuantumRegister or list(Qubit)): The list of control qubits
q_target (Qubit): The target qubit
use_basis_gates (bool): use p, u, cx
Expand Down Expand Up @@ -134,7 +142,15 @@ def mcrx(self, theta, q_controls, q_target, use_basis_gates=False):
)


def mcry(self, theta, q_controls, q_target, q_ancillae=None, mode=None, use_basis_gates=False):
def mcry(
self,
theta: ParameterValueType,
q_controls: Union[QuantumRegister, List[Qubit]],
q_target: Qubit,
q_ancillae: Optional[Union[QuantumRegister, Tuple[QuantumRegister, int]]] = None,
mode: str = None,
use_basis_gates=False,
):
"""
Apply Multiple-Controlled Y rotation gate
Expand Down Expand Up @@ -219,7 +235,13 @@ def mcry(self, theta, q_controls, q_target, q_ancillae=None, mode=None, use_basi
raise QiskitError(f"Unrecognized mode for building MCRY circuit: {mode}.")


def mcrz(self, lam, q_controls, q_target, use_basis_gates=False):
def mcrz(
self,
lam: ParameterValueType,
q_controls: Union[QuantumRegister, List[Qubit]],
q_target: Qubit,
use_basis_gates: bool = False,
):
"""
Apply Multiple-Controlled Z rotation gate
Expand Down
34 changes: 28 additions & 6 deletions qiskit/circuit/library/standard_gates/p.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@

"""Phase Gate."""

from typing import Optional, Union
import numpy
from qiskit.circuit.controlledgate import ControlledGate
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit.parameterexpression import ParameterValueType


class PhaseGate(Gate):
Expand Down Expand Up @@ -69,7 +71,7 @@ class PhaseGate(Gate):
`1612.00858 <https://arxiv.org/abs/1612.00858>`_
"""

def __init__(self, theta, label=None):
def __init__(self, theta: ParameterValueType, label: Optional[str] = None):
"""Create new Phase gate."""
super().__init__("p", 1, [theta], label=label)

Expand All @@ -83,7 +85,12 @@ def _define(self):
qc.append(UGate(0, 0, self.params[0]), [0])
self.definition = qc

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
def control(
self,
num_ctrl_qubits: int = 1,
label: Optional[str] = None,
ctrl_state: Optional[Union[int, str]] = None,
):
"""Return a (multi-)controlled-Phase gate.
Args:
Expand Down Expand Up @@ -153,7 +160,12 @@ class CPhaseGate(ControlledGate):
phase difference.
"""

def __init__(self, theta, label=None, ctrl_state=None):
def __init__(
self,
theta: ParameterValueType,
label: Optional[str] = None,
ctrl_state: Optional[Union[str, int]] = None,
):
"""Create new CPhase gate."""
super().__init__(
"cp",
Expand Down Expand Up @@ -185,7 +197,12 @@ def _define(self):
qc.p(self.params[0] / 2, 1)
self.definition = qc

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
def control(
self,
num_ctrl_qubits: int = 1,
label: Optional[str] = None,
ctrl_state: Optional[Union[str, int]] = None,
):
"""Controlled version of this gate.
Args:
Expand Down Expand Up @@ -242,7 +259,7 @@ class MCPhaseGate(ControlledGate):
The singly-controlled-version of this gate.
"""

def __init__(self, lam, num_ctrl_qubits, label=None):
def __init__(self, lam: ParameterValueType, num_ctrl_qubits: int, label: Optional[str] = None):
"""Create new MCPhase gate."""
super().__init__(
"mcphase",
Expand Down Expand Up @@ -273,7 +290,12 @@ def _define(self):
qc.data = definition
self.definition = qc

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
def control(
self,
num_ctrl_qubits: int = 1,
label: Optional[str] = None,
ctrl_state: Optional[Union[str, int]] = None,
):
"""Controlled version of this gate.
Args:
Expand Down
8 changes: 6 additions & 2 deletions qiskit/circuit/library/standard_gates/r.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
"""Rotation around an axis in x-y plane."""

import math
from typing import Optional
import numpy
from qiskit.qasm import pi
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit.parameterexpression import ParameterValueType


class RGate(Gate):
Expand All @@ -43,9 +45,11 @@ class RGate(Gate):
\end{pmatrix}
"""

def __init__(self, theta, phi):
def __init__(
self, theta: ParameterValueType, phi: ParameterValueType, label: Optional[str] = None
):
"""Create new r single-qubit gate."""
super().__init__("r", 1, [theta, phi])
super().__init__("r", 1, [theta, phi], label=label)

def _define(self):
"""
Expand Down
19 changes: 16 additions & 3 deletions qiskit/circuit/library/standard_gates/rx.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
"""Rotation around the X axis."""

import math
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.quantumregister import QuantumRegister
from qiskit.circuit.parameterexpression import ParameterValueType


class RXGate(Gate):
Expand All @@ -44,7 +47,7 @@ class RXGate(Gate):
\end{pmatrix}
"""

def __init__(self, theta, label=None):
def __init__(self, theta: ParameterValueType, label: Optional[str] = None):
"""Create new RX gate."""
super().__init__("rx", 1, [theta], label=label)

Expand All @@ -64,7 +67,12 @@ def _define(self):

self.definition = qc

def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None):
def control(
self,
num_ctrl_qubits: int = 1,
label: Optional[str] = None,
ctrl_state: Optional[Union[str, int]] = None,
):
"""Return a (multi-)controlled-RX gate.
Args:
Expand Down Expand Up @@ -151,7 +159,12 @@ class CRXGate(ControlledGate):
\end{pmatrix}
"""

def __init__(self, theta, label=None, ctrl_state=None):
def __init__(
self,
theta: ParameterValueType,
label: Optional[str] = None,
ctrl_state: Optional[Union[str, int]] = None,
):
"""Create new CRX gate."""
super().__init__(
"crx",
Expand Down
6 changes: 4 additions & 2 deletions qiskit/circuit/library/standard_gates/rxx.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@

"""Two-qubit XX-rotation gate."""

from typing import Optional
from qiskit.circuit.gate import Gate
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit.parameterexpression import ParameterValueType


class RXXGate(Gate):
Expand Down Expand Up @@ -66,9 +68,9 @@ class RXXGate(Gate):
\end{pmatrix}
"""

def __init__(self, theta):
def __init__(self, theta: ParameterValueType, label: Optional[str] = None):
"""Create new RXX gate."""
super().__init__("rxx", 2, [theta])
super().__init__("rxx", 2, [theta], label=label)

def _define(self):
"""Calculate a subcircuit that implements this unitary."""
Expand Down
Loading

0 comments on commit 2cd42b4

Please sign in to comment.