Skip to content

Commit 8ef0c8b

Browse files
Emieeelncrubin
andauthored
Added functionality to compute one-norm of qubit/majorana Hamiltonian from molecular integrals (#725)
* Added get_one_norm with tests * format incremental applied * reference to the paper * changed from unittest to pytest * Now pytest works... * My bad... fixed formatting now * anti-symmetric integral implementation and better documentation * Specified input must be RHF or ROHF Hamiltonian * I think everything is good now? * no overloading functions... * type correction * Documented the functions properly * Added Type hints to the functions Co-authored-by: Nicholas Rubin <[email protected]>
1 parent f685ffc commit 8ef0c8b

File tree

5 files changed

+202
-3
lines changed

5 files changed

+202
-3
lines changed

README.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,11 @@ Authors
175175
`Qiming Sun <https://github.com/sunqm>`__ (Caltech),
176176
`Wei Sun <https://github.com/Spaceenter>`__ (Google),
177177
`Daochen Wang <https://github.com/daochenw>`__ (River Lane Research),
178-
`Chris Winkler <https://github.com/quid256>`__ (University of Chicago) and
179-
`Fang Zhang <https://github.com/fangzh-umich>`__ (University of Michigan).
178+
`Chris Winkler <https://github.com/quid256>`__ (University of Chicago),
179+
`Fang Zhang <https://github.com/fangzh-umich>`__ (University of Michigan) and
180+
`Emiel Koridon <https://github.com/Emieeel>`__ (Leiden University).
181+
182+
180183

181184
How to cite
182185
===========

src/openfermion/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
make_reduced_hamiltonian,
3535
)
3636

37-
from openfermion.functionals import contextuality
37+
from openfermion.functionals import (contextuality, get_one_norm_mol,
38+
get_one_norm_mol_woconst, get_one_norm_int,
39+
get_one_norm_int_woconst)
3840

3941
from openfermion.hamiltonians import (
4042
FermiHubbardModel,

src/openfermion/functionals/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@
1111
# limitations under the License.
1212

1313
from .contextuality import is_contextual
14+
15+
from .get_one_norm import (get_one_norm_mol, get_one_norm_mol_woconst,
16+
get_one_norm_int, get_one_norm_int_woconst)
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
"""
13+
Function to calculate the 1-Norm of a molecular Hamiltonian
14+
in spatial orbital basis after fermion-to-qubit transformation. See
15+
https://arxiv.org/abs/2103.14753 for more information on the 1-norm.
16+
"""
17+
18+
import numpy as np
19+
from openfermion import MolecularData
20+
21+
22+
def get_one_norm_mol(molecule: MolecularData):
23+
"""
24+
Returns the 1-Norm of a RHF or ROHF Hamiltonian described in
25+
https://arxiv.org/abs/2103.14753 after a fermion-to-qubit
26+
transformation given a MolecularData class.
27+
28+
Parameters
29+
----------
30+
31+
molecule : MolecularData class representing a molecular Hamiltonian
32+
33+
Returns
34+
-------
35+
one_norm : 1-Norm of the qubit Hamiltonian
36+
"""
37+
return get_one_norm_int(molecule.nuclear_repulsion,
38+
molecule.one_body_integrals,
39+
molecule.two_body_integrals)
40+
41+
42+
def get_one_norm_mol_woconst(molecule: MolecularData):
43+
"""
44+
Returns 1-norm, emitting the constant term in the qubit Hamiltonian.
45+
See get_one_norm_mol.
46+
47+
Parameters
48+
----------
49+
50+
molecule : MolecularData class representing a molecular Hamiltonian
51+
52+
Returns
53+
-------
54+
one_norm : 1-Norm of the qubit Hamiltonian
55+
"""
56+
return get_one_norm_int_woconst(molecule.one_body_integrals,
57+
molecule.two_body_integrals)
58+
59+
60+
def get_one_norm_int(constant: float, one_body_integrals: np.ndarray,
61+
two_body_integrals: np.ndarray):
62+
"""
63+
Returns the 1-Norm of a RHF or ROHF Hamiltonian described in
64+
https://arxiv.org/abs/2103.14753 after a fermion-to-qubit
65+
transformation given nuclear constant, one-body (2D np.array)
66+
and two-body (4D np.array) integrals in spatial orbital basis.
67+
68+
Parameters
69+
----------
70+
constant(float) : Nuclear repulsion or adjustment to constant shift in
71+
Hamiltonian from integrating out core orbitals.
72+
one_body_integrals(ndarray) : An array of the one-electron integrals having
73+
shape of (n_orb, n_orb), where n_orb is the number of spatial orbitals.
74+
two_body_integrals(ndarray) : An array of the two-electron integrals having
75+
shape of (n_orb, n_orb, n_orb, n_orb).
76+
77+
Returns
78+
-------
79+
one_norm : 1-Norm of the qubit Hamiltonian
80+
"""
81+
n_orb = one_body_integrals.shape[0]
82+
83+
htilde = constant
84+
for p in range(n_orb):
85+
htilde += one_body_integrals[p, p]
86+
for q in range(n_orb):
87+
htilde += ((1 / 2 * two_body_integrals[p, q, q, p]) -
88+
(1 / 4 * two_body_integrals[p, q, p, q]))
89+
90+
htildepq = np.zeros(one_body_integrals.shape)
91+
for p in range(n_orb):
92+
for q in range(n_orb):
93+
htildepq[p, q] = one_body_integrals[p, q]
94+
for r in range(n_orb):
95+
htildepq[p, q] += ((two_body_integrals[p, r, r, q]) -
96+
(1 / 2 * two_body_integrals[p, r, q, r]))
97+
98+
one_norm = abs(htilde) + np.sum(np.absolute(htildepq))
99+
100+
anti_sym_integrals = two_body_integrals - np.transpose(
101+
two_body_integrals, (0, 1, 3, 2))
102+
103+
one_norm += 1 / 8 * np.sum(np.absolute(anti_sym_integrals))
104+
one_norm += 1 / 4 * np.sum(np.absolute(two_body_integrals))
105+
106+
return one_norm
107+
108+
109+
def get_one_norm_int_woconst(one_body_integrals: np.ndarray,
110+
two_body_integrals: np.ndarray):
111+
"""
112+
Returns 1-norm, emitting the constant term in the qubit Hamiltonian.
113+
See get_one_norm_int.
114+
115+
Parameters
116+
----------
117+
one_body_integrals(ndarray) : An array of the one-electron integrals having
118+
shape of (n_orb, n_orb), where n_orb is the number of spatial orbitals.
119+
two_body_integrals(ndarray) : An array of the two-electron integrals having
120+
shape of (n_orb, n_orb, n_orb, n_orb).
121+
122+
Returns
123+
-------
124+
one_norm : 1-Norm of the qubit Hamiltonian
125+
"""
126+
n_orb = one_body_integrals.shape[0]
127+
128+
htildepq = np.zeros(one_body_integrals.shape)
129+
for p in range(n_orb):
130+
for q in range(n_orb):
131+
htildepq[p, q] = one_body_integrals[p, q]
132+
for r in range(n_orb):
133+
htildepq[p, q] += ((two_body_integrals[p, r, r, q]) -
134+
(1 / 2 * two_body_integrals[p, r, q, r]))
135+
136+
one_norm = np.sum(np.absolute(htildepq))
137+
138+
anti_sym_integrals = two_body_integrals - np.transpose(
139+
two_body_integrals, (0, 1, 3, 2))
140+
141+
one_norm += 1 / 8 * np.sum(np.absolute(anti_sym_integrals))
142+
one_norm += 1 / 4 * np.sum(np.absolute(two_body_integrals))
143+
144+
return one_norm
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
"""Tests for get_one_norm."""
13+
14+
import os
15+
import pytest
16+
from openfermion import (get_one_norm_mol, get_one_norm_mol_woconst,
17+
get_one_norm_int, get_one_norm_int_woconst,
18+
MolecularData, jordan_wigner)
19+
from openfermion.config import DATA_DIRECTORY
20+
21+
filename = os.path.join(DATA_DIRECTORY, "H1-Li1_sto-3g_singlet_1.45.hdf5")
22+
molecule = MolecularData(filename=filename)
23+
molecular_hamiltonian = molecule.get_molecular_hamiltonian()
24+
qubit_hamiltonian = jordan_wigner(molecular_hamiltonian)
25+
26+
27+
def test_one_norm_from_molecule():
28+
assert qubit_hamiltonian.induced_norm() == pytest.approx(
29+
get_one_norm_mol(molecule))
30+
31+
32+
def test_one_norm_from_ints():
33+
assert qubit_hamiltonian.induced_norm() == pytest.approx(
34+
get_one_norm_int(
35+
molecule.nuclear_repulsion,
36+
molecule.one_body_integrals,
37+
molecule.two_body_integrals,
38+
))
39+
40+
41+
def test_one_norm_woconst():
42+
one_norm_woconst = (qubit_hamiltonian.induced_norm() -
43+
abs(qubit_hamiltonian.constant))
44+
assert one_norm_woconst == pytest.approx(get_one_norm_mol_woconst(molecule))
45+
assert one_norm_woconst == pytest.approx(
46+
get_one_norm_int_woconst(molecule.one_body_integrals,
47+
molecule.two_body_integrals))

0 commit comments

Comments
 (0)