Skip to content

Fermion twist#703

Open
manuschneider wants to merge 24 commits intomasterfrom
fermion_twist
Open

Fermion twist#703
manuschneider wants to merge 24 commits intomasterfrom
fermion_twist

Conversation

@manuschneider
Copy link
Copy Markdown
Collaborator

-Added fermion twists, which corresponds to the P-gates in arXiv:2404.14611
-Cleaned up code and updated documentation
-Made all methods return a pointer to the class to allow for chaining (e.g. UniTensor.contiguous().fermion_twists(). ...)

@codecov
Copy link
Copy Markdown

codecov bot commented Nov 3, 2025

Codecov Report

❌ Patch coverage is 20.12780% with 250 lines in your changes missing coverage. Please review.
✅ Project coverage is 36.23%. Comparing base (b527d89) to head (f298349).
⚠️ Report is 57 commits behind head on master.

Files with missing lines Patch % Lines
include/backend/Scalar.hpp 0.00% 108 Missing ⚠️
src/BlockFermionicUniTensor.cpp 35.29% 28 Missing and 5 partials ⚠️
include/UniTensor.hpp 26.19% 28 Missing and 3 partials ⚠️
src/BlockUniTensor.cpp 26.47% 22 Missing and 3 partials ⚠️
src/backend/Storage_base.cpp 13.33% 13 Missing ⚠️
src/UniTensor_base.cpp 0.00% 12 Missing ⚠️
src/backend/StorageImplementation.cpp 0.00% 3 Missing and 2 partials ⚠️
src/utils/vec_range.cpp 0.00% 5 Missing ⚠️
include/tn_algo/MPS.hpp 0.00% 4 Missing ⚠️
src/stat/histogram.cpp 0.00% 3 Missing ⚠️
... and 8 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #703      +/-   ##
==========================================
+ Coverage   35.65%   36.23%   +0.58%     
==========================================
  Files         214      214              
  Lines       33068    33132      +64     
  Branches    13157    13171      +14     
==========================================
+ Hits        11789    12005     +216     
+ Misses      19349    19184     -165     
- Partials     1930     1943      +13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@hunghaoti
Copy link
Copy Markdown
Collaborator

Is it possible to add some simple unit test?

@manuschneider
Copy link
Copy Markdown
Collaborator Author

Is it possible to add some simple unit test?

done

@manuschneider manuschneider added the Pending check/approval Issue fixed, and need feedback label Feb 12, 2026
@ianmccul
Copy link
Copy Markdown
Collaborator

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ba15358496

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/BlockFermionicUniTensor.cpp Outdated
Comment thread src/BlockFermionicUniTensor.cpp Outdated
1) Transpose sets is_diag correctly after changing rowrank
2) Error messages print unknown labels as strings instead of integers
@manuschneider
Copy link
Copy Markdown
Collaborator Author

All fixed.

Copy link
Copy Markdown
Collaborator

@pcchen pcchen left a comment

Choose a reason for hiding this comment

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

PR Review: Fermion twist

Posted by Claude Code on behalf of @pcchen

Summary

This PR adds fermion twist operations (twist, twist_, fermion_twists, fermion_twists_) to UniTensor, implementing the P-gate concept from arXiv:2404.14611. It also makes several methods return *this for method chaining, improves error messages and documentation, and capitalizes cannotCannot throughout the codebase.

The core logic is reasonable. There are a few real bugs to address, along with some concerns about the scope of the change.


Critical Issues

1. Debug cout left in BlockFermionicUniTensor::permute_nosignflip_

src/BlockFermionicUniTensor.cpp, permute_nosignflip (string-label overload):

mapper_i64.push_back(std::distance(out_raw->_labels.begin(), it));
}
cout << "Mapper: " << mapper_i64 << endl;  // <-- debug output in production!

This will print to stdout on every call to permute_nosignflip by label. Should be removed.


2. No tests for the new API

The PR adds twist(), twist_(), fermion_twists(), fermion_twists_() (C++ and Python), but no test files are modified. These operations are non-trivial (they flip sign bits on specific blocks), so correctness should be verified by unit tests covering at minimum:

  • twist_ on a single-bond fermionic tensor with known parity
  • fermion_twists_ on a multi-bond tensor
  • Calling twist on a bosonic tensor (should be a no-op)
  • Invalid index / label error paths

Important Issues

3. UniTensor_base::twist_() base implementations always throw

src/UniTensor_base.cpp:

void UniTensor_base::twist_(const cytnx_int64 &idx) {
  cytnx_error_msg(
    true, "[ERROR] fatal internal, cannot call on an un-initialized UniTensor_base%s", "\n");
}

These always throw, with an error message about "un-initialized UniTensor_base". In practice, concrete types (DenseUniTensor, BlockUniTensor, BlockFermionicUniTensor) all override them correctly, so this is never reached for initialized tensors. However, the error message is wrong — it says "un-initialized UniTensor_base" but it would be triggered for any type that inherits without overriding (e.g., VoidUniTensor or future subclasses). Consider making these pure virtual or at least fixing the error message.


