From 568e5cb6c11644500cc2d4954b6dd80051bc8ac5 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Mon, 2 Feb 2026 14:15:00 +0100 Subject: [PATCH 01/16] Add missing [[maybe_unused]] --- SeQuant/domain/mbpt/op.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SeQuant/domain/mbpt/op.hpp b/SeQuant/domain/mbpt/op.hpp index ed79d8eef8..dbea3ff144 100644 --- a/SeQuant/domain/mbpt/op.hpp +++ b/SeQuant/domain/mbpt/op.hpp @@ -109,7 +109,7 @@ struct OpParams { if (!batch_ordinals.empty()) { SEQUANT_ASSERT(ranges::is_sorted(batch_ordinals) && "OpParams: batch_ordinals must be sorted"); - auto duplicate = ranges::adjacent_find(batch_ordinals); + [[maybe_unused]] auto duplicate = ranges::adjacent_find(batch_ordinals); SEQUANT_ASSERT(duplicate == batch_ordinals.end() && "OpParams: batch_ordinals must contain unique values"); } From 39a30fdbf5d2080b64daf2c26193bfcf936a2355 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Mon, 2 Feb 2026 14:54:42 +0100 Subject: [PATCH 02/16] Introduce Slot enum --- SeQuant/core/attr.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SeQuant/core/attr.hpp b/SeQuant/core/attr.hpp index dea1c6f88d..5f7b6956d9 100644 --- a/SeQuant/core/attr.hpp +++ b/SeQuant/core/attr.hpp @@ -54,6 +54,12 @@ enum class BraKetPos { Ket, }; +enum class Slot { + Bra, + Ket, + Aux, +}; + enum class Statistics { FermiDirac, BoseEinstein, From 2e403ada1863d25cc50bc7eb8eb81634ad1e3cc8 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Mon, 2 Feb 2026 14:55:04 +0100 Subject: [PATCH 03/16] Introduce SlottedIndex --- CMakeLists.txt | 1 + SeQuant/core/slotted_index.hpp | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 SeQuant/core/slotted_index.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c6a066da13..f0907924d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,6 +330,7 @@ set(SeQuant_symb_src SeQuant/core/runtime.hpp SeQuant/core/space.cpp SeQuant/core/space.hpp + SeQuant/core/slotted_index.hpp SeQuant/core/tag.hpp SeQuant/core/tensor_canonicalizer.cpp SeQuant/core/tensor_canonicalizer.hpp diff --git a/SeQuant/core/slotted_index.hpp b/SeQuant/core/slotted_index.hpp new file mode 100644 index 0000000000..e05b5519a2 --- /dev/null +++ b/SeQuant/core/slotted_index.hpp @@ -0,0 +1,42 @@ +#ifndef SEQUANT_SLOTTED_INDEX_H +#define SEQUANT_SLOTTED_INDEX_H + +#include +#include + +namespace sequant { + +/// Combination of an Index along with information about the Slot it occupies +/// +/// @note Usage of this class only makes sense, if the index in question does +/// not appear in multiple slots +/// +/// @sa Index +/// @sa Slot +class SlottedIndex { + public: + SlottedIndex(Index idx, Slot slot) + : idx_(std::move(idx)), slot_(std::move(slot)) {} + + Index &index() { return idx_; } + + const Index &index() const { return idx_; } + + Slot slot() const { return slot_; } + + friend bool operator==(const SlottedIndex &lhs, const SlottedIndex &rhs) { + return lhs.index() == rhs.index() && lhs.slot() == rhs.slot(); + } + + friend bool operator!=(const SlottedIndex &lhs, const SlottedIndex &rhs) { + return !(lhs == rhs); + } + + private: + Index idx_; + Slot slot_; +}; + +} // namespace sequant + +#endif From fa70e82aa409e2fe54e3b90af043f634951f2da4 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Mon, 2 Feb 2026 15:11:53 +0100 Subject: [PATCH 04/16] Add constness meta helpers --- SeQuant/core/meta.hpp | 81 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/SeQuant/core/meta.hpp b/SeQuant/core/meta.hpp index 84a1f36e78..8632f45c85 100644 --- a/SeQuant/core/meta.hpp +++ b/SeQuant/core/meta.hpp @@ -7,9 +7,10 @@ #include #include +#include + #include #include -#include namespace sequant { @@ -493,6 +494,84 @@ struct std_array_size> template constexpr inline std::size_t std_array_size_v = std_array_size::value; +/// make_immutable_t +/// Contrary to std::add_const_t, this works as one would expect on reference +/// types +template +using make_immutable_t = std::conditional_t< + std::is_lvalue_reference_v, + std::add_lvalue_reference_t>>, + std::conditional_t, + std::add_rvalue_reference_t< + std::add_const_t>>, + std::add_const_t>>; +static_assert(std::is_const_v>); +static_assert(std::is_const_v>); +static_assert(std::is_lvalue_reference_v>); +static_assert(std::is_lvalue_reference_v>); +static_assert( + std::is_const_v>>); +static_assert( + std::is_const_v>>); +static_assert(std::is_rvalue_reference_v>); +static_assert(std::is_rvalue_reference_v>); +static_assert( + std::is_const_v>>); +static_assert( + std::is_const_v>>); + +/// make_mutable_t +/// Contrary to std::remove_const_t, this works as one would expect on reference +/// types +template +using make_mutable_t = std::conditional_t< + std::is_lvalue_reference_v, + std::add_lvalue_reference_t< + std::remove_const_t>>, + std::conditional_t, + std::add_rvalue_reference_t< + std::remove_const_t>>, + std::remove_const_t>>; +static_assert(!std::is_const_v>); +static_assert(!std::is_const_v>); +static_assert(std::is_lvalue_reference_v>); +static_assert(std::is_lvalue_reference_v>); +static_assert( + !std::is_const_v>>); +static_assert( + !std::is_const_v>>); +static_assert(std::is_rvalue_reference_v>); +static_assert(std::is_rvalue_reference_v>); +static_assert( + !std::is_const_v>>); +static_assert( + !std::is_const_v>>); + +/// is_immutable_v +/// Contrary to std::is_const_v, this works as one would expect on reference +/// types +template +constexpr bool is_immutable_v = std::is_const_v>; +static_assert(is_immutable_v); +static_assert(!is_immutable_v); +static_assert(is_immutable_v); +static_assert(!is_immutable_v); +static_assert(is_immutable_v); +static_assert(!is_immutable_v); + +/// mimic_constness_t +/// Makes To const, if From is const, else makes To non-const +template +using mimic_constness_t = + std::conditional_t, make_immutable_t, + make_mutable_t>; +static_assert( + std::is_const_v< + std::remove_reference_t>>); +static_assert( + !std::is_const_v< + std::remove_reference_t>>); + } // namespace meta } // namespace sequant From 6b7e628106097c6da6a344d21e5c89749654481b Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Mon, 2 Feb 2026 15:33:21 +0100 Subject: [PATCH 05/16] Make ResultExpr::external_index_pairings support SlottedIndex --- SeQuant/core/expressions/result_expr.hpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/SeQuant/core/expressions/result_expr.hpp b/SeQuant/core/expressions/result_expr.hpp index bc26db069d..09c142296b 100644 --- a/SeQuant/core/expressions/result_expr.hpp +++ b/SeQuant/core/expressions/result_expr.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -102,15 +103,23 @@ class ResultExpr { // based on the particle they belong to and that bra and // ket indices are assigned to the same set of particles. for (std::size_t i = 0; i < m_braIndices.size(); ++i) { - if constexpr (std::is_constructible_v>) { + if constexpr (std::is_constructible_v< + Group, std::initializer_list>) { + groups.emplace_back(std::initializer_list{ + {m_braIndices.at(i), Slot::Bra}, {m_ketIndices.at(i), Slot::Ket}}); + } else if constexpr (std::is_constructible_v< + Group, std::initializer_list>) { groups.emplace_back(std::initializer_list{m_braIndices.at(i), m_ketIndices.at(i)}); + } else if constexpr (std::is_constructible_v) { + groups.emplace_back(SlottedIndex{m_braIndices.at(i), Slot::Bra}, + SlottedIndex{m_ketIndices.at(i), Slot::Ket}); } else { static_assert( std::is_constructible_v, - "Group is expected to be constructible from two indices or from an " - "initializer_list of indices"); + "Group is expected to be constructible from two (slotted) indices " + "or from an initializer_list of (slotted) indices"); groups.emplace_back(m_braIndices.at(i), m_ketIndices.at(i)); } } From ca4303962bc11fd42958880fb1df1ab2139e9bcb Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Mon, 2 Feb 2026 15:34:05 +0100 Subject: [PATCH 06/16] Make external index handling more robust We now explicitly track the slot (kind) of a given external index instead of relying on ordering conventions to encode this information. --- SeQuant/core/utility/indices.hpp | 140 +++++++++++++------- SeQuant/domain/mbpt/biorthogonalization.cpp | 6 +- SeQuant/domain/mbpt/biorthogonalization.hpp | 8 +- SeQuant/domain/mbpt/spin.cpp | 115 ++++++++-------- SeQuant/domain/mbpt/spin.hpp | 15 ++- tests/integration/srcc.cpp | 8 +- tests/unit/test_spin.cpp | 121 +++++++++++------ tests/unit/test_utilities.cpp | 55 +++++--- tests/unit/test_wick.cpp | 11 +- 9 files changed, 304 insertions(+), 175 deletions(-) diff --git a/SeQuant/core/utility/indices.hpp b/SeQuant/core/utility/indices.hpp index c2b008ab07..40581463f6 100644 --- a/SeQuant/core/utility/indices.hpp +++ b/SeQuant/core/utility/indices.hpp @@ -1,20 +1,25 @@ #ifndef SEQUANT_CORE_UTILITY_INDICES_HPP #define SEQUANT_CORE_UTILITY_INDICES_HPP +#include #include #include #include +#include #include #include +#include #include #include #include +#include #include #include #include #include +#include #include #include @@ -434,8 +439,11 @@ std::string csv_labels(Rng&& idxs) { /// /// @see get_bra_idx /// @see get_ket_idx -template >> -Container external_indices(const Expr& expr) { +template