Skip to content

Commit

Permalink
Introduce PEP484 type hints to paulis.py
Browse files Browse the repository at this point in the history
  • Loading branch information
rht committed Oct 22, 2017
1 parent b871e5d commit 7c6d394
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 9 deletions.
56 changes: 47 additions & 9 deletions pyquil/paulis.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
from six import integer_types
from six.moves import range

from typing import Dict, Iterator, List, Tuple, Union # noqa: F401

PAULI_OPS = ["X", "Y", "Z", "I"]
PAULI_PROD = {'ZZ': 'I', 'YY': 'I', 'XX': 'I', 'II': 'I',
'XY': 'Z', 'XZ': 'Y', 'YX': 'Z', 'YZ': 'X', 'ZX': 'Y',
Expand All @@ -53,6 +55,7 @@ class PauliTerm(object):
"""

def __init__(self, op, index, coefficient=1.0):
# type: (str, int, float) -> None
""" Create a new Pauli Term with a Pauli operator at a particular index and a leading
coefficient.
Expand All @@ -63,23 +66,24 @@ def __init__(self, op, index, coefficient=1.0):
assert op in PAULI_OPS
assert isinstance(index, integer_types) and index >= 0

self._ops = {}
self._ops = {} # type: Dict[int,str]
if op != "I":
self._ops[index] = op
if not isinstance(coefficient, Number):
raise ValueError("coefficient of PauliTerm must be a Number.")
self.coefficient = complex(coefficient)
self._id = None
self.coefficient = complex(coefficient) # type: complex
self._id = "" # type: str

def id(self):
# type: () -> str
"""
Returns the unique identifier string for the PauliTerm (ignoring the coefficient).
Used in the simplify method of PauliSum.
:return: The unique identifier for this term.
:rtype: string
"""
if self._id is not None:
if self._id is not "":
return self._id
else:
s = ""
Expand All @@ -89,6 +93,7 @@ def id(self):
return s

def __eq__(self, other):
# type: (PauliTerm) -> bool
if not isinstance(other, (PauliTerm, PauliSum)):
raise TypeError("Can't compare PauliTerm with object of type {}.".format(type(other)))
elif isinstance(other, PauliSum):
Expand All @@ -97,19 +102,22 @@ def __eq__(self, other):
return self.id() == other.id() and np.isclose(self.coefficient, other.coefficient)

def __ne__(self, other):
# type: (PauliTerm) -> bool
# x!=y and x<>y call __ne__() instead of negating __eq__
# This is only a weirdness in python2 as in python 3 __ne__ defaults to the inversion of
# __eq__
return not self.__eq__(other)

def __len__(self):
# type: () -> int
"""
The length of the PauliTerm is the number of Pauli operators in the term. A term that
consists of only a scalar has a length of zero.
"""
return len(self._ops)

def copy(self):
# type: () -> PauliTerm
"""
Properly creates a new PauliTerm, with a completely new dictionary
of operators
Expand All @@ -126,19 +134,23 @@ def copy(self):
return new_term

def get_qubits(self):
# type () -> List[int]
"""Gets all the qubits that this PauliTerm operates on.
"""
# sort the keys to get a deterministic iteration order over qubits
return sorted(self._ops.keys())

def __getitem__(self, i):
# type: (int) -> str
return self._ops.get(i, "I")

def __iter__(self):
# type: () -> Iterator[Tuple[int, str]]
for i in self.get_qubits():
yield i, self[i]

def _multiply_factor(self, factor, index):
# type: (str, int) -> PauliTerm
new_term = PauliTerm("I", 0)
new_coeff = self.coefficient
new_ops = self._ops.copy()
Expand All @@ -157,6 +169,7 @@ def _multiply_factor(self, factor, index):
return new_term

def __mul__(self, term):
# type: (Union[PauliTerm, PauliSum, Number]) -> PauliTerm
"""Multiplies this Pauli Term with another PauliTerm, PauliSum, or number according to the
Pauli algebra rules.
Expand All @@ -178,6 +191,7 @@ def __mul__(self, term):
return term_with_coeff(new_term, new_term.coefficient * new_coeff)

def __rmul__(self, other):
# type: (Number) -> PauliTerm
"""Multiplies this PauliTerm with another object, probably a number.
:param other: A number or PauliTerm to multiply by
Expand All @@ -188,6 +202,7 @@ def __rmul__(self, other):
return self * other

def __pow__(self, power):
# type: (int) -> PauliTerm
"""Raises this PauliTerm to power.
:param int power: The power to raise this PauliTerm to.
Expand All @@ -209,21 +224,23 @@ def __pow__(self, power):
return result

def __add__(self, other):
# type: (Union[PauliTerm, Number]) -> PauliSum
"""Adds this PauliTerm with another one.
:param other: A PauliTerm object or a Number
:returns: A PauliSum object representing the sum of this PauliTerm and other
:rtype: PauliSum
"""
if isinstance(other, Number):
return self + PauliTerm("I", 0, other)
return self + PauliTerm("I", 0, float(other))
elif isinstance(other, PauliSum):
return other + self
else:
new_sum = PauliSum([self, other])
return new_sum.simplify()

def __radd__(self, other):
# type: (Number) -> PauliSum
"""Adds this PauliTerm with a Number.
:param other: A PauliTerm object or a Number
Expand All @@ -234,6 +251,7 @@ def __radd__(self, other):
return self + other

def __sub__(self, other):
# type: (Union[PauliTerm, Number]) -> PauliSum
"""Subtracts a PauliTerm from this one.
:param other: A PauliTerm object or a Number
Expand All @@ -243,6 +261,7 @@ def __sub__(self, other):
return self + -1. * other

def __rsub__(self, other):
# type: (Union[PauliTerm, Number]) -> PauliSum
"""Subtracts this PauliTerm from a Number or PauliTerm.
:param other: A PauliTerm object or a Number
Expand All @@ -252,6 +271,7 @@ def __rsub__(self, other):
return other + -1. * self

def __str__(self):
# type: () -> str
term_strs = []
for index in sorted(self._ops.keys()):
term_strs.append("%s%s" % (self[index], index))
Expand Down Expand Up @@ -347,6 +367,7 @@ def sZ(q):


def term_with_coeff(term, coeff):
# type: (PauliTerm, Number) -> PauliTerm
"""
Change the coefficient of a PauliTerm.
Expand All @@ -368,6 +389,7 @@ class PauliSum(object):
"""

def __init__(self, terms):
# type: (List[PauliTerm]) -> None
"""
:param Sequence terms: A Sequence of PauliTerms.
"""
Expand All @@ -380,9 +402,10 @@ def __init__(self, terms):
self.terms = terms

def __eq__(self, other):
# type: (Union[PauliTerm, PauliSum]) -> bool
"""Equality testing to see if two PauliSum's are equivalent.
:param PauliSum other: The PauliSum to compare this PauliSum with.
:param PauliTerm or PauliSum other: The PauliSum to compare this PauliSum with.
:return: True if other is equivalent to this PauliSum, False otherwise.
:rtype: bool
"""
Expand All @@ -396,24 +419,28 @@ def __eq__(self, other):
return all([term == other.terms[i] for i, term in enumerate(self.terms)])

def __ne__(self, other):
# type: (Union[PauliTerm, PauliSum]) -> bool
"""Inequality testing to see if two PauliSum's are not equivalent.
:param PauliSum other: The PauliSum to compare this PauliSum with.
:param PauliTerm or PauliSum other: The PauliSum to compare this PauliSum with.
:return: False if other is equivalent to this PauliSum, True otherwise.
:rtype: bool
"""
return not self == other

def __str__(self):
# type: () -> str
return " + ".join([str(term) for term in self.terms])

def __len__(self):
# type () -> int
"""
The length of the PauliSum is the number of PauliTerms in the sum.
"""
return len(self.terms)

def __getitem__(self, item):
# type (int) -> PauliTerm
"""
:param int item: The index of the term in the sum to return
:return: The PauliTerm at the index-th position in the PauliSum
Expand All @@ -422,9 +449,11 @@ def __getitem__(self, item):
return self.terms[item]

def __iter__(self):
# type () -> Iterator[PauliTerm]
return self.terms.__iter__()

def __mul__(self, other):
# type: (Union[PauliSum, PauliTerm, Number]) -> PauliSum
"""
Multiplies together this PauliSum with PauliSum, PauliTerm or Number objects. The new term
is then simplified according to the Pauli Algebra rules.
Expand All @@ -445,6 +474,7 @@ def __mul__(self, other):
return new_sum.simplify()

def __rmul__(self, other):
# type: (Union[PauliSum, PauliTerm, Number]) -> PauliSum
"""
Multiples together this PauliSum with PauliSum, PauliTerm or Number objects. The new term
is then simplified according to the Pauli Algebra rules.
Expand All @@ -460,6 +490,7 @@ def __rmul__(self, other):
return PauliSum(new_terms).simplify()

def __pow__(self, power):
# type: (int) -> PauliSum
"""Raises this PauliSum to power.
:param int power: The power to raise this PauliSum to.
Expand All @@ -485,6 +516,7 @@ def __pow__(self, power):
return result

def __add__(self, other):
# type: (Union[PauliSum, PauliTerm, Number]) -> PauliSum
"""
Adds together this PauliSum with PauliSum, PauliTerm or Number objects. The new term
is then simplified according to the Pauli Algebra rules.
Expand All @@ -503,6 +535,7 @@ def __add__(self, other):
return new_sum.simplify()

def __radd__(self, other):
# type: (Union[PauliSum, PauliTerm, Number]) -> PauliSum
"""
Adds together this PauliSum with PauliSum, PauliTerm or Number objects. The new term
is then simplified according to the Pauli Algebra rules.
Expand All @@ -515,6 +548,7 @@ def __radd__(self, other):
return self + other

def __sub__(self, other):
# type: (Union[PauliSum, PauliTerm, Number]) -> PauliSum
"""
Finds the difference of this PauliSum with PauliSum, PauliTerm or Number objects. The new
term is then simplified according to the Pauli Algebra rules.
Expand All @@ -526,6 +560,7 @@ def __sub__(self, other):
return self + -1. * other

def __rsub__(self, other):
# type: (Union[PauliSum, PauliTerm, Number]) -> PauliSum
"""
Finds the different of this PauliSum with PauliSum, PauliTerm or Number objects. The new
term is then simplified according to the Pauli Algebra rules.
Expand All @@ -537,6 +572,8 @@ def __rsub__(self, other):
return other + -1. * self

def get_qubits(self):
# type () -> List[Any]
# TODO: precisify
"""
The support of all the operators in the PauliSum object.
Expand All @@ -546,6 +583,7 @@ def get_qubits(self):
return list(set().union(*[term.get_qubits() for term in self.terms]))

def simplify(self):
# type: () -> PauliSum
"""
Simplifies the sum of Pauli operators according to Pauli algebra rules.
"""
Expand All @@ -554,15 +592,15 @@ def coalesce(d):
for k in sorted(d):
term_list = d[k]
if (len(term_list) == 1 and not
np.isclose(term_list[0].coefficient, 0.0)):
np.isclose(term_list[0].coefficient, 0.0)):
terms.append(term_list[0])
else:
coeff = sum(t.coefficient for t in term_list)
if not np.isclose(coeff, 0.0):
terms.append(term_with_coeff(term_list[0], coeff))
return PauliSum(terms)

like_terms = {}
like_terms = {} # type: Dict[str, List[PauliTerm]]
for term in self.terms:
id = term.id()
if id not in like_terms:
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ tox==2.9.1
typing==3.6.2
urllib3==1.22
virtualenv==15.1.0
typing==3.6.2
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
tests_require=[
'pytest >= 3.0.0',
'mock',
'typing == 3.6.2',
],
test_suite='pyquil.tests',
entry_points={
Expand Down

0 comments on commit 7c6d394

Please sign in to comment.