Skip to content

Refactor MPSTensor construction to fix type piracy - #475

Open
VinceNeede wants to merge 2 commits into
QuantumKitHub:mainfrom
VinceNeede:vb-mpstensor
Open

Refactor MPSTensor construction to fix type piracy#475
VinceNeede wants to merge 2 commits into
QuantumKitHub:mainfrom
VinceNeede:vb-mpstensor

Conversation

@VinceNeede

Copy link
Copy Markdown
Contributor

Closes #471.

Not really my place to be doing bigger refactors yet (this is only my second PR, after my
DMRG3S implementation), but the discussion in #471 pointed pretty directly at a concrete fix,
so I wanted to give it a try rather than just patching zeros!zerovector! and leaving
the type piracy in place.

What this does

  • Removes the old MPSTensor(f, T, P, Vₗ, Vᵣ) / MPSTensor(::UndefInitializer, ...) /
    MPSTensor(d, Dₗ, Dᵣ) constructors, rather than just fixing the zeros! call inside them.
    As @lkdvos noted, these were type piracy (MPSTensor is a const alias for
    AbstractTensorMap, not a type MPSKit owns), and the original issue was really just a
    symptom of that.

  • Introduces a small MPSMapSpace{S, Sₚ} struct that holds (Vₗ, P, Vᵣ), so the
    Vₗ ⊗ P ← Vᵣ leg convention lives in exactly one place instead of being repeated in every
    constructor/accessor.

  • Extends Base.rand/Base.randn/Base.zeros for MPSMapSpace, giving essentially the
    zeros(T, Vl * P, Vr)-style interface you mentioned as a preferred option, e.g.:

    julia> zeros(Float64, MPSMapSpace(ℂ^10, ℂ^2, ℂ^10))

    These are added as genuine Base.rand/Base.randn/Base.zeros methods (not a new type
    alias constructor), so there's no piracy here — MPSMapSpace is a type this package owns.

What this does not do

I left out a dedicated mpstensor(...) convenience function for now. MPSTensor was never
exported, and grepping both MPSKit (src, test, docs, examples) and PEPSKit.jl for
MPSTensor(/MPSTensor.( turns up zero call sites outside the old constructor definitions
themselves, so I don't think there's a hidden dependency on the old constructor shapes. Given
that, it felt safer to start minimal and let you decide whether a convenience wrapper on top
of MPSMapSpace is actually wanted, rather than guessing at a signature nobody's using yet.

Happy to add mpstensor (or rename MPSMapSpace to something else, if Vl * P composite
notation is what you'd rather standardize on) if that's preferred — this is very much open
to being redirected.

`MPSTensor` used type piracy, the new struct `MPSMapSpace` allows to keep the default leg convention `Vl * Vp <- Vr` in one place, and overload `rand`, `randn` and `zeros` constructor
@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.00000% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/states/abstractmps.jl 50.00% 3 Missing ⚠️
src/states/infinitemps.jl 66.66% 1 Missing ⚠️
Files with missing lines Coverage Δ
src/states/finitemps.jl 93.72% <100.00%> (+8.11%) ⬆️
src/states/infinitemps.jl 80.14% <66.66%> (+5.14%) ⬆️
src/states/abstractmps.jl 54.79% <50.00%> (+4.79%) ⬆️

... and 65 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@lkdvos lkdvos 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.

Thanks for getting started with this!

I think my main question here is about whether it makes sense to have MPSMapSpace as a dedicated struct, or we could just use TensorMapSpace{S,N,1} directly and get rid of this functionality.
I understand that it can be convenient to not have to think too much about the exact shape of the tensors, but on the other hand it is also useful to be more upfront about the underlying structure of these tensors, and it is slightly less code to maintain.

I'd be curious to hear what other people think too, @VictorVanthilt, @borisdevos, @leburgel ?

Comment thread src/states/finitemps.jl

# construct MPS
tensors = MPSTensor.(f, elt, Pspaces, Vspaces[1:(end - 1)], Vspaces[2:end])
tensors = @. f(elt, MPSMapSpace(Vspaces[1:(end - 1)], Pspaces, Vspaces[2:end]))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
tensors = @. f(elt, MPSMapSpace(Vspaces[1:(end - 1)], Pspaces, Vspaces[2:end]))
tensors = @. f(elt, Vspaces[1:(end - 1)] Pspaces Vspaces[2:end])

@lkdvos do you mean something like this directly? This was my original idea, but I didn't love hardcoding this specific TensorMapSpace construction at every call site — I thought a centralized struct would make the convention easier to maintain in one place, which is why I went with MPSMapSpace instead.

That said, I don't have a strong opinion — happy to go with whichever you and the others prefer.

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.

Yeah exactly. I agree it is nice to have a centralized part for this, but the struct really is just a TensorMapSpace which has to reimplement some of the logic that already is there, so there might be an argument for the fact that TensorMapSpace already is this centralized convention and we don't need to reinvent that here.

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.

zeros initialization of MPSTensor not working

2 participants