diff --git a/pyquil/paulis.py b/pyquil/paulis.py index c2fadc922..4284e010c 100644 --- a/pyquil/paulis.py +++ b/pyquil/paulis.py @@ -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', @@ -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. @@ -63,15 +66,16 @@ 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. @@ -79,7 +83,7 @@ def id(self): :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 = "" @@ -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): @@ -97,12 +102,14 @@ 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. @@ -110,6 +117,7 @@ def __len__(self): return len(self._ops) def copy(self): + # type: () -> PauliTerm """ Properly creates a new PauliTerm, with a completely new dictionary of operators @@ -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() @@ -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. @@ -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 @@ -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. @@ -209,6 +224,7 @@ 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 @@ -216,7 +232,7 @@ def __add__(self, 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: @@ -224,6 +240,7 @@ def __add__(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 @@ -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 @@ -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 @@ -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)) @@ -347,6 +367,7 @@ def sZ(q): def term_with_coeff(term, coeff): + # type: (PauliTerm, Number) -> PauliTerm """ Change the coefficient of a PauliTerm. @@ -368,6 +389,7 @@ class PauliSum(object): """ def __init__(self, terms): + # type: (List[PauliTerm]) -> None """ :param Sequence terms: A Sequence of PauliTerms. """ @@ -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 """ @@ -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 @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. """ @@ -554,7 +592,7 @@ 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) @@ -562,7 +600,7 @@ def coalesce(d): 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: diff --git a/requirements.txt b/requirements.txt index 25fdce510..5a475e183 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,3 +27,4 @@ tox==2.9.1 typing==3.6.2 urllib3==1.22 virtualenv==15.1.0 +typing==3.6.2 diff --git a/setup.py b/setup.py index 1bd576733..83989d233 100755 --- a/setup.py +++ b/setup.py @@ -42,6 +42,7 @@ tests_require=[ 'pytest >= 3.0.0', 'mock', + 'typing == 3.6.2', ], test_suite='pyquil.tests', entry_points={