Skip to content

Commit

Permalink
Merge pull request #256 from Krzmbrzl/benchmarks
Browse files Browse the repository at this point in the history
More benchmarks
  • Loading branch information
Krzmbrzl authored Feb 10, 2025
2 parents c70044d + 014f830 commit 97e0755
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 17 deletions.
26 changes: 13 additions & 13 deletions SeQuant/core/wick.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ class WickTheorem {
"get_default_context().spbasis() should be used to specify spin-free "
"basis")]] WickTheorem &
spinfree(bool sf) {
if (!((sf && get_default_context().spbasis() == SPBasis::spinfree) ||
(!sf && get_default_context().spbasis() == SPBasis::spinorbital))) {
if (!((sf && get_default_context(S).spbasis() == SPBasis::spinfree) ||
(!sf && get_default_context(S).spbasis() == SPBasis::spinorbital))) {
throw std::invalid_argument(
"WickTheorem::spinfree(sf): sf must match the contents of "
"get_default_context().spbasis() (N.B. WickTheorem::spinfree() is "
Expand Down Expand Up @@ -567,10 +567,10 @@ class WickTheorem {
ExprPtr compute_nopseq(const bool count_only) const {
// precondition 1: spin-free version only supported for physical and Fermi
// vacua
if (get_default_context().spbasis() == SPBasis::spinfree &&
!(get_default_context().vacuum() == Vacuum::Physical ||
if (get_default_context(S).spbasis() == SPBasis::spinfree &&
!(get_default_context(S).vacuum() == Vacuum::Physical ||
(S == Statistics::FermiDirac &&
get_default_context().vacuum() == Vacuum::SingleProduct)))
get_default_context(S).vacuum() == Vacuum::SingleProduct)))
throw std::logic_error(
"WickTheorem::compute: spinfree=true supported only for physical "
"vacuum and for Fermi facuum");
Expand Down Expand Up @@ -1373,9 +1373,9 @@ class WickTheorem {
// for spinfree Wick over Fermi vacuum, we need to
// include extra x2 factor for each cycle
if (S == Statistics::FermiDirac &&
get_default_context().vacuum() ==
get_default_context(S).vacuum() ==
Vacuum::SingleProduct &&
get_default_context().spbasis() ==
get_default_context(S).spbasis() ==
SPBasis::spinfree) {
auto [target_partner_indices, ncycles] =
state.make_target_partner_indices();
Expand Down Expand Up @@ -1404,9 +1404,9 @@ class WickTheorem {
// for spinfree Wick over Fermi vacuum, we need to
// include extra x2 factor for each cycle
if (ncycles > 0 &&
get_default_context().vacuum() ==
get_default_context(S).vacuum() ==
Vacuum::SingleProduct &&
get_default_context().spbasis() ==
get_default_context(S).spbasis() ==
SPBasis::spinfree) {
scalar_prefactor *= 1 << ncycles;
}
Expand Down Expand Up @@ -1475,8 +1475,8 @@ class WickTheorem {

public:
static bool can_contract(const Op<S> &left, const Op<S> &right,
Vacuum vacuum = get_default_context().vacuum()) {
const auto &isr = get_default_context().index_space_registry();
Vacuum vacuum = get_default_context(S).vacuum()) {
const auto &isr = get_default_context(S).index_space_registry();
// for bosons can only do Wick's theorem for physical vacuum (or similar)
if constexpr (statistics == Statistics::BoseEinstein)
assert(vacuum == Vacuum::Physical);
Expand All @@ -1491,8 +1491,8 @@ class WickTheorem {
}

static ExprPtr contract(const Op<S> &left, const Op<S> &right,
Vacuum vacuum = get_default_context().vacuum()) {
const auto &isr = get_default_context().index_space_registry();
Vacuum vacuum = get_default_context(S).vacuum()) {
const auto &isr = get_default_context(S).index_space_registry();
assert(can_contract(left, right, vacuum));
// assert(
// !left.index().has_proto_indices() &&
Expand Down
8 changes: 8 additions & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
include(FindOrFetchGoogleBenchmark)

add_executable(sequant_benchmarks
"canonicalize.cpp"
"main.cpp"
"simplify.cpp"
"spintrace.cpp"
"wick.cpp"
)

# The benchmark implementations contain a bunch of same-name symbol definition that
# ought to be local to the individual translation unit. Hence, we must not combine
# all of them into a single translation unit.
set_target_properties(sequant_benchmarks PROPERTIES UNITY_BUILD OFF)

target_link_libraries(sequant_benchmarks
PRIVATE
benchmark::benchmark
Expand Down
47 changes: 47 additions & 0 deletions benchmarks/canonicalize.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include <benchmark/benchmark.h>

#include <SeQuant/core/expr.hpp>
#include <SeQuant/core/expr_algorithm.hpp>
#include <SeQuant/core/parse.hpp>

using namespace sequant;

static constexpr std::size_t nInputs = 6;

static ExprPtr get_expression(std::size_t i) {
switch (i) {
case 1:
return parse_expr(L"g{a1,i5;i6,p12}:A");
case 2:
return parse_expr(L"g{a1,i5;i6,p12}:A t{i6,i7;a1,a2}:A");
case 3:
return parse_expr(
L"A{i1,i2;a1,a2}:A g{i3,i4;a3,a4}:A t{a1,a3;i3,i4}:A "
L"t{a2,a4;i1,i2}:A");
case 4:
return parse_expr(
L"A{i1,i2;a1,a2}:A DF{i3;a3;p1} DF{i4;a4;p1} t{a1;i3} t{a3;i4} "
L"t{a2;i1} t{a4;i2}");
case 5:
return parse_expr(L"g{i3,i4;a3<i1,i4>,a4<i2>} s{a1<i1,i2>;a5<i3>}");
case 6:
return parse_expr(
L"s{a2<i1,i2>;a6<i2,i4>} g{i3,i4;a3<i2,i4>,a4<i1,i3>} "
L"t{a3<i2,i4>,a6<i2,i4>;i4,i2}");
}

throw "Invalid index";
}

static void canonicalize(benchmark::State &state) {
ExprPtr input = get_expression(state.range(0));

for (auto _ : state) {
ExprPtr canonicalized = canonicalize(input->clone());

// Prevent canonicalization from being optimized away by the compiler
benchmark::DoNotOptimize(canonicalized);
}
}

BENCHMARK(canonicalize)->DenseRange(1, nInputs);
11 changes: 9 additions & 2 deletions benchmarks/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@ int main(int argc, char *argv[]) {
// Disable multithreading
set_num_threads(1);
set_locale();
set_default_context(Context(mbpt::make_sr_spaces(), Vacuum::SingleProduct,
Context fermi_ctx = Context(mbpt::make_sr_spaces(), Vacuum::SingleProduct,
IndexSpaceMetric::Unit, BraKetSymmetry::nonsymm,
SPBasis::spinorbital));
SPBasis::spinorbital);
set_default_context(fermi_ctx);

Context bose_einstein_ctx =
Context(mbpt::make_sr_spaces(), Vacuum::Physical, IndexSpaceMetric::Unit,
BraKetSymmetry::nonsymm, SPBasis::spinorbital);

set_default_context(bose_einstein_ctx, Statistics::BoseEinstein);

::benchmark::Initialize(&argc, argv);
if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
Expand Down
48 changes: 48 additions & 0 deletions benchmarks/simplify.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <benchmark/benchmark.h>

#include <SeQuant/core/expr.hpp>
#include <SeQuant/core/expr_algorithm.hpp>
#include <SeQuant/core/parse.hpp>

using namespace sequant;

static constexpr std::size_t nInputs = 2;

static ExprPtr get_expression(std::size_t i) {
switch (i) {
case 1:
return parse_expr(
L"1/2 A{i1,i2;a1,a2}:A g{i3,i4;a3,a4}:A t{a1,a3;i3,i4}:A "
L"t{a2,a4;i1,i2}:A"
L"- 1/2 A{i2,i1;a1,a2}:A g{i3,i4;a4,a3}:A t{a2,a3;i2,i1}:A "
L"t{a4,a1;i3,i4}:A ");
case 2:
return parse_expr(
L"A{p4;p1;}:A 1/3 g{p1,p2;p3,p4}:A t{p3;p2} "
L"+ A{p1;p4;}:A 1/3 g{p4,p2;p3,p1}:A t{p3;p2} "
L"+ A{p3;p1;}:A 1/3 g{p2,p1;p3,p4}:A t{p4;p2} ");
}

throw "Invalid index";
}

template <bool rapid_only>
static void simplify(benchmark::State &state) {
ExprPtr input = get_expression(state.range(0));

for (auto _ : state) {
ExprPtr expression = input->clone();
if constexpr (rapid_only) {
rapid_simplify(expression);
} else {
simplify(expression);
}

// Prevent simplification from being optimized away by the compiler
benchmark::DoNotOptimize(expression);
}
}

BENCHMARK(simplify<false>)->Name("simplify")->DenseRange(1, nInputs);

BENCHMARK(simplify<true>)->Name("rapid_simplify")->DenseRange(1, nInputs);
50 changes: 50 additions & 0 deletions benchmarks/spintrace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <benchmark/benchmark.h>

#include <SeQuant/core/expr.hpp>
#include <SeQuant/core/expr_algorithm.hpp>
#include <SeQuant/core/parse.hpp>
#include <SeQuant/domain/mbpt/spin.hpp>

using namespace sequant;

static constexpr std::size_t nInputs = 2;

static ExprPtr get_expression(std::size_t i) {
switch (i) {
case 1:
return parse_expr(L"2 t{i1;a1<i1>} F{a1<i1>;i1}");
case 2:
return parse_expr(
L"f{i1;a1} t{a1;i1} + 1/2 g{i1,i2;a1,a2}:A t{a1;i1} t{a2;i2} "
L"+ 1/4 g{i1,i2;a1,a2}:A t{a1,a2;i1,i2}:A");
}

throw "Invalid index";
}

template <bool closed_shell>
static void spintrace(benchmark::State &state, bool assume_spinfree) {
ExprPtr input = get_expression(state.range(0));

for (auto _ : state) {
ExprPtr result = [&]() {
if constexpr (closed_shell) {
return closed_shell_spintrace(input->clone());
} else {
return spintrace(input->clone(), {}, assume_spinfree);
}
}();

// Prevent spintracing from being optimized away by the compiler
benchmark::DoNotOptimize(result);
}
}

BENCHMARK_CAPTURE(spintrace<false>, spintrace_remove_spin, true)
->DenseRange(1, nInputs);

BENCHMARK_CAPTURE(spintrace<false>, spintrace_keep_spin, false)
->DenseRange(1, nInputs);

BENCHMARK_CAPTURE(spintrace<true>, closed_shell_spintrace, true)
->DenseRange(1, nInputs);
6 changes: 4 additions & 2 deletions benchmarks/wick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ static void wick(benchmark::State &state, bool full_conractions_only,

state.counters["produced"] = n_useful;
state.counters["attempted"] = n_attempted;
state.counters["percentage"] = static_cast<int>(
100 * static_cast<float>(n_useful) / static_cast<float>(n_attempted));
state.counters["percentage"] =
n_attempted > 0 ? static_cast<int>(100 * static_cast<float>(n_useful) /
static_cast<float>(n_attempted))
: 0;
}

BENCHMARK_CAPTURE(wick<Statistics::FermiDirac>, full_only_with_topology, true,
Expand Down

0 comments on commit 97e0755

Please sign in to comment.