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

Introduce specific show methods, add Base.parent overload #87

Merged
merged 10 commits into from
Oct 7, 2020
Merged

Conversation

dkarrasch
Copy link
Member

I was very inspired by the show methods in #84, so I went ahead and introduced consistent such methods for all LinearMap subtypes. This is the current output:

julia> using LinearAlgebra, LinearMaps

julia> A = LinearMap(rand(10, 10))
10×10 LinearMaps.WrappedMap{Float64} of
 0.6769273787529222   0.036539631768852665    0.9873418166811534
 0.6765549649256377   0.9624717119719399       0.3575343347655404
 0.31545830565381205  0.846611890984601        0.07509443800525162
 0.9046438881682486   0.6282119777830519       0.16271650036125607
 0.13027892373965533  0.18887153454128924      0.3656173314780382
 0.8105579896722099   0.8689278012808201      0.613575621252296
 0.3501936207693894   0.41662154485059477      0.634150209365973
 0.5371570288242542   0.7182968669111338       0.3200262911743803
 0.9126028660250189   0.25564178492353906      0.23743297526797136
 0.5819814278543964   0.9943728715581492       0.4875339524077975

julia> B = LinearMap(rand(10, 10))
10×10 LinearMaps.WrappedMap{Float64} of
 0.8700744216295719     0.458876698914481      0.21599839571588952
 0.5444272069489469     0.30974679189517595     0.20158982970939365
 0.0039023841368437395  0.1743141153244383      0.5255090943219167
 0.6585137742811065     0.21529067784534073     0.09553647923800157
 0.6810489351017359     0.7726713554570053      0.88655004487403
 0.02948775918770319    0.804402117644776      0.8520117918594712
 0.981317366746389      0.42937017270368405     0.723298669979153
 0.05590009791874673    0.23243683344460941     0.7504218236329141
 0.6105003794996771     0.23372276641277856     0.5026331262236272
 0.45419955654642186    0.9829667847054768      0.5560613057463222

julia> A + B
10×10 LinearMaps.LinearCombination{Float64} with 2 maps:
10×10 LinearMaps.WrappedMap{Float64} of
 0.6769273787529222   0.036539631768852665    0.9873418166811534
 0.6765549649256377   0.9624717119719399       0.3575343347655404
 0.31545830565381205  0.846611890984601        0.07509443800525162
 0.9046438881682486   0.6282119777830519       0.16271650036125607
 0.13027892373965533  0.18887153454128924      0.3656173314780382
 0.8105579896722099   0.8689278012808201      0.613575621252296
 0.3501936207693894   0.41662154485059477      0.634150209365973
 0.5371570288242542   0.7182968669111338       0.3200262911743803
 0.9126028660250189   0.25564178492353906      0.23743297526797136
 0.5819814278543964   0.9943728715581492       0.4875339524077975
10×10 LinearMaps.WrappedMap{Float64} of
 0.8700744216295719     0.458876698914481      0.21599839571588952
 0.5444272069489469     0.30974679189517595     0.20158982970939365
 0.0039023841368437395  0.1743141153244383      0.5255090943219167
 0.6585137742811065     0.21529067784534073     0.09553647923800157
 0.6810489351017359     0.7726713554570053      0.88655004487403
 0.02948775918770319    0.804402117644776      0.8520117918594712
 0.981317366746389      0.42937017270368405     0.723298669979153
 0.05590009791874673    0.23243683344460941     0.7504218236329141
 0.6105003794996771     0.23372276641277856     0.5026331262236272
 0.45419955654642186    0.9829667847054768      0.5560613057463222

julia> A*B
10×10 LinearMaps.CompositeMap{Float64} with 2 maps:
10×10 LinearMaps.WrappedMap{Float64} of
 0.8700744216295719     0.458876698914481      0.21599839571588952
 0.5444272069489469     0.30974679189517595     0.20158982970939365
 0.0039023841368437395  0.1743141153244383      0.5255090943219167
 0.6585137742811065     0.21529067784534073     0.09553647923800157
 0.6810489351017359     0.7726713554570053      0.88655004487403
 0.02948775918770319    0.804402117644776      0.8520117918594712
 0.981317366746389      0.42937017270368405     0.723298669979153
 0.05590009791874673    0.23243683344460941     0.7504218236329141
 0.6105003794996771     0.23372276641277856     0.5026331262236272
 0.45419955654642186    0.9829667847054768      0.5560613057463222
