Repository: quantumlib/OpenFermion
Pull request #693 (2020-12-12 23:11:50)

Type hints hamiltonians
I added type hints to the function parameters and for the function return for some files in Hamiltonians.
I also noticed that the parity parameter is expected to take a value of -1 or 1. It doesn't check whether the actual value is either one of those. It will now throw a ValueError for other values.

google-cla[bot]: 
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

:memo: **Please visit <https://cla.developers.google.com/> to sign.**

Once you've signed (or fixed any issues), please reply here with `@googlebot I signed it!` and we'll verify it.

----

#### What to do if you already signed the CLA

##### Individual signers

*   It's possible we don't have your GitHub username or you're using a different email address on your commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).

##### Corporate signers

*   Your company has a Point of Contact who decides which employees are authorized to participate. Ask your POC to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the Google project maintainer to [go/cla#troubleshoot](http://go/cla#troubleshoot) ([Public version](https://opensource.google/docs/cla/#troubleshoot)).
*   The email used to register you as an authorized contributor must be the email used for the Git commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).
*   The email used to register you as an authorized contributor must also be [attached to your GitHub account](https://github.com/settings/emails).
		

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fquantumlib%2FOpenFermion%2Fpull%2F693) for more info**.

<!-- need_sender_cla -->
subzjee: The Format and Lint check won't pass because of the long type hints that define geometry.
Such as:
`geometry: Optional[List[Tuple[str, Tuple[Union[int, float], Union[int, float], Union[int, float]]]]] = None`
I tried splitting them up into two lines but that's not allowed in Python.

Patch:
diff --git a/src/openfermion/hamiltonians/jellium.py b/src/openfermion/hamiltonians/jellium.py
index bf5f381..9cd2e68 100644
--- a/src/openfermion/hamiltonians/jellium.py
+++ b/src/openfermion/hamiltonians/jellium.py
@@ -11,13 +11,16 @@
 #   limitations under the License.
 """This module constructs Hamiltonians for the uniform electron gas."""
 
+from typing import Optional
+
 import numpy
 
 from openfermion.ops.operators import FermionOperator, QubitOperator
 from openfermion.utils.grid import Grid
 
 
-def wigner_seitz_length_scale(wigner_seitz_radius, n_particles, dimension):
+def wigner_seitz_length_scale(wigner_seitz_radius: float, n_particles: int,
+                              dimension: int) -> float:
     """Function to give length_scale associated with Wigner-Seitz radius.
 
     Args:
@@ -51,7 +54,9 @@ def wigner_seitz_length_scale(wigner_seitz_radius, n_particles, dimension):
     return length_scale
 
 
-def plane_wave_kinetic(grid, spinless=False, e_cutoff=None):
+def plane_wave_kinetic(grid: Grid,
+                       spinless: bool = False,
+                       e_cutoff: Optional[float] = None) -> FermionOperator:
     """Return the kinetic energy operator in the plane wave basis.
 
     Args:
@@ -86,11 +91,12 @@ def plane_wave_kinetic(grid, spinless=False, e_cutoff=None):
     return operator
 
 
-def plane_wave_potential(grid,
-                         spinless=False,
-                         e_cutoff=None,
-                         non_periodic=False,
-                         period_cutoff=None):
+def plane_wave_potential(grid: Grid,
+                         spinless: bool = False,
+                         e_cutoff: float = None,
+                         non_periodic: bool = False,
+                         period_cutoff: Optional[float] = None
+                        ) -> FermionOperator:
     """Return the e-e potential operator in the plane wave basis.
 
     Args:
@@ -184,13 +190,14 @@ def plane_wave_potential(grid,
     return operator
 
 
-def dual_basis_jellium_model(grid,
-                             spinless=False,
-                             kinetic=True,
-                             potential=True,
-                             include_constant=False,
-                             non_periodic=False,
-                             period_cutoff=None):
+def dual_basis_jellium_model(grid: Grid,
+                             spinless: bool = False,
+                             kinetic: bool = True,
+                             potential: bool = True,
+                             include_constant: bool = False,
+                             non_periodic: bool = False,
+                             period_cutoff: Optional[float] = None
+                            ) -> FermionOperator:
     """Return jellium Hamiltonian in the dual basis of arXiv:1706.00023
 
     Args:
