Skip to content

Fold BraKetSymmetry::Conjugate bra<->ket orientations onto one eval cache slot (opt-in) - #591

Open
kshitij-05 wants to merge 5 commits into
masterfrom
kshitij/feature/braket-conjugate-fold
Open

Fold BraKetSymmetry::Conjugate bra<->ket orientations onto one eval cache slot (opt-in)#591
kshitij-05 wants to merge 5 commits into
masterfrom
kshitij/feature/braket-conjugate-fold

Conversation

@kshitij-05

Copy link
Copy Markdown
Member

A Hermitian (BraKetSymmetry::Conjugate) tensor and its bra↔ket-swapped partner are the same data up to complex conjugation, but the eval layer treated the two orientations as distinct leaves/subtrees, evaluating and caching both. This adds an opt-in exploit_conjugate channel that folds the orientations onto one canonical form:

  • TensorNetworkV3::canonicalize_slots gains an exploit_conjugate argument and reports the conjugation byproduct of the orientation fold;
  • EvalExpr records the byproduct in a new canon_conj() bit, kept out of hash_value() so both orientations share a cache slot;
  • binarize serves the swapped orientation via the existing EvalOp::Adjoint machinery (pure elementwise conjugation on retrieval — both TA backends, flat and ToT, already implement Result::adjoint);
  • TensorBlockCanonicalizer factors its Symm-branch orientation choice into orient_braket_by_color() and adds fold_conjugate_braket() for the Conjugate case (flat and ToT leaf paths);
  • a drive-by fix: the ToT leaf ctor now passes the declared default_idxptr_slottype_lesscompare{} named-index comparator instead of {} (which silently selected the space-only fallback and mis-ordered proto-indexed canon_indices).

Default off; no behavior change without the opt-in. Covered by [exploit_conjugate] unit tests for both flat and ToT leaves; the full unit suite passes (311243 assertions in 88 cases).

Opt-in (exploit_conjugate): canonicalize_slots reports whether folding the
two bra<->ket orientations of a Hermitian (BraKetSymmetry::Conjugate)
tensor onto one canonical orientation introduced a conjugation, so
eval-node CSE can share one cache slot between the orientations and
serve the swapped one via an adjoint. Default off; no behavior change
without the opt-in.
Layer the exploit_conjugate byproduct from canonicalize_slots onto the
eval tree, so the two bra<->ket orientations of a Conjugate leaf share one
cached value.

EvalExpr(Tensor, exploit_conjugate) threads the flag into the ToT leaf's
canonicalize_slots call and records the conjugation in a new canon_conj()
bit. That bit is kept OUT of hash_value() (only canon_phase is folded
there), so a Conjugate leaf and its bra<->ket swap hash identically and
share a cache slot. binarize(Tensor, opts) then turns the conjugated
orientation into an EvalOp::Adjoint over the bare canonical leaf, carrying
the SAME canonical index order -- so the existing adjoint evaluator's
result(post) = operand(pre).conj() degenerates to a pure elementwise
conjugation (post == pre, no transpose) on retrieval. This reuses the
tested '+'-adjoint machinery rather than adding a new eval op.

Default off leaves every existing path byte-identical: the new binarize
branch is skipped and canonicalize_slots is called with
exploit_conjugate=false, exactly as before.

Test [exploit_conjugate] (replaces the throwaway probe): a proto-indexed
Conjugate leaf and its adjoint fold to one hash with exactly one carrying
the byproduct; binarize wraps the swapped orientation in EvalOp::Adjoint
over the shared bare leaf with matching canonical indices; off by default
keeps the two distinct.
Extend the exploit_conjugate conjugation channel to the flat
(protoindex-free) block-canonicalization leaf path, so a flat
BraKetSymmetry::Conjugate tensor and its bra<->ket-swapped partner fold
onto one cached value the same way the ToT/canonicalize_slots path
already does. This is the path flat complex-field Conjugate leaves take.

TensorBlockCanonicalizer::apply() already folds the two bra<->ket
orientations of a Symm tensor (a free relabeling). Factor that
color-based swap into a shared orient_braket_by_color() (apply()'s Symm
branch reuses it, byte-for-byte unchanged) and add
fold_conjugate_braket(), which applies the same swap to a Conjugate
tensor and reports whether it swapped -- for Conjugate the swap carries a
conjugation (C{ket;bra} = conj(C{bra;ket})), so it is a byproduct the
caller must consume, not a free relabeling.

The EvalExpr flat-leaf ctor branch calls it under exploit_conjugate and
records the result in canon_conj_ (kept out of the hash, so the two
orientations share a cache slot); binarize(Tensor)'s existing
EvalOp::Adjoint wrap then serves the swapped orientation as a pure
elementwise conjugation on retrieval, exactly as for the ToT path.

