Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better printing for MPS #266

Open
starsfordummies opened this issue Dec 2, 2024 · 15 comments
Open

better printing for MPS #266

starsfordummies opened this issue Dec 2, 2024 · 15 comments
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@starsfordummies
Copy link
Contributor

now that we have forms and all that, it would be nice to have it shown when we print an mps. We could print also the info on the bond dimension (see #181 ) , maybe on the physical dimension as well

linkdims(psi) = [size(psi,link) for link in inds(psi, set=:inner)]
maxlinkdim(psi) = maximum(linkdims(psi))
function Base.show(io::IO, tn::T) where {T<:Tenet.AbstractQuantum}
               return print(io, "$T (inputs=$(nsites(tn; set=:inputs)), outputs=$(nsites(tn; set=:outputs))), chimax=$(maxlinkdim(tn)), form=$(form(psi))")
               end
julia> psi = rand(MPS, n=10, maxdim=128)
julia> psi
MPS (inputs=0, outputs=10), chimax=32, form=MixedCanonical(1)

Ideally even printing linkdims(psi) (so the bond dimension on all tensors) would be useful, but right now if I just print them like this it returns it in sparse ordering, which I don't like (should sort it appropriately but I'm not too sure how )

julia> psi = rand(MPS, n=10, maxdim=128)
MPS (inputs=0, outputs=10), chimax=32, form=MixedCanonical(1)

julia> print(linkdims(psi))
[2, 2, 16, 8, 4, 8, 16, 4, 32]
@starsfordummies starsfordummies added the enhancement New feature or request label Dec 2, 2024
@mofeing mofeing added the good first issue Good for newcomers label Dec 2, 2024
@mofeing
Copy link
Member

mofeing commented Dec 2, 2024

I like the idea of prettier printing for MPS, MPO and other types in general.

About printing all the physical and virtual dimensions is not sth that I'm convinced because it will be big when we have a lot sites. But we should have sth like the following working:

size.(Ref(tn), inds(tn; set=:physical))
size.(Ref(tn), inds(tn; set=:virtual))

# or
size(tn; set=:physical)
size(tn; set=:bonds)

In general, the printing should just provide superficial info in a short message. But I agree that additional info should be easy to query.

@starsfordummies
Copy link
Contributor Author

I'm ok with the second option (no idea how the Ref() works but the easier the commands the better)

so for the MPS something like the Base.show() I wrote above would be ok for you ?

I was also thinking about what to do for the physical dimension - in 90% of the cases it's equal for every site so it makes sense to print it once, though there are counterexamples, maybe one could print only the Set() of the physical dims, not sure..

@mofeing
Copy link
Member

mofeing commented Dec 3, 2024

I'm ok with the second option (no idea how the Ref() works but the easier the commands the better)

it actually has nothing to do with Ref (which is like a managed pointer), but a lil trick for broadcasting: if you put an argument in Ref or 1-element tuple, then that argument will be used equally for all calls in the broadcast.

e.g.

size.(Ref(tn), inds(tn; set=:physical))
# is equal to
[
	size(tn, :A),
	size(tn, :B),
	...
]

so for the MPS something like the Base.show() I wrote above would be ok for you ?

Yes, but

  1. You should define it for AbstractAnsatz, not AbstractQuantum
  2. You can remove the inputs/outputs and directly say the number of sites (which you can get with nlanes)

I was also thinking about what to do for the physical dimension - in 90% of the cases it's equal for every site so it makes sense to print it once, though there are counterexamples, maybe one could print only the Set() of the physical dims, not sure..

Printing a Set is gonna be ugly and I don't think is so primordial to print all physical dims. What we can maybe do is print a range, so you can call extrema on the sizes of the physical inds.

@starsfordummies
Copy link
Contributor Author

What is the simplest way to print the sizes of all tensors in the MPS ?
Like if I have

psi2 = MPS([rand(2,2),rand(2,2,4),rand(2,4,7),rand(3,7,4),rand(4,4)])

something that returns
(2,2),(2,2,4),(2,4,7),(3,7,4),(4,4)

@jofrevalles
Copy link
Member

What is the simplest way to print the sizes of all tensors in the MPS ? Like if I have

psi2 = MPS([rand(2,2),rand(2,2,4),rand(2,4,7),rand(3,7,4),rand(4,4)])

something that returns (2,2),(2,2,4),(2,4,7),(3,7,4),(4,4)

If you don't mind the order you can simply do size.(tensors(ψ)).

@starsfordummies
Copy link
Contributor Author

ah nice! but you say order because in principle they might be in the wrong order ?

@jofrevalles
Copy link
Member

ah nice! but you say order because in principle they might be in the wrong order ?

And even size.(ψ) also works by the way. Yes, exactly... This happens when you do operations on them:

julia> psi2 = MPS([rand(2,2),rand(2,2,4),rand(2,4,7),rand(3,7,4),rand(4,4)])

julia> canonize!(psi2)

julia> size.(psi2)
9-element Vector{Tuple{Int64, Vararg{Int64}}}:
 (2, 2)
 (2, 2, 4)
 (4, 2, 7)
 (7, 3, 4)
 (4, 4)
 (2,)
 (4,)
 (7,)
 (4,)

