diff --git a/SeQuant/core/index.cpp b/SeQuant/core/index.cpp index 0c4da854b5..24efc88612 100644 --- a/SeQuant/core/index.cpp +++ b/SeQuant/core/index.cpp @@ -71,4 +71,9 @@ std::string Index::to_string() const { return sequant::to_string(this->label()); } +std::shared_ptr +Index::obtain_default_index_registry() { + return get_default_context().index_space_registry(); +} + } // namespace sequant diff --git a/SeQuant/core/index.hpp b/SeQuant/core/index.hpp index fed1ffaf20..92b9869e59 100644 --- a/SeQuant/core/index.hpp +++ b/SeQuant/core/index.hpp @@ -6,8 +6,9 @@ #define SEQUANT_INDEX_H #include -#include #include +#include +#include #include #include #include @@ -15,7 +16,6 @@ #include #include -#include #include #include #include @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -328,12 +329,11 @@ class Index : public Taggable { /// the cost of slightly increased danger template Index(String &&label) - : Index( - get_default_context().index_space_registry() - ? get_default_context().index_space_registry()->retrieve(label) - : IndexSpace{base_label(label), IndexSpace::Type::reserved, - IndexSpace::QuantumNumbers::reserved}, - to_ordinal(label), {}) { + : Index(obtain_default_index_registry() + ? obtain_default_index_registry()->retrieve(label) + : IndexSpace{base_label(label), IndexSpace::Type::reserved, + IndexSpace::QuantumNumbers::reserved}, + to_ordinal(label), {}) { check_nonreserved(); if constexpr (std::is_same_v) { label_ = std::move(label); @@ -1043,6 +1043,8 @@ class Index : public Taggable { return i1_Q < i2_Q ? SO::less : SO::greater; } + static std::shared_ptr obtain_default_index_registry(); + }; // class Index inline const IndexSpace::Attr Index::default_space_attr{ diff --git a/SeQuant/core/options.cpp b/SeQuant/core/options.cpp index acd7fbb2fd..597ec35a9c 100644 --- a/SeQuant/core/options.cpp +++ b/SeQuant/core/options.cpp @@ -45,9 +45,9 @@ CanonicalizeOptions CanonicalizeOptions::copy_and_set( } CanonicalizeOptions CanonicalizeOptions::copy_and_set( - std::optional> arg) const { + std::optional> arg) const { auto result = *this; - result.named_indices = arg; + result.named_indices = std::move(arg); return result; } diff --git a/SeQuant/core/options.hpp b/SeQuant/core/options.hpp index 11b4f0f1b7..435394dd80 100644 --- a/SeQuant/core/options.hpp +++ b/SeQuant/core/options.hpp @@ -5,12 +5,14 @@ #ifndef SEQUANT_CORE_OPTIONS_HPP #define SEQUANT_CORE_OPTIONS_HPP +#include + +#include #include +#include namespace sequant { -class Index; - /// canonicalization methods enum class CanonicalizationMethod { /// Enables use of expression topology in the canonicalization, may be @@ -47,7 +49,7 @@ struct CanonicalizeOptions { /// specifies named indices; by default all indices that appear only once are /// deduced to be named, but this may be misleading if e.g. single /// summed-over dummy index appears in an expression - std::optional> named_indices = std::nullopt; + std::optional> named_indices = std::nullopt; /// whether to ignore the labels of named indices. Setting /// to false will cause named indices to be treated as equivalent slots, which /// the result to be independent of their labels. This does not make sense in @@ -57,8 +59,7 @@ struct CanonicalizeOptions { static CanonicalizeOptions default_options(); CanonicalizeOptions copy_and_set(CanonicalizationMethod) const; - CanonicalizeOptions copy_and_set( - std::optional>) const; + CanonicalizeOptions copy_and_set(std::optional>) const; CanonicalizeOptions copy_and_set(IgnoreNamedIndexLabel) const; friend constexpr bool operator==(const CanonicalizeOptions& a, diff --git a/tests/unit/test_spin.cpp b/tests/unit/test_spin.cpp index b3d1cb9983..4f720c78f6 100644 --- a/tests/unit/test_spin.cpp +++ b/tests/unit/test_spin.cpp @@ -632,6 +632,20 @@ SECTION("partial spintracing + S_maps = full spintracing") { //(canonicalized: -2 t{a_1,a_2;i_2,i_1}:N-C-S + 4 t{a_1,a_2;i_1,i_2}:N-C-S) } +SECTION("external indices have to remain consistent") { + // Internally, closed_shell_spintrace performs canonicalization which can end + // up renaming external indices (due to the presence of the symmetrizer). This + // will cause an inconsistency with the explicitly provided external index + // names. + ExprPtr input = parse_expr( + L"A{p_8,p_9;a_8,a_9}:A-C-S * y{p_3,p_4;p_8,p_9}:A-C-S * " + L"g{i_3,a_8;p_3,p_4}:A-C-S * t{a_9;i_3}:A-C-S"); + ExprPtr result = + closed_shell_spintrace(input, {{L"a_8", L"p_8"}, {L"a_9", L"p_9"}}); + + // REQUIRE_THAT(result, EquivalentTo(L"TODO")); +} + SECTION("Symmetrize expression") { { // g * t1 + g * t1