4. fermion_twists_() docstring is contradictory

include/UniTensor.hpp, docstring for fermion_twists():

@brief Apply twists to all bra bonds with type BD_KET

"Bra bonds with type BD_KET" is self-contradictory. Bra bonds are typically BD_BRA. The implementation applies twists to bonds at positions idx >= rowrank that have type BD_KET. The docstring needs to be reworded to clearly describe this: e.g., "Apply twists to all bonds in bra-position (index ≥ rowrank) that have bond type BD_KET."


5. twist_(std::string label) should be const std::string &

include/UniTensor.hpp and src/BlockFermionicUniTensor.cpp:

virtual void twist_(const std::string label);           // base class
void twist_(const std::string label) override { ... }  // DenseUniTensor, BlockUniTensor
void BlockFermionicUniTensor::twist_(const std::string label) { ... }

All overloads take std::string by value. Throughout the codebase, label parameters are consistently passed as const std::string &. This should be const std::string &label to match conventions and avoid unnecessary copies.


Minor Issues

6. Typo in docstring: "weather" → "whether"

include/UniTensor.hpp, twist() docstring:

@note This always applies the twist to the bond, ignoring its direction or weather they are
incoming or outgoing bonds.

Should be "whether".

7. Duplicate sentence in get_block warning

include/UniTensor.hpp, warning added to get_block(const cytnx_uint64 &idx = 0):

Use signflip() to get the sign structure for each block. Use signflip() to get the sign
structure for each block.

The sentence "Use signflip() to get the sign structure for each block." appears twice.

8. Commented-out code in include/UniTensor.hpp

A block of commented-out permute_ overloads was added:

// void permute_( const std::initializer_list<char*> &mapper, ...
// void permute_(const std::vector<cytnx_int64> &mapper, ...

These should be removed if no longer needed.

9. Unsigned underflow in twist_ error message

src/BlockFermionicUniTensor.cpp, twist_(const cytnx_int64 &idx):

cytnx_error_msg(idx >= this->_labels.size() || idx < 0,
                "...[0, %d].\n",
                idx, this->_labels.size() - 1);

When _labels.size() == 0, _labels.size() - 1 underflows (wraps to a very large unsigned number). Protect with a check or use a signed cast.

10. Scope of capitalization churn

The cannotCannot change spans ~200 locations across Scalar.hpp, Storage_base.cpp, StorageImplementation.cpp, MPS.hpp, SparseUniTensor.cpp, RegularGncon.cpp, and many more. While consistency is good, mixing this into a feature PR makes it substantially harder to review. Consider isolating it in a separate PR.


Positive Observations

  • The design is clean: bosonic types override twist_() as a no-op, and only BlockFermionicUniTensor has the real implementation.
  • Method chaining (returning *this) is a useful ergonomic improvement.
  • The fermion_twists_() documentation correctly describes the physical motivation (scalar products of fermionic states).
  • Error messages for permute, permute_nosignflip, and contract are now significantly more informative with tensor names and label values included.
  • Debug couts removed from contract are appropriate cleanup.
  • The Transpose_() rowrank expression simplification is correct.

Recommended Actions

  1. Remove the debug cout in permute_nosignflip (item 1) — will spam stdout in production.
  2. Add unit tests for twist_() and fermion_twists_() (item 2).
  3. Fix docstring contradiction in fermion_twists() (item 4).
  4. Pass label by const std::string & in twist_() overloads (item 5).
  5. Fix the "weather" typo (item 6) and duplicate sentence (item 7).
  6. Consider splitting the capitalization changes into a separate PR (item 10).

pass string by reference
debug cout removed and cleanup
docstring/error message updates
@manuschneider
Copy link
Copy Markdown
Collaborator Author

  1. 1. fixed
  2. 2. use AI for help with unit tests?
    [ ] 3. This is our default mode: UniTensor_base throws an error because it means the UniTensor was not initialized correctly
  3. 4. fixed
  4. 5. fixed
  5. 6. fixed
  6. 7. fixed
  7. 8. fixed
  8. 9. fixed
    [ ] 10. Agreed, but will keep it here

Use master's build_accessors() helper in __getitem__ and __setitem__
instead of the inlined accessor-building logic from fermion_twist.
Also picks up master's typo fix ("Blcok" -> "Block") in error message.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f298349f7e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pybind/unitensor_py.cpp
Comment on lines 559 to +560
.def("permute_nosignflip_", [](UniTensor &self, const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank){
self.permute_nosignflip_(mapper,rowrank);
return self.permute_nosignflip_(mapper,rowrank);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return self by reference in chainable pybind wrappers

These new in-place bindings return from lambdas without an explicit return type, so C++ deduces auto as UniTensor (by value) rather than UniTensor&. That means self.permute_nosignflip_(...)/self.twist_(...) mutate self but then return a copy, so chained calls execute on a temporary copy instead of the original object unless the caller reassigns (e.g. u.permute_nosignflip_(...).twist_()). Use an explicit -> UniTensor& return type (and reference return policy) for these overload lambdas.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Pending check/approval Issue fixed, and need feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants