JuliaLinearAlgebra / LinearMaps.jl

A Julia package for defining and working with linear maps, also known as linear transformations or linear operators acting on vectors. The only requirement for a LinearMap is that it can act on a vector (by multiplication) efficiently.
Other
303 stars 42 forks source link

More concise `show` for maps that combine many maps #197

Closed JeffFessler closed 1 year ago

JeffFessler commented 1 year ago

Here's just part of the show output for a LinearMap I've constructed for a dynamic MRI application here https://juliaimagerecon.github.io/Examples/generated/mri/3-2d-t/ This toy example has just 8 frames; a real-world problem could have 100s of frames, so a BlockDiagonalMap with 100s of maps. I'd propose that for any LinearMap type where there are more than, say, 4 maps combined, we just show the first two and last two with in between (or such). This is a minor and non-urgent issue but I hoped to get your thoughts before submitting a PR.

21504×30720 LinearMaps.BlockDiagonalMap{ComplexF64} with 8 diagonal block maps:
  2688×3840 LinearMaps.BlockMap{ComplexF64} with 2 block maps in 2 block rows
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
  2688×3840 LinearMaps.BlockMap{ComplexF64} with 2 block maps in 2 block rows
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
  2688×3840 LinearMaps.BlockMap{ComplexF64} with 2 block maps in 2 block rows
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
  2688×3840 LinearMaps.BlockMap{ComplexF64} with 2 block maps in 2 block rows
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
  2688×3840 LinearMaps.BlockMap{ComplexF64} with 2 block maps in 2 block rows
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
    1344×3840 LinearMaps.CompositeMap{ComplexF64} with 2 maps:
      3840×3840 LinearMaps.WrappedMap{ComplexF32} of
        3840×3840 Diagonal{ComplexF32, Base.ReshapedArray{ComplexF32, 1, SubArray{ComplexF32, 2, Array{ComplexF32, 3}, Tuple{Base.Slice{Base.OneTo{Int64}}, Base.Slice{Base.OneTo{Int64}}, Int64}, true}, Tuple{}}}
      1344×3840 LinearMaps.FunctionMap{ComplexF64}(#5, #7; ismutating=true, issymmetric=false, ishermitian=false, isposdef=false)
JeffFessler commented 1 year ago

I just noticed that the code already is configured to show "just" the first 5 and last 5 maps: https://github.com/JuliaLinearAlgebra/LinearMaps.jl/blob/f8eaf9846f865f74ddb5dda831081f6a6e8db734/src/show.jl#L55 5 is reasonable for simple maps but gets a bit verbose for complicated maps like i have, but it's not worth quibbling about. In general i feel like julia spews too much for 3D and 4D arrays and i can just live with it. So i'll close the issue. Sorry for the extra noise!

dkarrasch commented 1 year ago

In the absence of concrete examples, I took 1:5. I think it goes back to a proposal #84. It's arbitrary anyway, and we could reduce that to, say, 2. After all, the shown output is perhaps not the right way to inspect a complicated LinearMap in the first place.

JeffFessler commented 1 year ago

I'd vote for just first and last, but it's really no big deal either way. The main thing I like to see in a summary is the size and primary type and the eltype.