10×10 LinearMaps.WrappedMap{Float64} of
 0.6769273787529222   0.036539631768852665    0.9873418166811534
 0.6765549649256377   0.9624717119719399       0.3575343347655404
 0.31545830565381205  0.846611890984601        0.07509443800525162
 0.9046438881682486   0.6282119777830519       0.16271650036125607
 0.13027892373965533  0.18887153454128924      0.3656173314780382
 0.8105579896722099   0.8689278012808201      0.613575621252296
 0.3501936207693894   0.41662154485059477      0.634150209365973
 0.5371570288242542   0.7182968669111338       0.3200262911743803
 0.9126028660250189   0.25564178492353906      0.23743297526797136
 0.5819814278543964   0.9943728715581492       0.4875339524077975

julia> A'
10×10 LinearMaps.WrappedMap{Float64} of
 0.6769273787529222    0.6765549649256377    0.5819814278543964
 0.036539631768852665  0.9624717119719399     0.9943728715581492
 0.4027902717113363    0.7026369092256841     0.7617166921327674
 0.7413107404966093    0.3203641222296265     0.6735049325510956
 0.41806755601877144   0.9765426747844308     0.004982227391467697
 0.6234799174891352    0.4282253038974375    0.012752198200326692
 0.6776227392879477    0.5539119205793519     0.5181151045294414
 0.21409932564096135   0.9807021706390484     0.13028886265083983
 0.9115007582179364    0.2871360638798117     0.8330562268795965
 0.9873418166811534    0.3575343347655404     0.4875339524077975

julia> transpose(B)
10×10 LinearMaps.WrappedMap{Float64} of
 0.8700744216295719   0.5444272069489469     0.45419955654642186
 0.458876698914481    0.30974679189517595     0.9829667847054768
 0.1941661929741807   0.8515496541558736      0.5210591620482088
 0.5049930060056573   0.9600731041579504      0.20258361820248338
 0.853244938937398    0.8770974066146568      0.3991378557794971
 0.9197564051076856   0.6721824083853565     0.3817926144866812
 0.24649887894680167  0.711909562164927       0.48691472563361726
 0.06738373935785602  0.4938423165045247      0.30750561352598305
 0.6377098655234006   0.6690778646165947      0.9561500428178002
 0.21599839571588952  0.20158982970939365     0.5560613057463222

julia> [A A; B B]
20×20 LinearMaps.BlockMap{Float64} with 4 block maps in 2 block rows
10×10 LinearMaps.WrappedMap{Float64} of
 0.6769273787529222   0.036539631768852665    0.9873418166811534
 0.6765549649256377   0.9624717119719399       0.3575343347655404
 0.31545830565381205  0.846611890984601        0.07509443800525162
 0.9046438881682486   0.6282119777830519       0.16271650036125607
 0.13027892373965533  0.18887153454128924      0.3656173314780382
 0.8105579896722099   0.8689278012808201      0.613575621252296
 0.3501936207693894   0.41662154485059477      0.634150209365973
 0.5371570288242542   0.7182968669111338       0.3200262911743803
 0.9126028660250189   0.25564178492353906      0.23743297526797136
 0.5819814278543964   0.9943728715581492       0.4875339524077975
10×10 LinearMaps.WrappedMap{Float64} of
 0.6769273787529222   0.036539631768852665    0.9873418166811534
 0.6765549649256377   0.9624717119719399       0.3575343347655404
 0.31545830565381205  0.846611890984601        0.07509443800525162
 0.9046438881682486   0.6282119777830519       0.16271650036125607
 0.13027892373965533  0.18887153454128924      0.3656173314780382
 0.8105579896722099   0.8689278012808201      0.613575621252296
 0.3501936207693894   0.41662154485059477      0.634150209365973
 0.5371570288242542   0.7182968669111338       0.3200262911743803
 0.9126028660250189   0.25564178492353906      0.23743297526797136
 0.5819814278543964   0.9943728715581492       0.4875339524077975
10×10 LinearMaps.WrappedMap{Float64} of
 0.8700744216295719     0.458876698914481      0.21599839571588952
 0.5444272069489469     0.30974679189517595     0.20158982970939365
 0.0039023841368437395  0.1743141153244383      0.5255090943219167
 0.6585137742811065     0.21529067784534073     0.09553647923800157
 0.6810489351017359     0.7726713554570053      0.88655004487403
 0.02948775918770319    0.804402117644776      0.8520117918594712
 0.981317366746389      0.42937017270368405     0.723298669979153
 0.05590009791874673    0.23243683344460941     0.7504218236329141
 0.6105003794996771     0.23372276641277856     0.5026331262236272
 0.45419955654642186    0.9829667847054768      0.5560613057463222