@@ -293,7 +300,7 @@ def dual_basis_jellium_model(grid,
     return operator
 
 
-def dual_basis_kinetic(grid, spinless=False):
+def dual_basis_kinetic(grid: Grid, spinless: bool = False) -> FermionOperator:
     """Return the kinetic operator in the dual basis of arXiv:1706.00023.
 
     Args:
@@ -306,10 +313,11 @@ def dual_basis_kinetic(grid, spinless=False):
     return dual_basis_jellium_model(grid, spinless, True, False)
 
 
-def dual_basis_potential(grid,
-                         spinless=False,
-                         non_periodic=False,
-                         period_cutoff=None):
+def dual_basis_potential(grid: Grid,
+                         spinless: bool = False,
+                         non_periodic: bool = False,
+                         period_cutoff: Optional[float] = None
+                        ) -> FermionOperator:
     """Return the potential operator in the dual basis of arXiv:1706.00023
 
     Args:
@@ -326,13 +334,13 @@ def dual_basis_potential(grid,
                                     non_periodic, period_cutoff)
 
 
-def jellium_model(grid,
-                  spinless=False,
-                  plane_wave=True,
-                  include_constant=False,
-                  e_cutoff=None,
-                  non_periodic=False,
-                  period_cutoff=None):
+def jellium_model(grid: Grid,
+                  spinless: bool = False,
+                  plane_wave: bool = True,
+                  include_constant: bool = False,
+                  e_cutoff: float = None,
+                  non_periodic: bool = False,
+                  period_cutoff: Optional[float] = None) -> FermionOperator:
     """Return jellium Hamiltonian as FermionOperator class.
 
     Args:
@@ -367,9 +375,10 @@ def jellium_model(grid,
     return hamiltonian
 
 
-def jordan_wigner_dual_basis_jellium(grid,
-                                     spinless=False,
-                                     include_constant=False):
+def jordan_wigner_dual_basis_jellium(grid: Grid,
+                                     spinless: bool = False,
+                                     include_constant: bool = False
+                                    ) -> QubitOperator:
     """Return the jellium Hamiltonian as QubitOperator in the dual basis.
 
     Args:
@@ -482,11 +491,11 @@ def jordan_wigner_dual_basis_jellium(grid,
 
 
 def hypercube_grid_with_given_wigner_seitz_radius_and_filling(
-        dimension,
-        grid_length,
-        wigner_seitz_radius,
-        filling_fraction=0.5,
-        spinless=True):
+        dimension: int,
+        grid_length: int,
+        wigner_seitz_radius: float,
+        filling_fraction: float = 0.5,
+        spinless: bool = True) -> Grid:
     """Return a Grid with the same number of orbitals along each dimension
     with the specified Wigner-Seitz radius.
 
diff --git a/src/openfermion/hamiltonians/mean_field_dwave.py b/src/openfermion/hamiltonians/mean_field_dwave.py
index 972fde6..43d146b 100644
--- a/src/openfermion/hamiltonians/mean_field_dwave.py
+++ b/src/openfermion/hamiltonians/mean_field_dwave.py
@@ -10,6 +10,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 """This module constructs Hamiltonians for the BCS mean-field d-wave model."""
+from typing import Optional
 
 from openfermion.ops.operators import FermionOperator
 from openfermion.utils.indexing import down_index, up_index
@@ -19,12 +20,12 @@ from openfermion.hamiltonians.special_operators import number_operator
 import openfermion.utils as op_utils
 
 
-def mean_field_dwave(x_dimension,
-                     y_dimension,
-                     tunneling,
-                     sc_gap,
-                     chemical_potential=0.,
-                     periodic=True):
+def mean_field_dwave(x_dimension: int,
+                     y_dimension: int,
+                     tunneling: float,
+                     sc_gap: float,
+                     chemical_potential: Optional[float] = 0.,
+                     periodic: bool = True) -> FermionOperator:
     r"""Return symbolic representation of a BCS mean-field d-wave Hamiltonian.
 
     The Hamiltonians of this model live on a grid of dimensions
diff --git a/src/openfermion/hamiltonians/plane_wave_hamiltonian.py b/src/openfermion/hamiltonians/plane_wave_hamiltonian.py
index a1006ef..c15a987 100644
--- a/src/openfermion/hamiltonians/plane_wave_hamiltonian.py
+++ b/src/openfermion/hamiltonians/plane_wave_hamiltonian.py
@@ -10,21 +10,26 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 """Construct Hamiltonians in plan wave basis and its dual in 3D."""
+from typing import List, Tuple, Optional, Union
+
 import numpy as np
 
 from openfermion.hamiltonians.jellium import (jellium_model,
                                               jordan_wigner_dual_basis_jellium)
 from openfermion.ops.operators import FermionOperator, QubitOperator
 from openfermion.transforms.repconversions import inverse_fourier_transform
+from openfermion.utils.grid import Grid
 
 import openfermion.chem.molecular_data as md
 
 
-def dual_basis_external_potential(grid,
-                                  geometry,
-                                  spinless,
-                                  non_periodic=False,
-                                  period_cutoff=None):
+def dual_basis_external_potential(
+        grid: Grid,
+        geometry: List[Tuple[str, Tuple[Union[int, float], Union[int, float],
+                                        Union[int, float]]]],
+        spinless: bool,
+        non_periodic: bool = False,
+        period_cutoff: Optional[float] = None) -> FermionOperator:
     """Return the external potential in the dual basis of arXiv:1706.00023.
 
     The external potential resulting from electrons interacting with nuclei
@@ -80,12 +85,14 @@ def dual_basis_external_potential(grid,
     return operator
 
 
-def plane_wave_external_potential(grid,
-                                  geometry,
-                                  spinless,
-                                  e_cutoff=None,
-                                  non_periodic=False,
-                                  period_cutoff=None):
+def plane_wave_external_potential(
+        grid: Grid,
+        geometry: List[Tuple[str, Tuple[Union[int, float], Union[int, float],
+                                        Union[int, float]]]],
+        spinless: bool,
+        e_cutoff: Optional[float] = None,
+        non_periodic: bool = False,
+        period_cutoff: Optional[float] = None) -> FermionOperator:
     """Return the external potential operator in plane wave basis.
 
     The external potential resulting from electrons interacting with nuclei.
@@ -116,14 +123,16 @@ def plane_wave_external_potential(grid,
     return operator
 
 
-def plane_wave_hamiltonian(grid,
-                           geometry=None,
-                           spinless=False,
-                           plane_wave=True,
-                           include_constant=False,
-                           e_cutoff=None,
-                           non_periodic=False,
-                           period_cutoff=None):
+def plane_wave_hamiltonian(
+        grid: Grid,
+        geometry: Optional[List[Tuple[str, Tuple[
+            Union[int, float], Union[int, float], Union[int, float]]]]] = None,
+        spinless: bool = False,
+        plane_wave: bool = True,
+        include_constant: bool = False,
+        e_cutoff: Optional[float] = None,
+        non_periodic: bool = False,
+        period_cutoff: Optional[float] = None) -> FermionOperator:
     """Returns Hamiltonian as FermionOperator class.
 
     Args:
@@ -168,10 +177,12 @@ def plane_wave_hamiltonian(grid,
     return jellium_op + external_potential
 
 
-def jordan_wigner_dual_basis_hamiltonian(grid,
-                                         geometry=None,
-                                         spinless=False,
-                                         include_constant=False):
+def jordan_wigner_dual_basis_hamiltonian(
+        grid: Grid,
+        geometry: Optional[List[Tuple[str, Tuple[
+            Union[int, float], Union[int, float], Union[int, float]]]]] = None,
+        spinless: bool = False,
+        include_constant: bool = False) -> QubitOperator:
     """Return the dual basis Hamiltonian as QubitOperator.
 
     Args:
diff --git a/src/openfermion/hamiltonians/special_operators.py b/src/openfermion/hamiltonians/special_operators.py
index e5f9f39..1dc0190 100644
--- a/src/openfermion/hamiltonians/special_operators.py
+++ b/src/openfermion/hamiltonians/special_operators.py
@@ -10,11 +10,13 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 """Commonly used operators (mainly instances of SymbolicOperator)."""
+from typing import Optional, Union, Tuple
+
 from openfermion.ops.operators import BosonOperator, FermionOperator
 from openfermion.utils.indexing import down_index, up_index
 
 
-def s_plus_operator(n_spatial_orbitals):
+def s_plus_operator(n_spatial_orbitals: int) -> FermionOperator:
     r"""Return the s+ operator.
 
     .. math::
@@ -44,7 +46,7 @@ def s_plus_operator(n_spatial_orbitals):
     return operator
 
 
-def s_minus_operator(n_spatial_orbitals):
+def s_minus_operator(n_spatial_orbitals: int) -> FermionOperator:
     r"""Return the s+ operator.
 
     .. math::
@@ -74,7 +76,7 @@ def s_minus_operator(n_spatial_orbitals):
     return operator
 
 
-def sx_operator(n_spatial_orbitals):
+def sx_operator(n_spatial_orbitals: int) -> FermionOperator:
     r"""Return the sx operator.
 
     .. math::
@@ -107,7 +109,7 @@ def sx_operator(n_spatial_orbitals):
     return operator
 
 
-def sy_operator(n_spatial_orbitals):
+def sy_operator(n_spatial_orbitals: int) -> FermionOperator:
     r"""Return the sy operator.
 
     .. math::
@@ -140,7 +142,7 @@ def sy_operator(n_spatial_orbitals):
     return operator
 
 
-def sz_operator(n_spatial_orbitals):
+def sz_operator(n_spatial_orbitals: int) -> FermionOperator:
     r"""Return the sz operator.
 
     .. math::
@@ -172,7 +174,7 @@ def sz_operator(n_spatial_orbitals):
     return operator
 
 
-def s_squared_operator(n_spatial_orbitals):
+def s_squared_operator(n_spatial_orbitals: int) -> FermionOperator:
     r"""Return the s^{2} operator.
 
     .. math::
@@ -203,7 +205,8 @@ def s_squared_operator(n_spatial_orbitals):
     return operator
 
 
-def majorana_operator(term=None, coefficient=1.):
+def majorana_operator(term: Optional[Union[Tuple[int, int], str]] = None,
+                      coefficient=1.) -> FermionOperator:
     r"""Initialize a Majorana operator.
 
     Args:
@@ -270,7 +273,10 @@ def majorana_operator(term=None, coefficient=1.):
         raise ValueError('Operator specified incorrectly.')
 
 
-def number_operator(n_modes, mode=None, coefficient=1., parity=-1):
+def number_operator(n_modes: int,
+                    mode: Optional[int] = None,
+                    coefficient=1.,
+                    parity: int = -1) -> Union[BosonOperator, FermionOperator]:
     """Return a fermionic or bosonic number operator.
 
     Args:
@@ -285,10 +291,13 @@ def number_operator(n_modes, mode=None, coefficient=1., parity=-1):
     Returns:
         operator (BosonOperator or FermionOperator)
     """
+
     if parity == -1:
         Op = FermionOperator
     elif parity == 1:
         Op = BosonOperator
+    else:
+        raise ValueError('Invalid parity value: {}'.format(parity))
 
     if mode is None:
         operator = Op()


Test patch:
diff --git a/src/openfermion/hamiltonians/special_operators_test.py b/src/openfermion/hamiltonians/special_operators_test.py
index 696833f..185bdcc 100644
--- a/src/openfermion/hamiltonians/special_operators_test.py
+++ b/src/openfermion/hamiltonians/special_operators_test.py
@@ -145,6 +145,10 @@ class NumberOperatorTest(unittest.TestCase):
                 ((3, 1), (3, 0))))
         self.assertTrue(op == expected)
 
+    def test_bad_parity(self):
+        with self.assertRaises(ValueError):
+            number_operator(4, parity=2)
+
 
 class MajoranaOperatorTest(unittest.TestCase):
 
@@ -182,4 +186,4 @@ class MajoranaOperatorTest(unittest.TestCase):
         with self.assertRaises(ValueError):
             majorana_operator('a')
         with self.assertRaises(ValueError):
-            majorana_operator(2)
+            majorana_operator(2)
\ No newline at end of file