diff --git a/README.rst b/README.rst index 2b901301b..0601631fb 100644 --- a/README.rst +++ b/README.rst @@ -175,8 +175,11 @@ Authors `Qiming Sun `__ (Caltech), `Wei Sun `__ (Google), `Daochen Wang `__ (River Lane Research), -`Chris Winkler `__ (University of Chicago) and -`Fang Zhang `__ (University of Michigan). +`Chris Winkler `__ (University of Chicago), +`Fang Zhang `__ (University of Michigan) and +`Emiel Koridon `__ (Leiden University). + + How to cite =========== diff --git a/src/openfermion/__init__.py b/src/openfermion/__init__.py index 1529b5ba6..28e556eb7 100644 --- a/src/openfermion/__init__.py +++ b/src/openfermion/__init__.py @@ -34,7 +34,9 @@ make_reduced_hamiltonian, ) -from openfermion.functionals import contextuality +from openfermion.functionals import (contextuality, get_one_norm_mol, + get_one_norm_mol_woconst, get_one_norm_int, + get_one_norm_int_woconst) from openfermion.hamiltonians import ( FermiHubbardModel, diff --git a/src/openfermion/functionals/__init__.py b/src/openfermion/functionals/__init__.py index 8f8550764..ad11c2d4c 100644 --- a/src/openfermion/functionals/__init__.py +++ b/src/openfermion/functionals/__init__.py @@ -11,3 +11,6 @@ # limitations under the License. from .contextuality import is_contextual + +from .get_one_norm import (get_one_norm_mol, get_one_norm_mol_woconst, + get_one_norm_int, get_one_norm_int_woconst) diff --git a/src/openfermion/functionals/get_one_norm.py b/src/openfermion/functionals/get_one_norm.py new file mode 100755 index 000000000..7eadef57d --- /dev/null +++ b/src/openfermion/functionals/get_one_norm.py @@ -0,0 +1,144 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Function to calculate the 1-Norm of a molecular Hamiltonian +in spatial orbital basis after fermion-to-qubit transformation. See +https://arxiv.org/abs/2103.14753 for more information on the 1-norm. +""" + +import numpy as np +from openfermion import MolecularData + + +def get_one_norm_mol(molecule: MolecularData): + """ + Returns the 1-Norm of a RHF or ROHF Hamiltonian described in + https://arxiv.org/abs/2103.14753 after a fermion-to-qubit + transformation given a MolecularData class. + + Parameters + ---------- + + molecule : MolecularData class representing a molecular Hamiltonian + + Returns + ------- + one_norm : 1-Norm of the qubit Hamiltonian + """ + return get_one_norm_int(molecule.nuclear_repulsion, + molecule.one_body_integrals, + molecule.two_body_integrals) + + +def get_one_norm_mol_woconst(molecule: MolecularData): + """ + Returns 1-norm, emitting the constant term in the qubit Hamiltonian. + See get_one_norm_mol. + + Parameters + ---------- + + molecule : MolecularData class representing a molecular Hamiltonian + + Returns + ------- + one_norm : 1-Norm of the qubit Hamiltonian + """ + return get_one_norm_int_woconst(molecule.one_body_integrals, + molecule.two_body_integrals) + + +def get_one_norm_int(constant: float, one_body_integrals: np.ndarray, + two_body_integrals: np.ndarray): + """ + Returns the 1-Norm of a RHF or ROHF Hamiltonian described in + https://arxiv.org/abs/2103.14753 after a fermion-to-qubit + transformation given nuclear constant, one-body (2D np.array) + and two-body (4D np.array) integrals in spatial orbital basis. + + Parameters + ---------- + constant(float) : Nuclear repulsion or adjustment to constant shift in + Hamiltonian from integrating out core orbitals. + one_body_integrals(ndarray) : An array of the one-electron integrals having + shape of (n_orb, n_orb), where n_orb is the number of spatial orbitals. + two_body_integrals(ndarray) : An array of the two-electron integrals having + shape of (n_orb, n_orb, n_orb, n_orb). + + Returns + ------- + one_norm : 1-Norm of the qubit Hamiltonian + """ + n_orb = one_body_integrals.shape[0] + + htilde = constant + for p in range(n_orb): + htilde += one_body_integrals[p, p] + for q in range(n_orb): + htilde += ((1 / 2 * two_body_integrals[p, q, q, p]) - + (1 / 4 * two_body_integrals[p, q, p, q])) + + htildepq = np.zeros(one_body_integrals.shape) + for p in range(n_orb): + for q in range(n_orb): + htildepq[p, q] = one_body_integrals[p, q] + for r in range(n_orb): + htildepq[p, q] += ((two_body_integrals[p, r, r, q]) - + (1 / 2 * two_body_integrals[p, r, q, r])) + + one_norm = abs(htilde) + np.sum(np.absolute(htildepq)) + + anti_sym_integrals = two_body_integrals - np.transpose( + two_body_integrals, (0, 1, 3, 2)) + + one_norm += 1 / 8 * np.sum(np.absolute(anti_sym_integrals)) + one_norm += 1 / 4 * np.sum(np.absolute(two_body_integrals)) + + return one_norm + + +def get_one_norm_int_woconst(one_body_integrals: np.ndarray, + two_body_integrals: np.ndarray): + """ + Returns 1-norm, emitting the constant term in the qubit Hamiltonian. + See get_one_norm_int. + + Parameters + ---------- + one_body_integrals(ndarray) : An array of the one-electron integrals having + shape of (n_orb, n_orb), where n_orb is the number of spatial orbitals. + two_body_integrals(ndarray) : An array of the two-electron integrals having + shape of (n_orb, n_orb, n_orb, n_orb). + + Returns + ------- + one_norm : 1-Norm of the qubit Hamiltonian + """ + n_orb = one_body_integrals.shape[0] + + htildepq = np.zeros(one_body_integrals.shape) + for p in range(n_orb): + for q in range(n_orb): + htildepq[p, q] = one_body_integrals[p, q] + for r in range(n_orb): + htildepq[p, q] += ((two_body_integrals[p, r, r, q]) - + (1 / 2 * two_body_integrals[p, r, q, r])) + + one_norm = np.sum(np.absolute(htildepq)) + + anti_sym_integrals = two_body_integrals - np.transpose( + two_body_integrals, (0, 1, 3, 2)) + + one_norm += 1 / 8 * np.sum(np.absolute(anti_sym_integrals)) + one_norm += 1 / 4 * np.sum(np.absolute(two_body_integrals)) + + return one_norm diff --git a/src/openfermion/functionals/get_one_norm_test.py b/src/openfermion/functionals/get_one_norm_test.py new file mode 100644 index 000000000..a6727cbb8 --- /dev/null +++ b/src/openfermion/functionals/get_one_norm_test.py @@ -0,0 +1,47 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Tests for get_one_norm.""" + +import os +import pytest +from openfermion import (get_one_norm_mol, get_one_norm_mol_woconst, + get_one_norm_int, get_one_norm_int_woconst, + MolecularData, jordan_wigner) +from openfermion.config import DATA_DIRECTORY + +filename = os.path.join(DATA_DIRECTORY, "H1-Li1_sto-3g_singlet_1.45.hdf5") +molecule = MolecularData(filename=filename) +molecular_hamiltonian = molecule.get_molecular_hamiltonian() +qubit_hamiltonian = jordan_wigner(molecular_hamiltonian) + + +def test_one_norm_from_molecule(): + assert qubit_hamiltonian.induced_norm() == pytest.approx( + get_one_norm_mol(molecule)) + + +def test_one_norm_from_ints(): + assert qubit_hamiltonian.induced_norm() == pytest.approx( + get_one_norm_int( + molecule.nuclear_repulsion, + molecule.one_body_integrals, + molecule.two_body_integrals, + )) + + +def test_one_norm_woconst(): + one_norm_woconst = (qubit_hamiltonian.induced_norm() - + abs(qubit_hamiltonian.constant)) + assert one_norm_woconst == pytest.approx(get_one_norm_mol_woconst(molecule)) + assert one_norm_woconst == pytest.approx( + get_one_norm_int_woconst(molecule.one_body_integrals, + molecule.two_body_integrals))