Default off leaves every existing path byte-identical. Limitation:
equal-color bra/ket bundles (identical spaces) are not folded on the flat
path -- that needs a full index-pattern comparison, which only the
bliss/ToT path does; the flat color rule matches apply()'s Symm fold.

Test [exploit_conjugate] gains a flat-leaf section (C{a_1;i_1}:N-C-S)
mirroring the ToT checks: off -> distinct, on -> fold + exactly one
conjugated + Adjoint over the shared bare leaf.
EvalExpr(Tensor)'s canonicalize_slots call passed {} for
named_index_compare in order to reach the exploit_conjugate argument. An
empty comparator is NOT the declared default: canonicalize_slots then
falls back to an internal space()-only lambda, whereas the declared
default (default_idxptr_slottype_lesscompare) orders named indices by
proto-index count first. That proto-count-first order is what lays a
proto-indexed (ToT) coefficient's canon_indices out with occupieds
first -- a layout downstream coefficient-shape detectors rely on. So {}
silently mis-ordered them and broke such consumers.

Pass default_idxptr_slottype_lesscompare{} explicitly, restoring the
comparator every ToT leaf had before the exploit_conjugate arg was
threaded. Flat leaves (block-canon else-branch) are unaffected.
The flat-leaf exploit_conjugate channel folds the two bra<->ket
orientations of a Conjugate tensor onto one cache slot, serving the
swapped orientation via EvalOp::Adjoint. The ToT (proto-indexed) leaf
path lacked the fold: TNV3's canonicalize_slots does not exploit
conjugate braket symmetry, so the orientations landed in separate slots.
Apply TensorBlockCanonicalizer::fold_conjugate_braket to the ToT leaf
before the network canonicalization (the color rule is label-independent
and proto-safe) and compose the byproduct into canon_conj_; the ToT TA
Result backend already implements adjoint() (conj recurses into nested
tiles). Off by default (exploit_conjugate opt-in unchanged).

Test tot_conjugate_braket_fold: hashes fold, canon_conj marks the
swapped orientation, no behavior change without the opt-in.
@kshitij-05
kshitij-05 requested review from Krzmbrzl, ajay-mk and evaleev and a lite review from Copilot and removed request for Krzmbrzl August 14, 2026 17:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 introduces an opt-in exploit_conjugate path that canonicalizes BraKetSymmetry::Conjugate tensors so bra↔ket-swapped orientations share a single eval/cache identity, recording a conjugation “byproduct” and serving the swapped orientation via EvalOp::Adjoint.

Changes:

  • Add exploit_conjugate plumbing to TensorNetworkV3::canonicalize_slots() and graph construction, plus a network-level conj byproduct bit.
  • Extend EvalExpr with canon_conj() (excluded from hashing) and update binarize() to wrap conjugated-orientation leaves with EvalOp::Adjoint when opted in.
  • Refactor tensor block canonicalization to factor out bra/ket orientation logic and add fold_conjugate_braket(), with new unit tests covering flat and ToT leaf paths.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/unit/test_tensor_network.cpp Adds coverage for exploit_conjugate behavior in TN canonicalization metadata and hashing.
tests/unit/test_eval_expr.cpp Adds end-to-end eval/binarize tests asserting leaf folding and Adjoint wrapping behavior when opted in.
tests/unit/test_canonicalize.cpp Adds a ToT-focused regression test validating Conjugate folding behavior and opt-in default-off behavior.
SeQuant/core/tensor_network/v3.hpp Extends canonicalization API/metadata with exploit_conjugate and conj byproduct reporting.
SeQuant/core/tensor_network/v3.cpp Implements Conjugate bra/ket folding in graph coloring and computes the conjugation byproduct.
SeQuant/core/tensor_canonicalizer.hpp Declares fold_conjugate_braket() and an extracted bra/ket orientation helper.
SeQuant/core/tensor_canonicalizer.cpp Implements the extracted orientation logic and Conjugate fold helper; keeps Symm behavior unchanged.
SeQuant/core/eval/eval_expr.hpp Adds EvalExpr(Tensor,bool) doc and canon_conj() API; extends BinarizationOptions.
SeQuant/core/eval/eval_expr.cpp Implements canon_conj_ propagation, passes exploit_conjugate into TN canonicalization, and wraps swapped Conjugate leaves via EvalOp::Adjoint in binarize().

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 15 to 17
#include <initializer_list>
#include <iostream>
#include <memory>
Comment on lines +255 to +258
auto md = [&cardinal](const std::wstring& s, bool exploit) {
TN tn(deserialize(s));
return tn.canonicalize_slots(cardinal, nullptr, {}, exploit);
};
Comment on lines +142 to +145
// Opt-in: fold the two bra<->ket orientations of a ToT Conjugate leaf
// onto one canonical orientation BEFORE the network canonicalization
// (TNV3 does not exploit conjugate braket symmetry itself), recording
// the conjugation byproduct exactly like the flat-leaf branch below.
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