perf(hash): Hash caching

added ability for composition to stash their own hash values
This commit is contained in:
2025-12-07 07:47:32 -05:00
parent 9541234a5f
commit 75ba6c8456
5 changed files with 51 additions and 1 deletions

View File

@@ -112,6 +112,7 @@ namespace fourdst::composition {
std::optional<std::vector<atomic::Species>> sortedSpecies; ///< Cached vector of sorted species (by mass).
std::optional<std::vector<std::string>> sortedSymbols; ///< Cached vector of sorted species (by mass).
std::optional<double> Ye; ///< Cached electron abundance.
std::optional<std::size_t> hash;
/**
* @brief Clears all cached values.
@@ -124,6 +125,7 @@ namespace fourdst::composition {
sortedSymbols = std::nullopt;
sortedSpecies = std::nullopt;
Ye = std::nullopt;
hash = std::nullopt;
}
/**
@@ -133,7 +135,7 @@ namespace fourdst::composition {
[[nodiscard]] bool is_clear() const {
return !canonicalComp.has_value() && !massFractions.has_value() &&
!numberFractions.has_value() && !molarAbundances.has_value() && !sortedSymbols.has_value() &&
!Ye.has_value() && !sortedSpecies.has_value();
!Ye.has_value() && !sortedSpecies.has_value() && !hash.has_value();
}
};
private:
@@ -832,6 +834,8 @@ namespace fourdst::composition {
return m_molarAbundances.cend();
}
[[nodiscard]] std::size_t hash() const override;
};
inline bool operator==(const Composition& a, const Composition& b) noexcept {

View File

@@ -179,6 +179,8 @@ namespace fourdst::composition {
[[nodiscard]] virtual std::map<atomic::Species, double>::iterator end() = 0;
[[nodiscard]] virtual std::map<atomic::Species, double>::const_iterator begin() const = 0;
[[nodiscard]] virtual std::map<atomic::Species, double>::const_iterator end() const = 0;
[[nodiscard]] virtual std::size_t hash() const = 0;
};
// ReSharper disable once CppClassCanBeFinal

View File

@@ -36,6 +36,7 @@ namespace fourdst::composition {
[[nodiscard]] size_t getSpeciesIndex(const std::string& symbol) const override { return m_base_composition->getSpeciesIndex(symbol); };
[[nodiscard]] size_t getSpeciesIndex(const atomic::Species& species) const override { return m_base_composition->getSpeciesIndex(species); };
[[nodiscard]] atomic::Species getSpeciesAtIndex(const size_t index) const override { return m_base_composition->getSpeciesAtIndex(index); }
[[nodiscard]] size_t hash() const override { return m_base_composition->hash(); };
[[nodiscard]] std::map<atomic::Species, double>::iterator begin() override { return m_base_composition->begin(); };
[[nodiscard]] std::map<atomic::Species, double>::iterator end() override { return m_base_composition->end(); };

View File

@@ -34,6 +34,7 @@
#include "fourdst/atomic/atomicSpecies.h"
#include "fourdst/atomic/species.h"
#include "fourdst/composition/composition.h"
#include "fourdst/composition/utils/composition_hash.h"
#include "fourdst/composition/utils.h"
#include "fourdst/composition/exceptions/exceptions_composition.h"
@@ -551,6 +552,15 @@ namespace fourdst::composition {
return std::make_unique<Composition>(*this);
}
std::size_t Composition::hash() const {
if (m_cache.hash.has_value()) {
return m_cache.hash.value();
}
std::size_t hash = utils::CompositionHash::hash_exact(*this);
m_cache.hash = hash;
return hash;
}
bool Composition::contains(
const atomic::Species &species
) const noexcept {

View File

@@ -2,6 +2,7 @@
#include <stdexcept>
#include <string>
#include <algorithm>
#include <chrono>
#include "fourdst/atomic/atomicSpecies.h"
#include "fourdst/atomic/species.h"
@@ -439,3 +440,35 @@ TEST_F(compositionTest, canonicalizeNaNIfAllowed) {
ASSERT_EQ(fourdst::composition::utils::CompositionHash::hash_exact(a),
fourdst::composition::utils::CompositionHash::hash_exact(b));
}
TEST_F(compositionTest, hash) {
fourdst::composition::Composition a, b;
a.registerSymbol("H-1"); b.registerSymbol("H-1");
a.setMolarAbundance("H-1", 0.6); b.setMolarAbundance("H-1", 0.6);
EXPECT_NO_THROW((void)a.hash());
EXPECT_EQ(a.hash(), b.hash());
}
TEST_F(compositionTest, hashCaching) {
using namespace fourdst::atomic;
std::unordered_map<Species, double> abundances ={
{H_1, 0.702},
{He_4, 0.06},
{C_12, 0.001},
{N_14, 0.0005},
{O_16, 0.22},
};
fourdst::composition::Composition a(abundances);
const auto first_hash_clock_start = std::chrono::high_resolution_clock::now();
(void)a.hash();
const auto first_hash_clock_end = std::chrono::high_resolution_clock::now();
const auto first_hash_duration = std::chrono::duration_cast<std::chrono::nanoseconds>(first_hash_clock_end - first_hash_clock_start).count();
const auto second_hash_clock_start = std::chrono::high_resolution_clock::now();
(void)a.hash();
const auto second_hash_clock_end = std::chrono::high_resolution_clock::now();
const auto second_hash_duration = std::chrono::duration_cast<std::chrono::nanoseconds>(second_hash_clock_end - second_hash_clock_start).count();
EXPECT_LT(second_hash_duration, first_hash_duration);
}