Refactor MPSTensor construction to fix type piracy - #475
Conversation
`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 Report❌ Patch coverage is
... and 65 files with indirect coverage changes 🚀 New features to boost your workflow:
|
lkdvos
left a comment
There was a problem hiding this comment.
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 ?
|
|
||
| # 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])) |
There was a problem hiding this comment.
| 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.
There was a problem hiding this comment.
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.
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 leavingthe 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 thezeros!call inside them.As @lkdvos noted, these were type piracy (
MPSTensoris aconstalias forAbstractTensorMap, not a type MPSKit owns), and the original issue was really just asymptom of that.
Introduces a small
MPSMapSpace{S, Sₚ}struct that holds(Vₗ, P, Vᵣ), so theVₗ ⊗ P ← Vᵣleg convention lives in exactly one place instead of being repeated in everyconstructor/accessor.
Extends
Base.rand/Base.randn/Base.zerosforMPSMapSpace, giving essentially thezeros(T, Vl * P, Vr)-style interface you mentioned as a preferred option, e.g.:These are added as genuine
Base.rand/Base.randn/Base.zerosmethods (not a new typealias constructor), so there's no piracy here —
MPSMapSpaceis a type this package owns.What this does not do
I left out a dedicated
mpstensor(...)convenience function for now.MPSTensorwas neverexported, and grepping both MPSKit (src, test, docs, examples) and PEPSKit.jl for
MPSTensor(/MPSTensor.(turns up zero call sites outside the old constructor definitionsthemselves, 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
MPSMapSpaceis actually wanted, rather than guessing at a signature nobody's using yet.Happy to add
mpstensor(or renameMPSMapSpaceto something else, ifVl * Pcompositenotation is what you'd rather standardize on) if that's preferred — this is very much open
to being redirected.