Skip to content

Refactor TJOperators to the dense-first strategy - #57

Merged
lkdvos merged 7 commits into
mainfrom
ld-tj
Jul 30, 2026
Merged

lkdvos merged 7 commits into
mainfrom
ld-tj

Conversation

@lkdvos

@lkdvos lkdvos commented Jul 27, 2026

Copy link
Copy Markdown
Member

Brings TJOperators in line with every other operator module: dense reference operators defined first, symmetric ones obtained by basis transformation + projection through @operator. Previously all 31 operators were generated by an @eval loop projecting the HubbardOperators counterparts, with docstrings scraped from Hubbard and patched by string substitution.

The two bases

slave_fermion is a parameter of the reference space, like spin in SpinOperators: @operator forwards keywords to the reference method as well as to the hook, and (Trivial, Trivial) never reaches _symmetrize_operator, so the reference has to return the operator in the requested basis. Flipping the parity also reorders the reference dense basis (|0⟩, |↑⟩, |↓⟩ → |↑⟩, |↓⟩, |0⟩), so basis_transform takes slave_fermion too. It comes out a pure integer permutation in both bases; the staggered sign of the slave-fermion representation stays inside transform_slave_fermion, applied once to the assembled N-site reference.

Other changes

  • tj_space is dispatched on the symmetries and rejects SU2Irrep particle symmetry with a dedicated error (no η-pairing doublet without |↑↓⟩).
  • Real docstrings per operator, without the unreachable |↑↓⟩ matrix elements the transplanted ones advertised.
  • Fixes three misaligned aliases of the old positional zip: u⁺u⁺/d⁻d⁻ were swapped with d_min_d_min/u_plus_u_plus, and S⁺S⁻/S⁻S⁺ with each other.
  • tj_projector stays public and documents the projection relation to HubbardOperators, which the tests now check.
  • Tests mirror test/hubbardoperators.jl: availability predicates, basis-transform unitarity and scalar-type preservation, test_operator_dense instead of the spectral comparison, transpose-regression values, the Hubbard projection relation, and the invariant O(…; slave_fermion = true) ≈ transform_slave_fermion(O(…)).
  • Drops the spectrum testsets (t-J and Hubbard), subsumed by the element-wise comparison; the analytic ED testsets are kept.

Verified against the pre-refactor implementation: all 31 operators match element-wise for the 6 symmetry combinations × both bases. Full suite green.

🤖 Generated with Claude Code

lkdvos and others added 2 commits July 27, 2026 10:37
Bring the t-J module in line with every other operator module: define the
dense reference operators first and obtain the symmetric ones by a basis
transformation + projection, generated by `@operator`.

Previously all 31 operators were generated by an `@eval` loop that projected
the corresponding `HubbardOperators` operator, and their docstrings were
scraped from Hubbard and patched by string substitution.

- `tj_space` is dispatched on the symmetries, and rejects `SU2Irrep` particle
  symmetry with a dedicated error (there is no η-pairing doublet without the
  doubly occupied state).
- New `basis_transform(P, S; slave_fermion)`, built generically from the sector
  order of the target space, which makes `test_operator_dense` available.
- The basis choice is a parameter of the reference space, like `spin` in
  `SpinOperators`: `slave_fermion` is forwarded to both the reference operator
  and `_symmetrize_operator`, so it also selects the reference dense ordering
  (the parity flip moves the holon to the back).
- The staggered sign of the slave-fermion representation stays inside
  `transform_slave_fermion`, applied once to the assembled N-site reference;
  derived operators are built in the plain basis and transformed at the end.
- Real docstrings per operator, without the unreachable |↑↓⟩ matrix elements
  the transplanted Hubbard ones advertised.
- Fixes three misaligned aliases of the old positional `zip`: `u⁺u⁺` and `d⁻d⁻`
  were swapped with `d_min_d_min`/`u_plus_u_plus`, and `S⁺S⁻`/`S⁻S⁺` with each
  other.
- `tj_projector` remains public and now documents the projection relation to
  `HubbardOperators`, which the tests check.

