Skip to content

Conversation

@ajay-mk
Copy link
Member

@ajay-mk ajay-mk commented Dec 24, 2025

Custom Operator Registry Support

This PR refactors Operator logic from depending on a predefined OpType enum to a runtime OpRegistry, enabling users to define custom operators beyond the predefined set.

Major Changes

  • OpRegistry: a registry for operator labels and their classifications
  • mbpt::Context now holds an OpRegistry along with the CSV setting.
  • There are two predefined registries available (minimal and legacy).
  • Some labels are reserved for internal use (antisymmetrizer, symmetrizer, kroneker, overlap), and cannot be registered.
  • OpType enum is removed, all related logic is gone:
    • OpMaker constructors now use strings.
    • OpConnections now uses strings to specify operator pairs. For example: {{L"f", L"A"}, {L"g", L"A"}, ...}
  • Built-in operators (both tensor and Operator level) check the registry if operators are registered.
  • Perturbation-related operators now support higher-order perturbations (up to 9).
  • mbpt::Context manipulations are thread-safe, and can be toggled by SEQUANT_CONTEXT_MANIPULATION_THREADSAFE option; follows the same pattern as core::Context.

Example Usage

    using namespace sequant;
    using namespace sequant::mbpt;
   
    auto registry = std::make_shared<OpRegistry>();

    registry->add(L"f", OpClass::gen)
        .add(L"g", OpClass::gen)
        .add(L"t", OpClass::ex)
        .add(L"x", OpClass::ex)
        .add(L"y", OpClass::ex);

    // set MBPT context
    auto ctx_resetter = set_scoped_default_mbpt_context(
        {.csv = CSV::No, .op_registry_ptr = registry});

    // use OpMaker to define a custom excitation operator of rank 2
    auto x = OpMaker<Statistics::FermiDirac>(L"x", 2)();

    // particle non-conserving excitation operator with custom IndexSpaces
    const auto& cre_space = get_particle_space(Spin::any);
    const auto& ann_space = get_hole_space(Spin::any);

    auto y = OpMaker<Statistics::FermiDirac>(L"y", ncre(2), nann(1),
                                             cre(cre_space), ann(ann_space))();

Additional Changes

  • The antisymmetrizer and symmetrizer labels have been updated to  and Ŝ, respectively. As a result, several tests and examples were updated. Most hardcoded strings were replaced with calls to the reserved label methods; however, some reference outputs and expressions are still constructed from plain strings.
  • In the TNC tests, the reference GraphViz output needed to be updated with the new label and the newly assigned color for the tensor. The rest of the graph remains unchanged.
  • The spin-tracing examples in tests/integration were not using mbpt::cardinal_tensor_labels() for expression canonicalization. After the label change, symmetrizer and antisymmetrizer tensors were moved to the end during canonicalization. Since the spin-tracing logic assumes all symmetrizer tensors share the same external indices, they must appear first. This was fixed by canonicalizing with mbpt::cardinal_tensor_labels(), which places symmetrizer tensors first and ensures consistent indexing.
  • The trace_product spin-tracing logic assumed that the symmetrizer tensor always appears first; this has been generalized. cc: @ABesharat
  • Some evaluation logic also requires canonical ordering. Accordingly, the eval_{ta,btas} cases now use mbpt::cardinal_tensor_labels() with TNC.
  • The external interface was updated to use reserved labels instead of hardcoded ones, and the labels in the example inputs were updated accordingly.

All connectivity info is now encoded using plain strings
All connectivity info is now encoded using plain strings
…ation order

Constructors now take strings as Operator identifiers
…f perturbation order.

Perturbation order does not make any difference on how the operator acts, so it is only for bookkeeping here.
All methods except A and S will check registry make sure the Operator label is registered.
ajay-mk added 13 commits January 6, 2026 13:36
Both hat and bar together looks complicated. Since we will eventually switch to an antisymmetrizer operator, it makes sense to not have the bar.
Ideally, this logic should be general: we should detect the presence of the Unicode character and avoid adding hats. Unfortunately this means introducing another dependency, so let's stick with this for now.
Boost.Locale has a way to support normalization, but still need ICU backend.
Some logic needs antisymmetrizer/symmetrizer to be in the front.
…trizer label

The graphs didn't change, just the label and the color assigned to the tensor
The indexing changed, but as the comment above says, all forms canonicalizes to the same form.
This lambda always assumed that symmetrizer is the first tensor, which may not be the case always. On the lines of #441.
The stcc and ostcc integration tests were failing with an assertion error in
external_indices(). The function requires that symmetrizer/antisymmetrizer
tensors be identical across all terms, but this does not happen
without setting cardinal_tensor_labels for the TNC to use.
Also setting the order ensures aesthetic printing.
@ajay-mk ajay-mk force-pushed the ajay/feature/runtime-op-support branch from 6e2e51d to 5ba9ddc Compare January 7, 2026 16:40
@evaleev evaleev requested a review from Copilot January 7, 2026 17:00
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 refactors the MBPT operator system from a predefined OpType enum to a runtime OpRegistry, enabling users to define custom operators beyond the predefined set. The implementation introduces a registry-based approach where operator labels map to operator classes (excitation, de-excitation, or general).

Key Changes:

  • Introduces OpRegistry for runtime operator registration with two predefined registries (minimal and legacy)
  • Removes OpType enum and replaces all usage with string-based operator labels
  • Adds support for perturbation orders 0-9 (previously limited to order 1)
  • Replaces hard-coded reserved labels (L"A", L"S") with functions returning L"Â", L"Ŝ"

Reviewed changes

Copilot reviewed 54 out of 54 changed files in this pull request and generated no comments.

Show a summary per file
File Description
SeQuant/core/reserved.hpp New file defining reserved operator labels (antisymmetrizer, symmetrizer, kronecker, overlap)
SeQuant/domain/mbpt/op_registry.hpp/cpp New registry class for mapping operator labels to OpClass
SeQuant/domain/mbpt/context.hpp/cpp Extended to hold OpRegistry with thread-safe manipulation
SeQuant/domain/mbpt/op.hpp/cpp/ipp Major refactoring: OpMaker/Operator now use strings; added perturbation order support
SeQuant/domain/mbpt/vac_av.hpp/cpp OpConnections changed from OpType to std::wstring
Test files Updated to use new string-based API and reserved label functions
Documentation Added operator registry documentation and examples
Input files (nevpt2, ccsd) Updated antisymmetrizer label from "A" to "Â"

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

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

Copilot reviewed 57 out of 57 changed files in this pull request and generated no new comments.


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

…ill append to it

- add default cardinal tensor labels: antisymm/symm reserved labels
- update set_cardinal_tensor_labels() to append user-provided labels to defaults
- add reset_cardinal_tensor_labels() to restore defaults
- add clear_all_cardinal_tensor_labels() to remove all labels including defaults
- add logic for duplicate label checking, only enabled if SEQUANT_ASSERT_ENABLED is true
…_tensor_labels()`

Since antisymm_label() and symm_label() are now default cardinal labels (see f4e2d75), they will be automatically prepended when calling TensorCanonicalizer::set_cardinal_tensor_labels()
…ithout setting `cardinal_tensor_labels()` for TNC.

See also f4e2d75
@ajay-mk ajay-mk force-pushed the ajay/feature/runtime-op-support branch from b4f63b8 to fea1717 Compare January 8, 2026 01:48
@ajay-mk ajay-mk force-pushed the ajay/feature/runtime-op-support branch from 5d0abbc to cb02281 Compare January 9, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants