Skip to content

Commit 146f034

Browse files
authored
Parallelize similarity transformation code (#434)
* Add more helper functions * Add tests for new functions * Cleanup code * Improved naming * Add function to create a SparseOperator from an ActiveSpaceIntegral object * Merge branch 'main' into mcscf_df * Simplify logic * Fix compilation
1 parent cacbe91 commit 146f034

21 files changed

+561
-196
lines changed

forte/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ sparse_ci/sparse_hamiltonian.cc
278278
sparse_ci/sparse_initial_guess.cc
279279
sparse_ci/sparse_operator.cc
280280
sparse_ci/sparse_operator_sim_trans.cc
281+
sparse_ci/sparse_operator_hamiltonian.cc
281282
sparse_ci/sparse_state.cc
282283
sparse_ci/sq_operator_string.cc
283284
sparse_ci/sq_operator_string_ops.cc

forte/api/determinant_api.cc

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ void export_Determinant(py::module& m) {
9494
const std::vector<int>& bann,
9595
const std::vector<int>& bcre) { return gen_excitation(d, aann, acre, bann, bcre); },
9696
"Apply a generic excitation") // uses gen_excitation() defined in determinant.hpp
97+
.def("spin_flip", &Determinant::spin_flip, "Get the spin-flip determinant")
9798
.def(
9899
"str", [](const Determinant& a, int n) { return str(a, n); },
99100
"n"_a = Determinant::norb(),

forte/api/sparse_operator_api.cc

+6
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@
3333

3434
#include "helpers/string_algorithms.h"
3535

36+
#include "integrals/active_space_integrals.h"
37+
3638
#include "sparse_ci/sparse_operator.h"
3739
#include "sparse_ci/sq_operator_string_ops.h"
40+
#include "sparse_ci/sparse_operator_hamiltonian.h"
3841

3942
namespace py = pybind11;
4043
using namespace pybind11::literals;
@@ -252,6 +255,9 @@ void export_SparseOperator(py::module& m) {
252255
},
253256
"list"_a, "Create a SparseOperator object from a list of Tuple[SQOperatorString, complex]");
254257

258+
m.def("sparse_operator_hamiltonian", &sparse_operator_hamiltonian,
259+
"Create a SparseOperator object from an ActiveSpaceIntegrals object");
260+
255261
m.def("new_product", [](const SparseOperator A, const SparseOperator B) {
256262
SparseOperator C;
257263
SQOperatorProductComputer computer;

forte/api/sparse_operator_list_api.cc

+9-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ void export_SparseOperatorList(py::module& m) {
4949
.def("add", &SparseOperatorList::add_term_from_str, "str"_a,
5050
"coefficient"_a = sparse_scalar_t(1), "allow_reordering"_a = false)
5151
.def("to_operator", &SparseOperatorList::to_operator)
52+
.def(
53+
"remove",
54+
[](SparseOperatorList& op, const std::string& s) {
55+
const auto [sqop, _] = make_sq_operator_string(s, false);
56+
op.remove(sqop);
57+
},
58+
"Remove a specific element from the vector space")
5259
.def("__len__", &SparseOperatorList::size)
5360
.def(
5461
"__iter__",
@@ -85,6 +92,7 @@ void export_SparseOperatorList(py::module& m) {
8592
op[i] = values[i];
8693
}
8794
})
95+
.def("reverse", &SparseOperatorList::reverse, "Reverse the order of the operators")
8896
.def(
8997
"__call__",
9098
[](const SparseOperatorList& op, const size_t n) {
@@ -93,7 +101,7 @@ void export_SparseOperatorList(py::module& m) {
93101
}
94102
return op(n);
95103
},
96-
"Get the nth element");
104+
"Get the nth operator");
97105

98106
m.def(
99107
"operator_list",

forte/api/sparse_state_api.cc

+12-5
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void export_SparseState(py::module& m) {
5050
.def("str", &SparseState::str)
5151
.def("size", &SparseState::size)
5252
.def("norm", &SparseState::norm, "p"_a = 2,
53-
"Calculate the p-norm of the SparseState (default p = 2, p = -1 for infinity norm)")
53+
"Calculate the p-norm of the SparseState (default p = 2, p = -1 for infinity norm)")
5454
.def("add", &SparseState::add)
5555
.def("__iadd__", &SparseState::operator+=, "Add a SparseState to this SparseState")
5656
.def("__isub__", &SparseState::operator-=, "Subtract a SparseState from this SparseState")
@@ -72,12 +72,19 @@ void export_SparseState(py::module& m) {
7272
"screen_thresh"_a = 1.0e-12);
7373

7474
m.def("apply_number_projector", &apply_number_projector);
75+
7576
m.def("get_projection", &get_projection);
7677
// there's already a function called spin2, overload the spin2 function
77-
m.def("spin2", [](const SparseState& left_state, const SparseState& right_state) {
78-
return spin2(left_state, right_state);
79-
}, "Calculate the <left_state|S^2|right_state> expectation value");
78+
79+
m.def(
80+
"spin2",
81+
[](const SparseState& left_state, const SparseState& right_state) {
82+
return spin2(left_state, right_state);
83+
},
84+
"Calculate the <left_state|S^2|right_state> expectation value");
85+
8086
m.def("overlap", &overlap);
81-
m.def("normalize", &normalize, "Returns a normalized version of the input SparseState");
87+
88+
m.def("normalize", &normalize, "Returns a normalized version of the input SparseState");
8289
}
8390
} // namespace forte

forte/api/sq_operator_string_api.cc

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ void export_SQOperatorString(py::module& m) {
4848
.def("str", &SQOperatorString::str, "Get the string representation of the operator string")
4949
.def("count", &SQOperatorString::count, "Get the number of operators")
5050
.def("adjoint", &SQOperatorString::adjoint, "Get the adjoint operator string")
51+
.def("spin_flip", &SQOperatorString::spin_flip, "Get the spin-flipped operator string")
5152
.def("number_component", &SQOperatorString::number_component,
5253
"Get the number component of the operator string")
5354
.def("non_number_component", &SQOperatorString::non_number_component,

forte/helpers/math_structures.h

+13
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,11 @@ template <typename Derived, typename T, typename F> class VectorSpaceList {
345345
/// @return the number of elements in the vector
346346
size_t size() const { return elements_.size(); }
347347

348+
/// @brief Remove a specific element from the vector space
349+
void remove(const T& e) {
350+
std::erase_if(elements_, [&e](const auto& p) { return p.first == e; });
351+
}
352+
348353
/// @return an element of the vector
349354
const F& operator[](size_t n) const { return elements_[n].second; }
350355

@@ -408,6 +413,14 @@ template <typename Derived, typename T, typename F> class VectorSpaceList {
408413
return result;
409414
}
410415

416+
/// @brief Return a reversed copy of the vector
417+
Derived reverse() {
418+
// avoid issues with const
419+
Derived result = static_cast<Derived&>(*this);
420+
std::reverse(result.elements_.begin(), result.elements_.end());
421+
return result;
422+
}
423+
411424
private:
412425
// Using an unordered_map with a custom hash function
413426
container elements_;

forte/sparse_ci/determinant.hpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ template <size_t N> class DeterminantImpl : public BitArray<N> {
537537
}
538538
}
539539

540-
BitArray<nbits_half> get_bits(DetSpinType spin_type) {
540+
BitArray<nbits_half> get_bits(DetSpinType spin_type) const {
541541
return (spin_type == DetSpinType::Alpha ? get_alfa_bits() : get_beta_bits());
542542
}
543543

@@ -552,6 +552,15 @@ template <size_t N> class DeterminantImpl : public BitArray<N> {
552552
for (size_t n = nwords_half; n < nwords_; n++)
553553
words_[n] = u_int64_t(0);
554554
}
555+
556+
/// Swap the alpha and beta bits of a determinant
557+
DeterminantImpl<N> spin_flip() const {
558+
DeterminantImpl<N> d(*this);
559+
for (size_t n = 0; n < nwords_half; n++) {
560+
std::swap(d.words_[n], d.words_[n + nwords_half]);
561+
}
562+
return d;
563+
}
555564
};
556565

557566
// Functions

forte/sparse_ci/sparse.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@
3131
#include <complex>
3232

3333
namespace forte {
34+
35+
// Define the scalar type used in the SparseOperator and SparseState objects
3436
using sparse_scalar_t = std::complex<double>;
3537

36-
// // For double
37-
// double to_double(const double& input) { return input; }
38+
// For double
39+
inline double to_double(const double& input) { return input; }
3840

3941
// For std::complex<double>
40-
template <typename T> double to_double(const T& input) { return std::real(input); }
42+
inline double to_double(const std::complex<double>& input) { return std::real(input); }
4143

4244
} // namespace forte

forte/sparse_ci/sparse_hamiltonian.cc

+2-37
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <cmath>
3030

3131
#include "sparse_ci/sparse_hamiltonian.h"
32+
#include "sparse_ci/sparse_operator_hamiltonian.h"
3233

3334
namespace forte {
3435

@@ -342,43 +343,7 @@ SparseState SparseHamiltonian::compute_on_the_fly(const SparseState& state, doub
342343
std::map<std::string, double> SparseHamiltonian::timings() const { return timings_; }
343344

344345
SparseOperator SparseHamiltonian::to_sparse_operator() const {
345-
SparseOperator H;
346-
size_t nmo = as_ints_->nmo();
347-
348-
H.add_term_from_str("[]", as_ints_->nuclear_repulsion_energy() + as_ints_->scalar_energy() +
349-
as_ints_->frozen_core_energy());
350-
for (size_t p = 0; p < nmo; p++) {
351-
for (size_t q = 0; q < nmo; q++) {
352-
H.add_term_from_str(std::format("{}a+ {}a-", p, q), as_ints_->oei_a(p, q));
353-
H.add_term_from_str(std::format("{}b+ {}b-", p, q), as_ints_->oei_b(p, q));
354-
}
355-
}
356-
357-
for (size_t p = 0; p < nmo; p++) {
358-
for (size_t q = p + 1; q < nmo; q++) {
359-
for (size_t r = 0; r < nmo; r++) {
360-
for (size_t s = r + 1; s < nmo; s++) {
361-
H.add_term_from_str(std::format("{}a+ {}a+ {}a- {}a-", p, q, s, r),
362-
as_ints_->tei_aa(p, q, r, s));
363-
H.add_term_from_str(std::format("{}b+ {}b+ {}b- {}b-", p, q, s, r),
364-
as_ints_->tei_bb(p, q, r, s));
365-
}
366-
}
367-
}
368-
}
369-
370-
for (size_t p = 0; p < nmo; p++) {
371-
for (size_t q = 0; q < nmo; q++) {
372-
for (size_t r = 0; r < nmo; r++) {
373-
for (size_t s = 0; s < nmo; s++) {
374-
H.add_term_from_str(std::format("{}a+ {}b+ {}b- {}a-", p, q, s, r),
375-
as_ints_->tei_ab(p, q, r, s));
376-
}
377-
}
378-
}
379-
}
380-
381-
return H;
346+
return sparse_operator_hamiltonian(as_ints_);
382347
}
383348

384349
} // namespace forte
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* @BEGIN LICENSE
3+
*
4+
* Forte: an open-source plugin to Psi4 (https://github.com/psi4/psi4)
5+
* that implements a variety of quantum chemistry methods for strongly
6+
* correlated electrons.
7+
*
8+
* Copyright (c) 2012-2024 by its authors (see COPYING, COPYING.LESSER, AUTHORS).
9+
*
10+
* The copyrights for code used from other parties are included in
11+
* the corresponding files.
12+
*
13+
* This program is free software: you can redistribute it and/or modify
14+
* it under the terms of the GNU Lesser General Public License as published by
15+
* the Free Software Foundation, either version 3 of the License, or
16+
* (at your option) any later version.
17+
*
18+
* This program is distributed in the hope that it will be useful,
19+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
* GNU Lesser General Public License for more details.
22+
*
23+
* You should have received a copy of the GNU Lesser General Public License
24+
* along with this program. If not, see http://www.gnu.org/licenses/.
25+
*
26+
* @END LICENSE
27+
*/
28+
29+
#include <format>
30+
31+
#include "sparse_ci/sparse_operator_hamiltonian.h"
32+
33+
#include "integrals/active_space_integrals.h"
34+
35+
namespace forte {
36+
37+
SparseOperator sparse_operator_hamiltonian(std::shared_ptr<ActiveSpaceIntegrals> as_ints) {
38+
SparseOperator H;
39+
size_t nmo = as_ints->nmo();
40+
41+
H.add_term_from_str("[]", as_ints->nuclear_repulsion_energy() + as_ints->scalar_energy() +
42+
as_ints->frozen_core_energy());
43+
44+
for (size_t p = 0; p < nmo; p++) {
45+
for (size_t q = 0; q < nmo; q++) {
46+
H.add_term_from_str(std::format("{}a+ {}a-", p, q), as_ints->oei_a(p, q));
47+
H.add_term_from_str(std::format("{}b+ {}b-", p, q), as_ints->oei_b(p, q));
48+
}
49+
}
50+
51+
for (size_t p = 0; p < nmo; p++) {
52+
for (size_t q = p + 1; q < nmo; q++) {
53+
for (size_t r = 0; r < nmo; r++) {
54+
for (size_t s = r + 1; s < nmo; s++) {
55+
H.add_term_from_str(std::format("{}a+ {}a+ {}a- {}a-", p, q, s, r),
56+
as_ints->tei_aa(p, q, r, s));
57+
H.add_term_from_str(std::format("{}b+ {}b+ {}b- {}b-", p, q, s, r),
58+
as_ints->tei_bb(p, q, r, s));
59+
}
60+
}
61+
}
62+
}
63+
64+
for (size_t p = 0; p < nmo; p++) {
65+
for (size_t q = 0; q < nmo; q++) {
66+
for (size_t r = 0; r < nmo; r++) {
67+
for (size_t s = 0; s < nmo; s++) {
68+
H.add_term_from_str(std::format("{}a+ {}b+ {}b- {}a-", p, q, s, r),
69+
as_ints->tei_ab(p, q, r, s));
70+
}
71+
}
72+
}
73+
}
74+
75+
return H;
76+
}
77+
78+
} // namespace forte
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* @BEGIN LICENSE
3+
*
4+
* Forte: an open-source plugin to Psi4 (https://github.com/psi4/psi4)
5+
* that implements a variety of quantum chemistry methods for strongly
6+
* correlated electrons.
7+
*
8+
* Copyright (c) 2012-2024 by its authors (see COPYING, COPYING.LESSER, AUTHORS).
9+
*
10+
* The copyrights for code used from other parties are included in
11+
* the corresponding files.
12+
*
13+
* This program is free software: you can redistribute it and/or modify
14+
* it under the terms of the GNU Lesser General Public License as published by
15+
* the Free Software Foundation, either version 3 of the License, or
16+
* (at your option) any later version.
17+
*
18+
* This program is distributed in the hope that it will be useful,
19+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
* GNU Lesser General Public License for more details.
22+
*
23+
* You should have received a copy of the GNU Lesser General Public License
24+
* along with this program. If not, see http://www.gnu.org/licenses/.
25+
*
26+
* @END LICENSE
27+
*/
28+
29+
#pragma once
30+
31+
#include <memory>
32+
33+
#include "sparse_ci/sparse_operator.h"
34+
35+
namespace forte {
36+
37+
class ActiveSpaceIntegrals;
38+
39+
/// @brief Generate the a SparseOperator representation of the Hamiltonian using integrals from an
40+
/// ActiveSpaceIntegrals object
41+
SparseOperator sparse_operator_hamiltonian(std::shared_ptr<ActiveSpaceIntegrals> as_ints);
42+
43+
} // namespace forte

0 commit comments

Comments
 (0)