Tests mirror `test/hubbardoperators.jl`: availability predicates, basis
transform unitarity and scalar-type preservation, element-wise dense
comparison instead of the spectral one, regression values against transposes,
the Hubbard projection relation, and the slave-fermion consistency invariant
`O(…; slave_fermion = true) ≈ transform_slave_fermion(O(…))`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The chain-spectrum comparisons are largely subsumed by `test_operator_dense`,
which compares every operator element-wise per bond and additionally catches
transposes and gauge rotations. The analytic exact-diagonalisation testsets are
kept as the many-body sanity check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lkdvos

lkdvos commented Jul 27, 2026

Copy link
Copy Markdown
Member Author

@Yue-Zhengyuan, I was planning to tag after this PR, so we can release the new "trivial-to-symmetric" path

- `tj_projector` referred to the `HubbardOperators` module with `@ref`, which
  Documenter cannot resolve (modules have no docstring here).
- Hoist the `Iterators.product` symmetry loops into named iterators, so the
  `for ... in` headers fit on one line: the line-range formatting `git runic`
  applies to a diff disagrees with whole-file formatting on that continuation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.63014% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/tjoperators.jl 98.63% 1 Missing ⚠️
Files with missing lines Coverage Δ
src/hubbardoperators.jl 98.88% <ø> (ø)
src/tjoperators.jl 98.95% <98.63%> (+6.80%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Yue-Zhengyuan Yue-Zhengyuan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm strongly against defining the t-J operators from hard-coded dense tensors all over again. I would still use projection from the corresponding Hubbard operators as the definition.

But the dense-conversion can be a good test: we de-symmetrize the symmetric t-J operators, and check that they are the same as the dense non-symmetric one.

@lkdvos

lkdvos commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

Oh, no worries, I somehow must have misinterpreted a previous conversation we had and I had it in my head that you wanted something similar to simplify the tests.
I'll try and rework this, but I would somehow like to keep the use of the @operator macro in there, just for uniformity. Maybe the best way is to just define the dense versions in terms of the dense Hubbard versions, and then keep the remaining machinery?

@Yue-Zhengyuan

Copy link
Copy Markdown
Member

I prefer not to change current TJOperator, only adding the basis transformations to enable the dense-symmetric comparison that was not supported before.

@lkdvos

lkdvos commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

Ok in the current version then? This keeps everything defined in terms of Hubbard, but fixes the issues that are listed in the PR description above. I agree the docstrings are a bit annoying, but I also didn't really like that the doubly-occupied state was there in the first place, so this seems like a reasonable inbetween solution

@lkdvos
lkdvos requested a review from Yue-Zhengyuan July 28, 2026 17:23

@Yue-Zhengyuan Yue-Zhengyuan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is more or less what I want. But I still have some opinions on docstring handling.

Comment thread src/tjoperators.jl Outdated
Comment thread src/tjoperators.jl Outdated
lkdvos and others added 2 commits July 29, 2026 13:53
The t-J operators are projections of the Hubbard operators of the same name, but
their docstrings restated the Hubbard prose in the `_OPERATORS` registry, and the
two copies had drifted. Make `HubbardOperators` the single source of truth and
inherit the descriptions from its docstrings at load time.

The listings of nonzero matrix elements are dropped from both modules: they were
the reason the two texts could not be shared, since the projection kills most of
the elements. Hubbard absorbs everything else the t-J docstrings had: the
"electrons" wording, the symmetry-compatibility remarks and the leg-ordering
diagram of the 3-site term.

Descriptions are read with `@doc`, which returns the raw docstring on recent Julia
versions and a rendered `Markdown.MD` object on 1.10; stringifying the latter
reflows the text and writes inline math as `$x$`, which parses the same way. An
admonition in a Hubbard operator docstring is Hubbard-specific and is not
inherited -- currently only the staggered-gauge note of `e_hopping`, which must
stay out of the t-J docs because t-J has no `SU2Irrep` particle symmetry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lkdvos

lkdvos commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

I agree that this duplication is a bit annoying, but there are definitely drawbacks to copying things from the hubbard counterparts.
I don't really like the annoying 1.10 vs 1.12 behavior changes (@doc returning markdown or regular strings), and this still silently assumes that we can never add anything related to the SU2Irrep-particlenumber specific parts without explicitly removing it in the TJOperators.
Ultimately it's trading off repetition for complexity, and I don't know which is best.

I made an attempt here to do something like you described, let me know what you think.

@lkdvos
lkdvos requested a review from Yue-Zhengyuan July 29, 2026 18:10
@Yue-Zhengyuan
Yue-Zhengyuan dismissed their stale review July 30, 2026 00:42

Concern on duplication is addressed.

@Yue-Zhengyuan Yue-Zhengyuan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

_inherit_description is clean enough and much better than repeating the docstrings.

@lkdvos
lkdvos merged commit 8c34c2d into main Jul 30, 2026
9 checks passed
@lkdvos
lkdvos deleted the ld-tj branch July 30, 2026 03:06
lkdvos added a commit that referenced this pull request Jul 30, 2026
Closes the main part of #45. Both stub pages now follow the structure of the
spin operator page: conventions with basis ordering and symmetry sectors, an
operator overview table, and the autodocs API section.

Since both modules take two independent symmetry arguments, the overview
tables carry separate particle and spin columns. This is exact rather than an
approximation: every availability predicate in the test suite factorizes into
an independent condition per symmetry axis.

The basis-ordering sections document the parity-sorted reference order
(|0>, |updn>, |up>, |dn> for Hubbard) rather than the enumeration order used
in the prose so far, and give a recipe for reading off the dense order of the
symmetric spaces instead of tabulating it, since it follows TensorKit's sector
sorting and is not part of the interface.

The t-J page additionally documents the slave-fermion keyword, including the
warning that the transformation does not distribute over tensor products, and
the projection relation to the Hubbard model.

Upgrade the docstrings of both modules to match: math definitions where they
were missing, and an explicit `Compatible symmetries:` line replacing the
ad-hoc prose notes. Since #57 made the t-J operator docstrings inherit their
description from the Hubbard docstring of the same name, that prose now lives
in `HubbardOperators` and reaches `TJOperators` through the inheritance, which
imposes two rules on it:

- Anything true only of the Hubbard space goes into an admonition, the
  mechanism #57 already uses to keep the staggered-gauge note out of the t-J
  docs. That now also covers the listings of nonzero matrix elements, which
  are basis-specific, and the remarks about `SU2Irrep` particle symmetry,
  which t-J does not have. The shared prose is worded to hold in both spaces,
  which is why the eigenvalue listings characterize the states they act on
  instead of enumerating a fixed basis.

- The symmetry line is derived rather than restated. t-J supports exactly the
  Hubbard combinations minus `SU2Irrep` particle symmetry, because the
  eta-pairing doublet (|updn>, |0>) loses its doubly occupied state to the
  projection, so `_project_symmetries` strips that one entry from the
  inherited line. The spin symmetries carry over verbatim, for all 31
  operators of the registry.

Along the way:
- `HubbardOperators.h_num` is `1 - n`, so it takes the value -1 on the doubly
  occupied state rather than counting holes as its docstring claimed. Document
  what it actually does, and point to the t-J module, where it is a genuine
  projector.
- Fix a few typos and an inconsistent float literal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lkdvos added a commit that referenced this pull request Jul 31, 2026
)

