Skip to content

Commit 9008253

Browse files
authored
Generate truncated hilbert spaces (#448)
* add truncation to hilbert space * ordering * add sanity checks, large test * Missed static cast * review response * review response * add truncated test with sym
1 parent a3f698f commit 9008253

File tree

5 files changed

+153
-10
lines changed

5 files changed

+153
-10
lines changed

forte/api/determinant_api.cc

+20-3
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,26 @@ void export_Determinant(py::module& m) {
166166
.def("get_idx", &DeterminantHashVec::get_idx, " Return the index of a determinant");
167167

168168
m.def(
169-
"hilbert_space", &make_hilbert_space, "nmo"_a, "na"_a, "nb"_a, "nirrep"_a = 1,
169+
"hilbert_space",
170+
[](size_t nmo, size_t na, size_t nb, size_t nirrep, std::vector<int> mo_symmetry,
171+
int symmetry) { return make_hilbert_space(nmo, na, nb, nirrep, mo_symmetry, symmetry); },
172+
"nmo"_a, "na"_a, "nb"_a, "nirrep"_a = 1, "mo_symmetry"_a = std::vector<int>(),
173+
"symmetry"_a = 0,
174+
"Generate the Hilbert space for a given number of electrons and orbitals."
175+
"If information about the symmetry of the MOs is not provided, it assumes that all MOs "
176+
"have symmetry 0.");
177+
m.def(
178+
"hilbert_space",
179+
[](size_t nmo, size_t na, size_t nb, Determinant ref, int truncation, size_t nirrep,
180+
std::vector<int> mo_symmetry, int symmetry) {
181+
return make_hilbert_space(nmo, na, nb, ref, truncation, nirrep, mo_symmetry, symmetry);
182+
},
183+
"nmo"_a, "na"_a, "nb"_a, "ref"_a, "truncation"_a, "nirrep"_a = 1,
170184
"mo_symmetry"_a = std::vector<int>(), "symmetry"_a = 0,
171-
"Generate the Hilbert space for a given number of electrons and orbitals. If information "
172-
"about the symmetry of the MOs is not provided, it assumes that all MOs have symmetry 0.");
185+
"Generate the Hilbert space for a given number of electrons, orbitals, and the truncation "
186+
"level."
187+
"If information about the symmetry of the MOs is not provided, it assumes that all MOs "
188+
"have symmetry 0."
189+
"A reference determinant must be provided to establish the excitation rank.");
173190
}
174191
} // namespace forte

forte/helpers/determinant_helpers.cc

+46
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,52 @@ std::vector<std::vector<String>> make_strings(int n, int k, size_t nirrep,
112112
return strings;
113113
}
114114

115+
std::vector<Determinant> make_hilbert_space(size_t nmo, size_t na, size_t nb, Determinant ref, int truncation,
116+
size_t nirrep, std::vector<int> mo_symmetry, int symmetry) {
117+
std::vector<Determinant> dets;
118+
if (mo_symmetry.size() != nmo) {
119+
mo_symmetry = std::vector<int>(nmo, 0);
120+
}
121+
// find the maximum value in mo_symmetry and check that it is less than nirrep
122+
int max_sym = *std::max_element(mo_symmetry.begin(), mo_symmetry.end());
123+
if (max_sym >= static_cast<int>(nirrep)) {
124+
throw std::runtime_error("The symmetry of the MOs is greater than the number of irreps.");
125+
}
126+
// implement other sensible checks, like making sure that symmetry is less than nirrep and na <=
127+
// nmo, nb <= nmo
128+
if (symmetry >= static_cast<int>(nirrep)) {
129+
throw std::runtime_error(
130+
"The symmetry of the determinants is greater than the number of irreps.");
131+
}
132+
if (na > nmo) {
133+
throw std::runtime_error(
134+
"The number of alpha electrons is greater than the number of MOs.");
135+
}
136+
if (nb > nmo) {
137+
throw std::runtime_error("The number of beta electrons is greater than the number of MOs.");
138+
}
139+
if (truncation < 0 || truncation > static_cast<int>(na + nb)) {
140+
throw std::runtime_error("The truncation level must an integer between 0 and na + nb.");
141+
}
142+
143+
auto strings_a = make_strings(nmo, na, nirrep, mo_symmetry);
144+
auto strings_b = make_strings(nmo, nb, nirrep, mo_symmetry);
145+
for (size_t ha = 0; ha < nirrep; ha++) {
146+
int hb = symmetry ^ ha;
147+
for (const auto& Ia : strings_a[ha]) {
148+
Determinant det;
149+
det.set_alfa_str(Ia);
150+
for (const auto& Ib : strings_b[hb]) {
151+
det.set_beta_str(Ib);
152+
if (det.fast_a_xor_b_count(ref) / 2 <= truncation) {
153+
dets.push_back(det);
154+
}
155+
}
156+
}
157+
}
158+
return dets;
159+
}
160+
115161
std::vector<Determinant> make_hilbert_space(size_t nmo, size_t na, size_t nb, size_t nirrep,
116162
std::vector<int> mo_symmetry, int symmetry) {
117163
std::vector<Determinant> dets;

forte/helpers/determinant_helpers.h

+17-3
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,26 @@ std::vector<std::vector<String>> make_strings(int n, int k, size_t nirrep,
6565
/// @param nmo The number of orbitals
6666
/// @param na The number of alpha electrons
6767
/// @param nb The number of beta electrons
68-
/// @param nirrep The number of irreps
69-
/// @param mo_symmetry The symmetry of the MOs
70-
/// @param symmetry The symmetry of the determinants
68+
/// @param nirrep The number of irreps (optional)
69+
/// @param mo_symmetry The symmetry of the MOs (optional)
70+
/// @param symmetry The symmetry of the determinants (optional)
7171
/// @return A vector of determinants
7272
std::vector<Determinant> make_hilbert_space(size_t nmo, size_t na, size_t nb, size_t nirrep = 1,
7373
std::vector<int> mo_symmetry = std::vector<int>(),
7474
int symmetry = 0);
7575

76+
/// @brief Generate the Hilbert space for a given number of electrons and orbitals
77+
/// @param nmo The number of orbitals
78+
/// @param na The number of alpha electrons
79+
/// @param nb The number of beta electrons
80+
/// @param ref The reference determinant
81+
/// @param truncation The excitation level truncation
82+
/// @param nirrep The number of irreps (optional)
83+
/// @param mo_symmetry The symmetry of the MOs (optional)
84+
/// @param symmetry The symmetry of the determinants (optional)
85+
/// @return A vector of determinants
86+
std::vector<Determinant> make_hilbert_space(size_t nmo, size_t na, size_t nb, Determinant ref, int truncation,
87+
size_t nirrep = 1, std::vector<int> mo_symmetry = std::vector<int>(),
88+
int symmetry = 0);
89+
7690
} // namespace forte

forte/sparse_ci/determinant.hpp

+12
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,18 @@ template <size_t N> class DeterminantImpl : public BitArray<N> {
177177
}
178178
}
179179

180+
void set_alfa_str(const BitArray<nbits_half>& sa) {
181+
for (size_t n = 0; n < nwords_half; n++) {
182+
words_[n] = sa.get_word(n);
183+
}
184+
}
185+
186+
void set_beta_str(const BitArray<nbits_half>& sb) {
187+
for (size_t n = 0; n < nwords_half; n++) {
188+
words_[n + nwords_half] = sb.get_word(n);
189+
}
190+
}
191+
180192
void set(std::initializer_list<size_t> alfa_list, std::initializer_list<size_t> beta_list) {
181193
zero();
182194
for (auto i : alfa_list) {

tests/pytest/determinant/test_hilbert_space.py

+58-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,43 @@
33
from forte import det
44

55

6-
def test_determinant_hilber_space():
6+
def test_determinant_hilbert_space():
77
dets = forte.hilbert_space(2, 1, 1)
88
# compare with the expected result of the determinant
99
expected = [det("20"), det("+-"), det("-+"), det("02")]
1010
assert len(dets) == 4
1111
assert sorted(dets) == sorted(expected)
1212

13+
# non-aufbau case
14+
ref = det("002")
15+
dets = forte.hilbert_space(3, 1, 1, ref, truncation=2)
16+
expected = [
17+
det("002"),
18+
det("0+-"),
19+
det("0-+"),
20+
det("+0-"),
21+
det("-0+"),
22+
det("020"),
23+
det("200"),
24+
det("+-0"),
25+
det("-+0"),
26+
]
27+
assert len(dets) == 9
28+
assert sorted(dets) == sorted(expected)
29+
30+
ref = det("0+-")
31+
dets = forte.hilbert_space(3, 1, 1, ref, truncation=1)
32+
expected = [det("0+-"), det("-+0"), det("+0-"), det("002"), det("020")]
33+
assert len(dets) == 5
34+
assert sorted(dets) == sorted(expected)
35+
36+
ref = det("20")
37+
dets = forte.hilbert_space(2, 1, 1, ref, truncation=1)
38+
# compare with the expected result of the determinant
39+
expected = [det("20"), det("+-"), det("-+")]
40+
assert len(dets) == 3, dets
41+
assert sorted(dets) == sorted(expected)
42+
1343
dets = forte.hilbert_space(2, 1, 1, nirrep=2, mo_symmetry=[0, 1], symmetry=0)
1444
# compare with the expected result of the determinant
1545
expected = [det("20"), det("02")]
@@ -22,12 +52,29 @@ def test_determinant_hilber_space():
2252
assert len(dets) == 2
2353
assert sorted(dets) == sorted(expected)
2454

55+
ref = det("22000")
56+
dets = forte.hilbert_space(5, 2, 2, ref, truncation=1, nirrep=4, mo_symmetry=[0, 1, 2, 3, 0], symmetry=2)
57+
# compare with the expected result of the determinant
58+
expected = [det("2+0-0"), det("2-0+0"), det("+2-00"), det("-2+00")]
59+
assert len(dets) == 4
60+
assert sorted(dets) == sorted(expected)
61+
2562
# test with the case of 6 electrons and 6 orbitals
2663
dets = forte.hilbert_space(6, 3, 3, 8, [0, 2, 3, 5, 6, 7], 0)
2764
assert len(dets) == 56
2865

66+
# test with the case of 6 electrons and 7 orbitals, truncated to 2 excitations
67+
ref = det("2220000")
68+
dets = forte.hilbert_space(7, 3, 3, ref, truncation=2)
69+
assert len(dets) == 205
70+
71+
# test with the case of 16 electrons and 18 orbitals, truncated to 3 excitations
72+
ref = det("2" * 8 + "0" * 10)
73+
dets = forte.hilbert_space(18, 8, 8, ref, truncation=3)
74+
assert len(dets) == 224121
2975

30-
def test_determinant_hilber_space_edge_cases():
76+
77+
def test_determinant_hilbert_space_edge_cases():
3178
dets = forte.hilbert_space(1, 1, 1)
3279
# compare with the expected result of the determinant
3380
expected = [det("2")]
@@ -57,7 +104,14 @@ def test_determinant_hilber_space_edge_cases():
57104
assert len(dets) == 6
58105
assert sorted(dets) == sorted(expected)
59106

107+
ref = det("++00")
108+
dets = forte.hilbert_space(4, 2, 0, ref, truncation=1)
109+
# compare with the expected result of the determinant
110+
expected = [det("++00"), det("+0+0"), det("+00+"), det("0++0"), det("0+0+")]
111+
assert len(dets) == 5
112+
assert sorted(dets) == sorted(expected)
113+
60114

61115
if __name__ == "__main__":
62-
test_determinant_hilber_space()
63-
test_determinant_hilber_space_edge_cases()
116+
test_determinant_hilbert_space()
117+
test_determinant_hilbert_space_edge_cases()

0 commit comments

Comments
 (0)