diff --git a/src/composition/include/fourdst/composition/composition.h b/src/composition/include/fourdst/composition/composition.h index 5e42f66..1968c2f 100644 --- a/src/composition/include/fourdst/composition/composition.h +++ b/src/composition/include/fourdst/composition/composition.h @@ -112,6 +112,7 @@ namespace fourdst::composition { std::optional> sortedSpecies; ///< Cached vector of sorted species (by mass). std::optional> sortedSymbols; ///< Cached vector of sorted species (by mass). std::optional Ye; ///< Cached electron abundance. + std::optional 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 { diff --git a/src/composition/include/fourdst/composition/composition_abstract.h b/src/composition/include/fourdst/composition/composition_abstract.h index 883f499..999561a 100644 --- a/src/composition/include/fourdst/composition/composition_abstract.h +++ b/src/composition/include/fourdst/composition/composition_abstract.h @@ -179,6 +179,8 @@ namespace fourdst::composition { [[nodiscard]] virtual std::map::iterator end() = 0; [[nodiscard]] virtual std::map::const_iterator begin() const = 0; [[nodiscard]] virtual std::map::const_iterator end() const = 0; + + [[nodiscard]] virtual std::size_t hash() const = 0; }; // ReSharper disable once CppClassCanBeFinal diff --git a/src/composition/include/fourdst/composition/decorators/composition_decorator_abstract.h b/src/composition/include/fourdst/composition/decorators/composition_decorator_abstract.h index c3575b7..4eca926 100644 --- a/src/composition/include/fourdst/composition/decorators/composition_decorator_abstract.h +++ b/src/composition/include/fourdst/composition/decorators/composition_decorator_abstract.h @@ -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::iterator begin() override { return m_base_composition->begin(); }; [[nodiscard]] std::map::iterator end() override { return m_base_composition->end(); }; diff --git a/src/composition/lib/composition.cpp b/src/composition/lib/composition.cpp index 6b8f570..247db82 100644 --- a/src/composition/lib/composition.cpp +++ b/src/composition/lib/composition.cpp @@ -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(*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 { diff --git a/tests/composition/compositionTest.cpp b/tests/composition/compositionTest.cpp index 791baf6..c58b5e8 100644 --- a/tests/composition/compositionTest.cpp +++ b/tests/composition/compositionTest.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #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 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(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(second_hash_clock_end - second_hash_clock_start).count(); + + EXPECT_LT(second_hash_duration, first_hash_duration); +} \ No newline at end of file