Closes #45.

`spinoperators.md` and `quantumgates.md` were full documentation pages;
the other four were 9-line bare `@autodocs` stubs. This brings all six
to the same structure — Conventions (basis ordering, symmetry sectors),
an operator overview table, then the `@autodocs` API section. Since
`@autodocs` only renders what the docstrings contain, the docstrings
were upgraded in step: math definitions, matrix elements, and an
explicit `Supported symmetries:` line where Boson/Fermion had none and
Hubbard had only ad-hoc prose.

### Rendered preview

Mostly prose, tables and math, so much easier to review rendered than as
a diff:

| Page | Preview |
|---|---|
| Boson operators |
https://quantumkithub.github.io/TensorKitTensors.jl/previews/PR58/bosonoperators/
|
| Fermion operators |
https://quantumkithub.github.io/TensorKitTensors.jl/previews/PR58/fermionoperators/
|
| Hubbard operators |
https://quantumkithub.github.io/TensorKitTensors.jl/previews/PR58/hubbardoperators/
|
| t-J operators |
https://quantumkithub.github.io/TensorKitTensors.jl/previews/PR58/tjoperators/
|

Full preview:
https://quantumkithub.github.io/TensorKitTensors.jl/previews/PR58/

### Notable decisions

- **The Hubbard/t-J overview tables use separate particle and spin
columns.** Exact, not an approximation: every `has_*(P, S)` predicate in
the test suite factorizes into an independent condition per axis.
- **The basis-ordering sections document the parity-sorted reference
order** — for Hubbard `|0⟩, |↑↓⟩, |↑⟩, |↓⟩`, not the enumeration used so
far, which is not an index order anywhere and read as a competing
convention against `basis_transform`.
- **The dense order of the *symmetric* spaces is a recipe, not a
table**, since it follows TensorKit's sector sorting and is not part of
the interface; tabulating it could silently desync.
- **The t-J page documents `slave_fermion`**, including the warning that
`transform_slave_fermion` does not distribute over `⊗`.

