Skip to content

Commit 99c9895

Browse files
authored
Initial release v0.1a0
Submitted on behalf of Jarrod McClean (LBNL), Ryan Babbush (Google), Damian Steiger (ETH, Google), Ian Kivlichan (Harvard University), Thomas Häner (ETH), Vojtech Havlicek, Matthew Neeley (Google), and Wei Sun (Google)
2 parents 4a15bd6 + 929c54c commit 99c9895

File tree

11 files changed

+997
-2
lines changed

11 files changed

+997
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.pyc
2+
.ipynb_*

MANIFEST.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
include COPYING
2+
include COPYING.LESSER
3+
include MANIFEST.in
4+
include README.rst
5+
include requirements.txt
6+
include setup.py
7+
8+
recursive-include fermilibpluginpsi4 *.py _psi4_template*

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
FermiLib Plugin to interface with Psi4
1+
FermiLib plugin to interface with Psi4
22
======================================
33

4-
This repository contains a plugin which allows `FermiLib <http://github.com/ProjectQ-Framework/FermiLib>`__ to interface with the open-source quantum chemistry package `Psi4 <http://www.psicode.org>`__.
4+
This repository contains a plugin which allows `FermiLib <http://github.com/ProjectQ-Framework/FermiLib>`__ (licensed under Apache 2) to interface with the open-source quantum chemistry package `Psi4 <http://www.psicode.org>`__ (licensed under GNU Lesser General Public License version 3).
55

66
License
77
-------

examples/psi4_demo.ipynb

Lines changed: 208 additions & 0 deletions
Large diffs are not rendered by default.

fermilibpluginpsi4/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# FermiLib plugin to interface with Psi4
2+
# Copyright (C) 2017 FermiLib Developers
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
"""
18+
FermiLib plugin to interface with Psi4
19+
"""
20+
21+
from ._version import __version__
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
# FermiLib plugin to interface with Psi4
2+
# Copyright (C) 2017 FermiLib Developers
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
"""Helper functions for parsing data files of different types."""
18+
from __future__ import absolute_import
19+
20+
import numpy
21+
22+
from fermilib.ops import InteractionOperator
23+
24+
25+
def unpack_spatial_rdm(one_rdm_a,
26+
one_rdm_b,
27+
two_rdm_aa,
28+
two_rdm_ab,
29+
two_rdm_bb):
30+
"""
31+
Covert from spin compact spatial format to spin-orbital format for RDM.
32+
33+
Note: the compact 2-RDM is stored as follows where A/B are spin up/down:
34+
RDM[pqrs] = <| a_{p, A}^\dagger a_{r, A}^\dagger a_{q, A} a_{s, A} |>
35+
for 'AA'/'BB' spins.
36+
RDM[pqrs] = <| a_{p, A}^\dagger a_{r, B}^\dagger a_{q, B} a_{s, A} |>
37+
for 'AB' spins.
38+
39+
Args:
40+
one_rdm_a: 2-index numpy array storing alpha spin
41+
sector of 1-electron reduced density matrix.
42+
one_rdm_b: 2-index numpy array storing beta spin
43+
sector of 1-electron reduced density matrix.
44+
two_rdm_aa: 4-index numpy array storing alpha-alpha spin
45+
sector of 2-electron reduced density matrix.
46+
two_rdm_ab: 4-index numpy array storing alpha-beta spin
47+
sector of 2-electron reduced density matrix.
48+
two_rdm_bb: 4-index numpy array storing beta-beta spin
49+
sector of 2-electron reduced density matrix.
50+
51+
Returns:
52+
one_rdm: 2-index numpy array storing 1-electron density matrix
53+
in full spin-orbital space.
54+
two_rdm: 4-index numpy array storing 2-electron density matrix
55+
in full spin-orbital space.
56+
"""
57+
# Initialize RDMs.
58+
n_orbitals = one_rdm_a.shape[0]
59+
n_qubits = 2 * n_orbitals
60+
one_rdm = numpy.zeros((n_qubits, n_qubits))
61+
two_rdm = numpy.zeros((n_qubits, n_qubits,
62+
n_qubits, n_qubits))
63+
64+
# Unpack compact representation.
65+
for p in range(n_orbitals):
66+
for q in range(n_orbitals):
67+
68+
# Populate 1-RDM.
69+
one_rdm[2 * p, 2 * q] = one_rdm_a[p, q]
70+
one_rdm[2 * p + 1, 2 * q + 1] = one_rdm_b[p, q]
71+
72+
# Continue looping to unpack 2-RDM.
73+
for r in range(n_orbitals):
74+
for s in range(n_orbitals):
75+
76+
# Handle case of same spin.
77+
two_rdm[2 * p, 2 * q, 2 * r, 2 * s] = (
78+
two_rdm_aa[p, r, q, s])
79+
two_rdm[2 * p + 1, 2 * q + 1, 2 * r + 1, 2 * s + 1] = (
80+
two_rdm_bb[p, r, q, s])
81+
82+
# Handle case of mixed spin.
83+
two_rdm[2 * p, 2 * q + 1, 2 * r, 2 * s + 1] = (
84+
two_rdm_ab[p, r, q, s])
85+
two_rdm[2 * p, 2 * q + 1, 2 * r + 1, 2 * s] = (
86+
-1. * two_rdm_ab[p, s, q, r])
87+
two_rdm[2 * p + 1, 2 * q, 2 * r + 1, 2 * s] = (
88+
two_rdm_ab[q, s, p, r])
89+
two_rdm[2 * p + 1, 2 * q, 2 * r, 2 * s + 1] = (
90+
-1. * two_rdm_ab[q, r, p, s])
91+
92+
# Map to physicist notation and return.
93+
two_rdm = numpy.einsum('pqsr', two_rdm)
94+
return one_rdm, two_rdm
95+
96+
97+
def parse_psi4_ccsd_amplitudes(number_orbitals,
98+
n_alpha_electrons, n_beta_electrons,
99+
psi_filename):
100+
"""Parse coupled cluster singles and doubles amplitudes from psi4 file.
101+
102+
Args:
103+
number_orbitals(int): Number of total spin orbitals in the system
104+
n_alpha_electrons(int): Number of alpha electrons in the system
105+
n_beta_electrons(int): Number of beta electrons in the system
106+
psi_filename(str): Filename of psi4 output file
107+
108+
Returns:
109+
molecule(InteractionOperator): Molecular Operator instance holding ccsd
110+
amplitudes
111+
112+
"""
113+
output_buffer = [line for line in open(psi_filename)]
114+
115+
T1IA_index = None
116+
T1ia_index = None
117+
T2IJAB_index = None
118+
T2ijab_index = None
119+
T2IjAb_index = None
120+
121+
# Find Start Indices
122+
for i, line in enumerate(output_buffer):
123+
if ('Largest TIA Amplitudes:' in line):
124+
T1IA_index = i
125+
126+
elif ('Largest Tia Amplitudes:' in line):
127+
T1ia_index = i
128+
129+
elif ('Largest TIJAB Amplitudes:' in line):
130+
T2IJAB_index = i
131+
132+
elif ('Largest Tijab Amplitudes:' in line):
133+
T2ijab_index = i
134+
135+
elif ('Largest TIjAb Amplitudes:' in line):
136+
T2IjAb_index = i
137+
138+
T1IA_Amps = []
139+
T1ia_Amps = []
140+
141+
T2IJAB_Amps = []
142+
T2ijab_Amps = []
143+
T2IjAb_Amps = []
144+
145+
# Read T1's
146+
if (T1IA_index is not None):
147+
for line in output_buffer[T1IA_index + 1:]:
148+
ivals = line.split()
149+
if not ivals:
150+
break
151+
T1IA_Amps.append([int(ivals[0]), int(ivals[1]), float(ivals[2])])
152+
153+
if (T1ia_index is not None):
154+
for line in output_buffer[T1ia_index + 1:]:
155+
ivals = line.split()
156+
if not ivals:
157+
break
158+
T1ia_Amps.append([int(ivals[0]), int(ivals[1]), float(ivals[2])])
159+
160+
# Read T2's
161+
if (T2IJAB_index is not None):
162+
for line in output_buffer[T2IJAB_index + 1:]:
163+
ivals = line.split()
164+
if not ivals:
165+
break
166+
T2IJAB_Amps.append([int(ivals[0]), int(ivals[1]),
167+
int(ivals[2]), int(ivals[3]),
168+
float(ivals[4])])
169+
170+
if (T2ijab_index is not None):
171+
for line in output_buffer[T2ijab_index + 1:]:
172+
ivals = line.split()
173+
if not ivals:
174+
break
175+
T2ijab_Amps.append([int(ivals[0]), int(ivals[1]),
176+
int(ivals[2]), int(ivals[3]),
177+
float(ivals[4])])
178+
179+
if (T2IjAb_index is not None):
180+
for line in output_buffer[T2IjAb_index + 1:]:
181+
ivals = line.split()
182+
if not ivals:
183+
break
184+
T2IjAb_Amps.append([int(ivals[0]), int(ivals[1]),
185+
int(ivals[2]), int(ivals[3]),
186+
float(ivals[4])])
187+
188+
# Determine if calculation is restricted / closed shell or otherwise
189+
restricted = T1ia_index is None and T2ijab_index is None
190+
191+
# Store amplitudes with spin-orbital indexing, including appropriate
192+
# symmetry
193+
single_amplitudes = numpy.zeros((number_orbitals, ) * 2)
194+
double_amplitudes = numpy.zeros((number_orbitals, ) * 4)
195+
196+
# Define local helper routines for clear indexing of orbitals
197+
def alpha_occupied(i):
198+
return 2 * i
199+
200+
def alpha_unoccupied(i):
201+
return 2 * (i + n_alpha_electrons)
202+
203+
def beta_occupied(i):
204+
return 2 * i + 1
205+
206+
def beta_unoccupied(i):
207+
return 2 * (i + n_beta_electrons) + 1
208+
209+
# Store singles
210+
for entry in T1IA_Amps:
211+
i, a, value = entry
212+
single_amplitudes[alpha_occupied(i),
213+
alpha_unoccupied(a)] = value
214+
if (restricted):
215+
single_amplitudes[beta_occupied(i),
216+
beta_unoccupied(a)] = value
217+
218+
for entry in T1ia_Amps:
219+
i, a, value = entry
220+
single_amplitudes[beta_occupied(i),
221+
beta_unoccupied(a)] = value
222+
223+
# Store doubles, include factor of 1/2 for convention
224+
for entry in T2IJAB_Amps:
225+
i, j, a, b, value = entry
226+
double_amplitudes[alpha_occupied(i),
227+
alpha_unoccupied(a),
228+
alpha_occupied(j),
229+
alpha_unoccupied(b)] = -value / 2.
230+
if (restricted):
231+
double_amplitudes[beta_occupied(i),
232+
beta_unoccupied(a),
233+
beta_occupied(j),
234+
beta_unoccupied(b)] = -value / 2.
235+
236+
for entry in T2ijab_Amps:
237+
i, j, a, b, value = entry
238+
double_amplitudes[beta_occupied(i),
239+
beta_unoccupied(a),
240+
beta_occupied(j),
241+
beta_unoccupied(b)] = -value / 2.
242+
243+
for entry in T2IjAb_Amps:
244+
i, j, a, b, value = entry
245+
double_amplitudes[alpha_occupied(i),
246+
alpha_unoccupied(a),
247+
beta_occupied(j),
248+
beta_unoccupied(b)] = -value / 2.
249+
250+
if (restricted):
251+
double_amplitudes[beta_occupied(i),
252+
beta_unoccupied(a),
253+
alpha_occupied(j),
254+
alpha_unoccupied(b)] = -value / 2.
255+
256+
# Package into InteractionOperator.
257+
molecule = InteractionOperator(0.0,
258+
single_amplitudes,
259+
double_amplitudes)
260+
return molecule

0 commit comments

Comments
 (0)