@starsfordummies
Copy link
Contributor Author

I see, then this doesn't work, ideally it would be good to have something that gets the size of the tensor in order with the Sites, and also prints the inds in the same order for all of them like eg. left,phys,right - here it's not clear anymore:

julia> psi2 = MPS([rand(2,2),rand(2,2,4),rand(2,4,7),rand(3,7,4),rand(4,4)])
MPS (inputs=0, outputs=5), chimax=7, form=MixedCanonical(1)

julia> size.(psi2)
5-element Vector{Tuple{Int64, Int64, Vararg{Int64}}}:
 (2, 2)
 (2, 2, 4)
 (2, 4, 7)
 (3, 7, 4)
 (4, 4)

julia> canonize!(psi2)
MPS (inputs=0, outputs=5), chimax=7, form=MixedCanonical(1)

julia> mixed_canonize!(psi2, Site(1))
MPS (inputs=0, outputs=5), chimax=7, form=MixedCanonical(1)

julia> size.(psi2)
5-element Vector{Tuple{Int64, Int64, Vararg{Int64}}}:
 (2, 2)
 (4, 2, 2)
 (7, 2, 4)
 (4, 3, 7)
 (4, 4)

@jofrevalles
Copy link
Member

I see, then this doesn't work, ideally it would be good to have something that gets the size of the tensor in order with the Sites, and also prints the inds in the same order for all of them like eg. left,phys,right - here it's not clear anymore:

I remember I needed once this function you mean and I quickly did this nicely written function:

julia> size_tensors(ψ) =Tenet.size.(vec(vcat([Tensor(permutedims(tensors(ψ, at=Site(1)), (inds(ψ, at=Site(1)), inds(ψ; at=Site(1), dir=:right))), inds(tensors(ψ, at=Site(1)))), tensors(ψ, between=(Site(1), Site(2)))],
[[Tensor(permutedims(tensors(ψ, at=Site(i)), (inds(ψ; at=Site(i), dir=:left), inds(ψ, at=Site(i)), inds(ψ; at=Site(i), dir=:right))), inds(tensors(ψ, at=Site(i)))), tensors(ψ, between=(Site(i), Site(i+1)))] for i in 2:nsites(ψ)-1]...,
[Tensor(permutedims(tensors(ψ, at=Site(nsites(ψ))), (inds(ψ; at=Site(nsites(ψ)), dir=:left), inds(ψ, at=Site(nsites(ψ))))), inds(tensors(ψ, at=Site(nsites(ψ)))))])))
julia> psi2 = MPS([rand(2,2),rand(2,2,4),rand(2,4,7),rand(3,7,4),rand(4,4)]); canonize!(psi2)
julia> size_tensors(psi2)
9-element Vector{Tuple{Int64, Vararg{Int64}}}:
 (2, 2)
 (2,)
 (2, 2, 4)
 (4,)
 (4, 2, 7)
 (7,)
 (7, 3, 4)
 (4,)
 (4, 4)

Which works for the Canonical form MPS. Of course we can do something like this (but properly written).

@mofeing
Copy link
Member

mofeing commented Dec 3, 2024

@starsfordummies just out of curiosity, is there sth you're trying? like what's your motivation for getting the size of tensors in order? is it just for debugging or are you trying sth else?

btw, having a reorder!(tn, order) function that permutedims the tensors to have them in the same order is totally doable

@starsfordummies
Copy link
Contributor Author

mostly for debugging I think it'd be nice to check if anything funky is going on with the MPS tensors. Doing some permutedims is kind of expensive for just some pretty printing though, no ?

@mofeing
Copy link
Member

mofeing commented Dec 3, 2024

yes, but we can also use PermuteDims which is a lazy version of permutedims

if you want it for debugging, we can maybe add support for About.jl

@starsfordummies
Copy link
Contributor Author

starsfordummies commented Dec 4, 2024

or maybe something like this which doesn't touch the tensors, no ?

 function print_sizes(psi)
       _size(psi, x) = isnothing(x) ? 1 : size(psi,x)

       ss = sites(psi)
      
       @assert length(ss) > 2  "too lazy for that" 

       sa(ind) = size(psi, at=ind)
       sl = map(x -> _size(psi, x), [inds(psi; at=s, dir=:left) for s in ss])
       sr = map(x -> _size(psi, x), [inds(psi; at=s, dir=:right) for s in ss])
       sp = map(x -> _size(psi, x), [inds(psi; at=s) for s in ss])
       sizes = "[$(sp[1]),$(sr[1])] "
       for ii in eachindex(ss)[2:end-1]
          sizes *= " [$(sl[ii]),$(sp[ii]),$(sr[ii])] "
       end
       sizes *= " [$(sl[end]), $(sp[end])]"

       return sizes
end

@mofeing
Copy link
Member

mofeing commented Dec 4, 2024

yeah, but I prefer not filling Tenet with hundreds of different functions.

There's no problem into adding this print_sizes function to a Tenet+About extension.

@jofrevalles
Copy link
Member

But maybe this is useful to have without extensions, right? We can talk about it in the next meeting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

3 participants