### Fitting the t-J docstrings to #57

#57 made each t-J operator docstring inherit its description from the
`HubbardOperators` docstring of the same name, so this prose lives in
`HubbardOperators` and reaches `TJOperators` through the inheritance.
Two rules follow:

- **Hubbard-only statements go into admonitions**, the mechanism #57
already uses for the staggered-gauge note. That now also covers the
nonzero-matrix-element listings (basis-specific) and the
`SU2Irrep`-particle remarks (t-J has no such symmetry). Shared prose is
worded to hold in both spaces, so eigenvalue listings characterize the
states they act on rather than enumerate a fixed basis.
- **The symmetry line is derived, not restated.** t-J supports exactly
the Hubbard combinations minus `SU2Irrep` particle symmetry — the
η-pairing doublet `(|↑↓⟩, |0⟩)` loses its doubly occupied state to the
projection — so `_project_symmetries` strips that entry from the
inherited line. Spin symmetries carry over verbatim for all 31
operators.

Trade-off worth flagging: per-operator prose true *only* of t-J has no
home under this design (that `n` never exceeds one, that `nʰ + n = 1`).
Both are stated on the t-J page instead.

### Bugs found along the way

- **`HubbardOperators.h_num` did not count holes.** It was `1 - n`,
returning `-1` on the doubly occupied state; now `(1 - nꜛ)(1 - nꜜ)`, the
projector onto the empty state. Invisible through the t-J projection —
the discrepancy lives entirely on `|↑↓⟩`, which the projector removes —
so `TJOperators.h_num` agreed either way. Tests now pin down idempotency
and `nʰ + n = 1 + nꜛnꜜ`.
- **`boson_space(; cutoff)` was a `MethodError`**, unlike every other
module's space constructor, while its docstring already advertised the
symmetry argument as optional.
- **An inherited `@ref` cannot name a Hubbard-only binding.** `h_num`'s
`See also ud_num` broke cross-references on the t-J page; it moves into
the admonition with the rest of the double-occupancy caveat.

### Also

`Documenter` compat bumped to `1.9`, which introduced `checkdocs =
:public` (on 1.8.x the symbol is unvalidated and silently disables the
check). `operatorpages` puts Hubbard before t-J, since the t-J page
refers to it several times. Harmonized on `Supported symmetries`
package-wide. Assorted typos, and `T` → `elt` in `FermionOperators` for
consistency.

### Verification

- Full test suite passes: 2387 tests. Runic clean, docs build clean.
- **855 symmetry combinations checked against the overview tables, 0
mismatches** — tables parsed out of the markdown, every listed
combination asserted to construct and every unlisted one to throw,
across both t-J bases.
- All 31 generated t-J docstrings audited: no Hubbard-only text
inherited, every symmetry line correct.
- 440 math expressions validated against KaTeX — Documenter renders math
client-side, so a glyph with no font metrics gives a clean build and a
blank on the page.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Yue Zhengyuan <yuezy1997@icloud.com>
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