10×10 LinearMaps.WrappedMap{Float64} of
 0.8700744216295719     0.458876698914481      0.21599839571588952
 0.5444272069489469     0.30974679189517595     0.20158982970939365
 0.0039023841368437395  0.1743141153244383      0.5255090943219167
 0.6585137742811065     0.21529067784534073     0.09553647923800157
 0.6810489351017359     0.7726713554570053      0.88655004487403
 0.02948775918770319    0.804402117644776      0.8520117918594712
 0.981317366746389      0.42937017270368405     0.723298669979153
 0.05590009791874673    0.23243683344460941     0.7504218236329141
 0.6105003794996771     0.23372276641277856     0.5026331262236272
 0.45419955654642186    0.9829667847054768      0.5560613057463222

julia> N = 100
100

julia> function myft(v::AbstractVector)
         # not so fast fourier transform
         N = length(v)
         w = zeros(complex(eltype(v)), N)
         for k = 1:N
             kappa = (2*(k-1)/N)*pi
             for n = 1:N
                 w[k] += v[n]*exp(kappa*(n-1)*im)
             end
         end
         return w
       end
myft (generic function with 1 method)

julia> MyFT = LinearMap{ComplexF64}(myft, N)
100×100 LinearMaps.FunctionMap{Complex{Float64}}(myft; ismutating=false, issymmetric=false, ishermitian=false, isposdef=false)

julia> MyFT'
100×100 LinearMaps.AdjointMap{Complex{Float64}} of
(myft; ismutating=false, issymmetric=false, ishermitian=false, isposdef=false)

julia> J = LinearMap(3I, 100)
100×100 LinearMaps.UniformScalingMap{Int64}
 3

julia> 2MyFT + J
100×100 LinearMaps.LinearCombination{Complex{Float64}} with 2 maps:
100×100 LinearMaps.CompositeMap{Complex{Float64}} with 2 maps:
100×100 LinearMaps.FunctionMap{Complex{Float64}}(myft; ismutating=false, issymmetric=false, ishermitian=false, isposdef=false)
100×100 LinearMaps.UniformScalingMap{Int64}
 2
100×100 LinearMaps.UniformScalingMap{Int64}
 3

I would like to give an idea of the hierarchy by adding indention to lower-order maps, but I don't know yet how to do that (across several lines, with potentially increasing width).

Of course, the details are up for discussion, now that we have something to start from. Needless to say that I can't help but finding it beautiful. 🤣

@codecov
Copy link

codecov bot commented Mar 28, 2020

Codecov Report

❗ No coverage uploaded for pull request base (master@2d8dcdf). Click here to learn what that means.
The diff coverage is 88.88%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master      #87   +/-   ##
=========================================
  Coverage          ?   99.08%           
=========================================
  Files             ?       13           
  Lines             ?      988           
  Branches          ?        0           
=========================================
  Hits              ?      979           
  Misses            ?        9           
  Partials          ?        0           
Impacted Files Coverage Δ
src/blockmap.jl 99.53% <66.66%> (ø)
src/show.jl 87.93% <87.93%> (ø)
src/LinearMaps.jl 98.82% <100.00%> (ø)
src/composition.jl 100.00% <100.00%> (ø)
src/functionmap.jl 100.00% <100.00%> (ø)
src/kronecker.jl 100.00% <100.00%> (ø)
src/linearcombination.jl 100.00% <100.00%> (ø)
src/scaledmap.jl 100.00% <100.00%> (ø)
src/transpose.jl 100.00% <100.00%> (ø)
src/uniformscalingmap.jl 100.00% <100.00%> (ø)
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2d8dcdf...c1355ee. Read the comment docs.

@coveralls
Copy link

coveralls commented Mar 28, 2020

Coverage Status

Coverage decreased (-4.4%) to 92.691% when pulling 020372e on dk/show into 47cba39 on master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-5.3%) to 91.835% when pulling 020372e on dk/show into 47cba39 on master.

@dkarrasch
Copy link
Member Author

Alright, this needs certainly tests, but meanwhile I'd like to solicit some feedback/opinions/suggestions. So please, be invited to checkout this branch and test it in your current workflow.

I see two "issues" here: (a) how to display matrices nicely; I'm not very well familiar with matrix plotting, but currently sparse matrices are displayed like dense ones; and (b) how to represent the hierarchy; ideally, I'd like to shift display blocks by two spaces or so, but I have no idea how to shift the matrix display, for instance.

@Jutho
Copy link
Collaborator

Jutho commented Jun 18, 2020

I also have little experience with print and show and IOContext and all the things you need to get nice printing, and find this one of the most confusing or worst documented parts of Julia.

My first suggestion for now would be to put the scalar of UniformScalingMap on the same line, so that it takes a single line like the FunctionMap

This was referenced Aug 5, 2020
@dkarrasch
Copy link
Member Author

As another suggestion, I have omitted printing of matrices. After all, one could print matrices by explicitly asking for A.maps[1] if one really wants to. So, if we only print the type of the matrix, then this is what we get:

julia> A = LinearMap(rand(10, 10))
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}

julia> B = LinearMap(rand(10, 10))
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}

julia> A + B
10×10 LinearMaps.LinearCombination{Float64} with 2 maps:
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}

julia> A*B
10×10 LinearMaps.CompositeMap{Float64} with 2 maps:
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}

julia> A'
10×10 LinearMaps.WrappedMap{Float64} of
Adjoint{Float64,Array{Float64,2}}

julia> transpose(B)
10×10 LinearMaps.WrappedMap{Float64} of
Transpose{Float64,Array{Float64,2}}

julia> [A A; B B]
20×20 LinearMaps.BlockMap{Float64} with 4 block maps in 2 block rows
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}
10×10 LinearMaps.WrappedMap{Float64} of
Array{Float64,2}

julia> N = 100
100

julia> function myft(v::AbstractVector)
                # not so fast fourier transform
                N = length(v)
                w = zeros(complex(eltype(v)), N)
                for k = 1:N
                    kappa = (2*(k-1)/N)*pi
                    for n = 1:N
                        w[k] += v[n]*exp(kappa*(n-1)*im)
                    end
                end
                return w
              end
myft (generic function with 1 method)

julia> MyFT = LinearMap{ComplexF64}(myft, N)
100×100 LinearMaps.FunctionMap{Complex{Float64}}(myft; ismutating=false, issymmetric=false, ishermitian=false, isposdef=false)

julia> MyFT'
100×100 LinearMaps.AdjointMap{Complex{Float64}} of
100×100 LinearMaps.FunctionMap{Complex{Float64}}(myft; ismutating=false, issymmetric=false, ishermitian=false, isposdef=false)

julia> J = LinearMap(3I, 100)
100×100 LinearMaps.UniformScalingMap{Int64} with scaling factor: 3

julia> 2MyFT + J
100×100 LinearMaps.LinearCombination{Complex{Float64}} with 2 maps:
100×100 LinearMaps.ScaledMap{Complex{Float64}} with scale: 2 of
100×100 LinearMaps.FunctionMap{Complex{Float64}}(myft; ismutating=false, issymmetric=false, ishermitian=false, isposdef=false)
100×100 LinearMaps.UniformScalingMap{Int64} with scaling factor: 3

It would be nice if one could have indentation, but this could be tackled in the future. How do you like this everyone?

@dkarrasch
Copy link
Member Author

I believe this is an improvement in any case. The main question is whether we want to display matrices or not. I don't plan to work on any other aspect (like indention) soon, so it would be great to receive a few votes. Maybe @chriscoey or @jagot? Personally, I have a slight preference towards not displaying them, but if anyone has a strong preference and a good reason, that would be helpful to know.

@dkarrasch dkarrasch mentioned this pull request Oct 6, 2020
3 tasks
@jagot
Copy link

jagot commented Oct 7, 2020

I think it is fine not to print them, you can always investigate them manually by WrappedMap.lmap if you're really curious.

@dkarrasch
Copy link
Member Author

Maybe we should provide a get_map function, to go down the hierarchy, independently of the concrete map type. Sometimes, we have an :lmap field, sometimes :maps, some maps have a lambda etc. So the user wouldn't necessarily need to know the name of the "map field" at hand.

@dkarrasch
Copy link
Member Author

Yes, that's cool.

julia> get_map(LinearMap(rand(2,3)))
2×3 Array{Float64,2}:
 0.765154  0.334224  0.702233
 0.887921  0.189611  0.18073

This is hard to use in an automated fashion, because it may return very different types in general, but for interactive usage and quick exploration, that should be helpful.

@dkarrasch
Copy link
Member Author

Actually, let's call it parent... 😃

help?> parent
search: parent parentmodule parentindices

  parent(A)

  Return the underlying "parent array”. This parent array of objects of types SubArray, ReshapedArray or LinearAlgebra.Transpose is what was passed as an
  argument to view, reshape, transpose, etc. during object creation. If the input is not a wrapped object, return the input itself.

@dkarrasch dkarrasch merged commit 630d0a0 into master Oct 7, 2020
@dkarrasch dkarrasch deleted the dk/show branch October 7, 2020 13:59
@dkarrasch dkarrasch changed the title Introduce specific show methods Introduce specific show methods, add Base.parent overload Oct 7, 2020
@JeffFessler
Copy link
Member

I'd like to add my vote of support for not showing the matrices and keeping the default show to be concise, which I sense is the direction going here. I don't have a MWE on hand, but there were times in the past where debugging was hard for me because of the verbosity of the output. Thanks for the efforts 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.

5 participants