Skip to content

evaluate expressions with non-aux-only hyperindices#495

Merged
bimalgaudel merged 7 commits intomasterfrom
evaleev/fix/eval-nonaux-hyperindex
Feb 18, 2026
Merged

evaluate expressions with non-aux-only hyperindices#495
bimalgaudel merged 7 commits intomasterfrom
evaleev/fix/eval-nonaux-hyperindex

Conversation

@evaleev
Copy link
Member

@evaleev evaleev commented Feb 16, 2026

Executive Summary

this relaxes the restriction in #462 that hyperindices can aux-only. This is needed, for example, to evaluate cluster-specific RDMs:

γ{a2;a1;i1,i2} = t{i1,i2;a1,a3} t⁺{a2,a3;i1,i2}

This also allows to relax bra-ket strictness imposed by default by TNv3.

Non-aux hyperindices

As of #462 evaluation of tensor networks with hyperindices is supported as long as the hyperindices are in aux slots. This is sufficient when the hyperindices are not external/named because summing over arbitrary combinations of primal/ket and dual/bra modes does not make sense; aux indices are the proper way to denote modes without vector-space structure (i.e., array-like). But as the cluster-specific RDM demonstrates it does makes sense to have named hyperindices that involve bra/ket slots. The key question is then what should these indices become? In the RDM example the hyperindices (i1,i2) appear in both bra and ket slots. It's clear that these indices should refer to an aux mode of the result: no meaningful primal-dual notion can be defined for these modes. One can imagine cases where it might make sense to designate the resulting modes as bra or ket, e.g.:

c{i1;i2} = a{i1;i2} b{i1,i2}

but there are yet many questions about such model (e.g. what should be pairing of the resulting modes). This PR postpones dealing with such cases. It's clear that more thinking is needed, and ultimately support for general tensor symmetries is the part of this issue.

Nonstrict bra-ket sanitization

Bra-ket separation exists to prevent the users from making accidental mistakes in dealing with expressions where primal/dual modes differ nontrivially (nonunit metric, complex fields, etc.). All TN implementations sanitize their input expressions accordingly. Nevertheless some (e.g., agents writing tests) will ignore this structure for pragmatic reasons. This PR adds the ability to turn off the bra-ket strictness in TNv3 (strictness is still on by default).

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR relaxes the restriction from #462 that hyperindices must be aux-only, enabling evaluation of expressions with cluster-specific reduced density matrices (RDMs) and allowing more flexible bra-ket contractions. The changes introduce a new StrictBraKetSymmetry context setting and convert compile-time assertion checks to runtime checks throughout the test suite.

Changes:

  • Added StrictBraKetSymmetry enum and context support to control whether bra/ket slots enforce strict vector space semantics
  • Refactored evaluation expression handling to work with all indices (bra, ket, aux) instead of just aux indices for hyperindices
  • Converted compile-time preprocessor assertion checks to runtime checks using new assert_behavior() function
  • Added comprehensive tests for evaluating expressions with non-covariant indices and multiple bra/ket hyperindices

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
SeQuant/core/attr.hpp Adds StrictBraKetSymmetry enum with Yes/No values
SeQuant/core/context.hpp Adds StrictBraKetSymmetry to Context class with getter/setter
SeQuant/core/context.cpp Implements StrictBraKetSymmetry support in Context
SeQuant/core/utility/macros.hpp Declares assert_enabled() and assert_behavior() functions
SeQuant/core/utility/macros.cpp Implements runtime assert behavior query functions
SeQuant/core/tensor_network/v3.hpp Removes strict bra-to-bra/ket-to-ket connection prohibition from Edge
SeQuant/core/tensor_network/v3.cpp Adds conditional strict bra-ket checks during graph creation with new include
SeQuant/core/eval/eval_expr.cpp Changes from aux_indices to all_indices, adds logic to route hyperindices to correct slots
SeQuant/core/io/serialization/serialization.hpp Uses explicit std::nullopt instead of {} for optional initialization
tests/unit/test_utilities.cpp Converts compile-time assertions to runtime checks
tests/unit/test_tensor_network.cpp Updates covariance tests to use runtime checks and new create_graph() call
tests/unit/test_tensor.cpp Converts compile-time assertions to runtime checks
tests/unit/test_mbpt.cpp Converts compile-time assertions to runtime checks
tests/unit/test_macros.cpp Converts compile-time assertions to runtime checks
tests/unit/test_index.cpp Converts compile-time assertions to runtime checks
tests/unit/test_eval_ta.cpp Adds new tests for non-covariant indices with StrictBraKetSymmetry::No

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@evaleev evaleev added the enhancement New feature or request label Feb 16, 2026
these happen
- only if not disabled in default context,
- only if SEQUANT_ASSERT_ENABLED, and
- in create_graph where we can ignore named indices
… (this is needed, for example, to evaluate cluster-specific RDMs)
@evaleev evaleev force-pushed the evaleev/fix/eval-nonaux-hyperindex branch from f5d39c5 to 35b0eac Compare February 16, 2026 15:56
…naux-hyperindex

# Conflicts:
#	SeQuant/core/tensor_network/v3.cpp
@evaleev evaleev force-pushed the evaleev/fix/eval-nonaux-hyperindex branch from 2f9ab4d to 458801c Compare February 17, 2026 03:14
Comment on lines +1211 to +1214
// strict bra-ket sanity checks
if constexpr (assert_enabled()) {
if (current_edge.vertex_count() > 2) {
[[maybe_unused]] std::size_t nbra = 0;
[[maybe_unused]] std::size_t nket = 0;
[[maybe_unused]] std::size_t naux = 0;
for (std::size_t i = 0; i < current_edge.vertex_count(); ++i) {
const Vertex &vertex = current_edge.vertex(i);
switch (vertex.getOrigin()) {
case Origin::Bra:
++nbra;
break;
case Origin::Ket:
++nket;
break;
case Origin::Aux:
++naux;
break;
case Origin::Proto:
SEQUANT_UNREACHABLE;
if (get_default_context().strict_braket_symmetry() ==
StrictBraKetSymmetry::Yes) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be guarded by an assertion. If the user has strict braket symmetry enabled, this should always be checked (and it should throw an exception on violation rather than assert). Otherwise, the user is presented with an option that they can't rely on, which seems odd.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first reaction is no, in applications where I know my expressions are correct (e.g. in a QC user code) I want to be able to disable pre/post-condition checks globally, by configuring with SEQUANT_ASSERT_BEHAVIOR=IGNORE. For SeQuant to be usable as a component in the end-user code we have to be able to control behavior of all of its contract checks.

Disabling strictness is for situations where a blunt "ignore nonsense math" sign is needed, such as in tests. I can see how the new option may be read as "checks always on", though. I think dox explaining what strict_braket_symmetry means would be sufficient ... ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe changing the name to include "assert" would already go towards making it clear what to expect from this? E.g. assert_strict_braket_symmetry

…ndexVec`.

- Set of `Index` with `FullLabelCompare` comparator seems to appear in many use cases.
- `Index::index_vector` is special because some containers like `boost::small_vector` cannot represent proto-indices as per the documentation on `Index::index_vector`. Then we must refer to the `Index::index_vector` type across the code base consistently using `IndexVec`.
@bimalgaudel bimalgaudel merged commit 2a191d1 into master Feb 18, 2026
16 checks passed
@bimalgaudel bimalgaudel deleted the evaleev/fix/eval-nonaux-hyperindex branch February 18, 2026 01:39
@evaleev evaleev added this to the 2.2 milestone Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments