Skip to content

Commit 97534b0

Browse files
committed
Prep for separation of AbstractMatrix & AbstractQ
1 parent 40c6dbc commit 97534b0

File tree

5 files changed

+56
-42
lines changed

5 files changed

+56
-42
lines changed

src/LinearMaps.jl

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
module LinearMaps
22

3-
export LinearMap
3+
export LinearMap, FunctionMap, FillMap, InverseMap
44
export , squarekron, kronsum, , sumkronsum, khatrirao, facesplitting
5-
export FillMap
6-
export InverseMap
75

86
using LinearAlgebra
7+
using LinearAlgebra: AbstractQ
98
import LinearAlgebra: mul!
109
using SparseArrays
1110

@@ -18,8 +17,9 @@ using Base: require_one_based_indexing
1817

1918
abstract type LinearMap{T} end
2019

21-
const MapOrVecOrMat{T} = Union{LinearMap{T}, AbstractVecOrMat{T}}
22-
const MapOrMatrix{T} = Union{LinearMap{T}, AbstractMatrix{T}}
20+
const AbstractVecOrMatOrQ{T} = Union{AbstractVecOrMat{T}, AbstractQ{T}}
21+
const MapOrVecOrMat{T} = Union{LinearMap{T}, AbstractVecOrMatOrQ{T}}
22+
const MapOrMatrix{T} = Union{LinearMap{T}, AbstractMatrix{T}, AbstractQ{T}}
2323
const TransposeAbsVecOrMat{T} = Transpose{T,<:AbstractVecOrMat}
2424
const RealOrComplex = Union{Real, Complex}
2525

@@ -31,7 +31,7 @@ Base.eltype(::LinearMap{T}) where {T} = T
3131

3232
# conversion to LinearMap
3333
Base.convert(::Type{LinearMap}, A::LinearMap) = A
34-
Base.convert(::Type{LinearMap}, A::AbstractVecOrMat) = LinearMap(A)
34+
Base.convert(::Type{LinearMap}, A::AbstractVecOrMatOrQ) = LinearMap(A)
3535

3636
convert_to_lmaps() = ()
3737
convert_to_lmaps(A) = (convert(LinearMap, A),)
@@ -49,6 +49,7 @@ MulStyle(::FiveArg, ::ThreeArg) = ThreeArg()
4949
MulStyle(::ThreeArg, ::ThreeArg) = ThreeArg()
5050
MulStyle(::LinearMap) = ThreeArg() # default
5151
MulStyle(::AbstractVecOrMat) = FiveArg()
52+
MulStyle(::AbstractQ) = ThreeArg()
5253
MulStyle(A::LinearMap, As::LinearMap...) = MulStyle(MulStyle(A), MulStyle(As...))
5354

5455
Base.isreal(A::LinearMap) = eltype(A) <: Real
@@ -337,11 +338,11 @@ end
337338
include("transpose.jl") # transposing linear maps
338339
include("wrappedmap.jl") # wrap a matrix of linear map in a new type, thereby allowing to alter its properties
339340
include("left.jl") # left multiplication by a matrix/transpose or adjoint vector
341+
include("functionmap.jl") # using a function as linear map
340342
include("uniformscalingmap.jl") # the uniform scaling map, to be able to make linear combinations of LinearMap objects and multiples of I
341343
include("linearcombination.jl") # defining linear combinations of linear maps
342344
include("scaledmap.jl") # multiply by a (real or complex) scalar
343345
include("composition.jl") # composition of linear maps
344-
include("functionmap.jl") # using a function as linear map
345346
include("blockmap.jl") # block linear maps
346347
include("kronecker.jl") # Kronecker product of linear maps
347348
include("khatrirao.jl") # Khatri-Rao and face-splitting products
@@ -355,34 +356,36 @@ include("chainrules.jl") # AD rules through ChainRulesCore
355356

356357
"""
357358
LinearMap(A::LinearMap; kwargs...)::WrappedMap
358-
LinearMap(A::AbstractVecOrMat; kwargs...)::WrappedMap
359+
LinearMap(A::AbstractVecOrMatOrQ; kwargs...)::WrappedMap
359360
LinearMap(J::UniformScaling, M::Int)::UniformScalingMap
360361
LinearMap{T=Float64}(f, [fc,], M::Int, N::Int = M; kwargs...)::FunctionMap
361362
LinearMap(A::MapOrVecOrMat, dims::Dims{2}, index::NTuple{2, AbstractVector{Int}})::EmbeddedMap
362363
LinearMap(A::MapOrVecOrMat, dims::Dims{2}; offset::Dims{2})::EmbeddedMap
363364
364365
Construct a linear map object, either
365366
366-
1. from an existing `LinearMap` or `AbstractVecOrMat` `A`, with the purpose of redefining
367-
its properties via the keyword arguments `kwargs`;
367+
1. from an existing `LinearMap` or `AbstractVecOrMat`/`AbstractQ` `A`, with the purpose of
368+
redefining its properties via the keyword arguments `kwargs`, see below;
368369
2. a `UniformScaling` object `J` with specified (square) dimension `M`;
369370
3. from a function or callable object `f`;
370-
4. from an existing `LinearMap` or `AbstractVecOrMat` `A`, embedded in a larger zero map.
371+
4. from an existing `LinearMap` or `AbstractVecOrMat`/`AbstractQ` `A`, embedded in a larger
372+
zero map.
371373
372374
In the case of item 3, one also needs to specify the size of the equivalent matrix
373-
representation `(M, N)`, i.e., for functions `f` acting
374-
on length `N` vectors and producing length `M` vectors (with default value `N=M`).
375-
Preferably, also the `eltype` `T` of the corresponding matrix representation needs to be
376-
specified, i.e., whether the action of `f` on a vector will be similar to, e.g., multiplying
377-
by numbers of type `T`. If not specified, the devault value `T=Float64` will be assumed.
378-
Optionally, a corresponding function `fc` can be specified that implements the adjoint
379-
(=transpose in the real case) of `f`.
380-
381-
The keyword arguments and their default values for the function-based constructor are:
382-
* `issymmetric::Bool = false` : whether `A` or `f` act as a symmetric matrix
383-
* `ishermitian::Bool = issymmetric & T<:Real` : whether `A` or `f` act as a Hermitian
384-
matrix
385-
* `isposdef::Bool = false` : whether `A` or `f` act as a positive definite matrix.
375+
representation `(M, N)`, i.e., for functions `f` acting on length `N` vectors and producing
376+
length `M` vectors (with default value `N=M`). Preferably, also the `eltype` `T` of the
377+
corresponding matrix representation needs to be specified, i.e., whether the action of `f`
378+
on a vector will be similar to, e.g., multiplying by numbers of type `T`. If not specified,
379+
the devault value `T=Float64` will be assumed. Optionally, a corresponding function `fc`
380+
can be specified that implements the adjoint (or transpose in the real case) of `f`.
381+
382+
The keyword arguments and their default values are:
383+
384+
* `issymmetric::Bool = false` : whether `A` or `f` act as a symmetric matrix
385+
* `ishermitian::Bool = issymmetric & T<:Real` : whether `A` or `f` act as a Hermitian
386+
matrix
387+
* `isposdef::Bool = false` : whether `A` or `f` act as a positive definite matrix.
388+
386389
For existing linear maps or matrices `A`, the default values will be taken by calling
387390
internal functions `_issymmetric`, `_ishermitian` and `_isposdef` on the existing object `A`.
388391
These in turn dispatch to (overloads of) `LinearAlgebra`'s `issymmetric`, `ishermitian`,
@@ -391,11 +394,11 @@ known at compile time as for certain structured matrices, but return `false` for
391394
`AbstractMatrix` types.
392395
393396
For the function-based constructor, there is one more keyword argument:
394-
* `ismutating::Bool` : flags whether the function acts as a mutating matrix multiplication
395-
`f(y,x)` where the result vector `y` is the first argument (in case of `true`),
396-
or as a normal matrix multiplication that is called as `y=f(x)` (in case of `false`).
397-
The default value is guessed by looking at the number of arguments of the first
398-
occurrence of `f` in the method table.
397+
* `ismutating::Bool` : flags whether the function acts as a mutating matrix multiplication
398+
`f(y,x)` where the result vector `y` is the first argument (in case of `true`),
399+
or as a normal matrix multiplication that is called as `y=f(x)` (in case of `false`).
400+
The default value is guessed by looking at the number of arguments of the first
401+
occurrence of `f` in the method table.
399402
400403
For the `EmbeddedMap` constructors, `dims` specifies the total dimensions of the map. The
401404
`index` argument specifies two collections of indices `inds1` and `inds2`, such that for

src/blockmap.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Base.size(A::BlockMap) = (last(last(A.rowranges)), last(last(A.colranges)))
6363
# hcat
6464
############
6565
"""
66-
hcat(As::Union{LinearMap,UniformScaling,AbstractVecOrMat}...)::BlockMap
66+
hcat(As::Union{LinearMap,UniformScaling,AbstractVecOrMatOrQ}...)::BlockMap
6767
6868
Construct a (lazy) representation of the horizontal concatenation of the arguments.
6969
All arguments are promoted to `LinearMap`s automatically.
@@ -81,7 +81,7 @@ julia> L * ones(Int, 6)
8181
6
8282
```
8383
"""
84-
function Base.hcat(As::Union{LinearMap, UniformScaling, AbstractVecOrMat}...)
84+
function Base.hcat(As::Union{LinearMap, UniformScaling, AbstractVecOrMatOrQ}...)
8585
T = promote_type(map(eltype, As)...)
8686
nbc = length(As)
8787

@@ -98,7 +98,7 @@ end
9898
# vcat
9999
############
100100
"""
101-
vcat(As::Union{LinearMap,UniformScaling,AbstractVecOrMat}...)::BlockMap
101+
vcat(As::Union{LinearMap,UniformScaling,AbstractVecOrMatOrQ}...)::BlockMap
102102
103103
Construct a (lazy) representation of the vertical concatenation of the arguments.
104104
All arguments are promoted to `LinearMap`s automatically.
@@ -119,7 +119,7 @@ julia> L * ones(Int, 3)
119119
3
120120
```
121121
"""
122-
function Base.vcat(As::Union{LinearMap,UniformScaling,AbstractVecOrMat}...)
122+
function Base.vcat(As::Union{LinearMap,UniformScaling,AbstractVecOrMatOrQ}...)
123123
T = promote_type(map(eltype, As)...)
124124
nbr = length(As)
125125

@@ -137,7 +137,7 @@ end
137137
# hvcat
138138
############
139139
"""
140-
hvcat(rows::Tuple{Vararg{Int}}, As::Union{LinearMap,UniformScaling,AbstractVecOrMat}...)::BlockMap
140+
hvcat(rows::Tuple{Vararg{Int}}, As::Union{LinearMap,UniformScaling,AbstractVecOrMatOrQ}...)::BlockMap
141141
142142
Construct a (lazy) representation of the horizontal-vertical concatenation of the arguments.
143143
The first argument specifies the number of arguments to concatenate in each block row.
@@ -165,7 +165,7 @@ julia> L * ones(Int, 6)
165165
Base.hvcat
166166

167167
function Base.hvcat(rows::Tuple{Vararg{Int}},
168-
As::Union{LinearMap, UniformScaling, AbstractVecOrMat}...)
168+
As::Union{LinearMap, UniformScaling, AbstractVecOrMatOrQ}...)
169169
nr = length(rows)
170170
T = promote_type(map(eltype, As)...)
171171
sum(rows) == length(As) ||
@@ -322,7 +322,7 @@ end
322322
# provide one global intermediate storage vector if necessary
323323
__blockmul!(::FiveArg, y, A, x::AbstractVecOrMat, α, β) = ___blockmul!(y, A, x, α, β, nothing)
324324
__blockmul!(::ThreeArg, y, A, x::AbstractVecOrMat, α, β) = ___blockmul!(y, A, x, α, β, similar(y))
325-
function ___blockmul!(y, A, x::AbstractVecOrMat, α, β, ::Nothing)
325+
function ___blockmul!(y, A, x, α, β, ::Nothing)
326326
maps, rows, yinds, xinds = A.maps, A.rows, A.rowranges, A.colranges
327327
mapind = 0
328328
for (row, yi) in zip(rows, yinds)
@@ -336,7 +336,7 @@ function ___blockmul!(y, A, x::AbstractVecOrMat, α, β, ::Nothing)
336336
end
337337
return y
338338
end
339-
function ___blockmul!(y, A, x::AbstractVecOrMat, α, β, z)
339+
function ___blockmul!(y, A, x, α, β, z)
340340
maps, rows, yinds, xinds = A.maps, A.rows, A.rowranges, A.colranges
341341
mapind = 0
342342
for (row, yi) in zip(rows, yinds)
@@ -497,7 +497,7 @@ BlockDiagonalMap(maps::LinearMap...) =
497497
# since the below methods are more specific than the Base method,
498498
# they would redefine Base/SparseArrays behavior
499499
for k in 1:8 # is 8 sufficient?
500-
Is = ntuple(n->:($(Symbol(:A, n))::AbstractVecOrMat), Val(k-1))
500+
Is = ntuple(n->:($(Symbol(:A, n))::AbstractVecOrMatOrQ), Val(k-1))
501501
# yields (:A1, :A2, :A3, ..., :A(k-1))
502502
L = :($(Symbol(:A, k))::LinearMap)
503503
# yields :Ak
@@ -524,7 +524,7 @@ for k in 1:8 # is 8 sufficient?
524524
end
525525

526526
"""
527-
blockdiag(As::Union{LinearMap,AbstractVecOrMat}...)::BlockDiagonalMap
527+
blockdiag(As::Union{LinearMap,AbstractVecOrMatOrQ}...)::BlockDiagonalMap
528528
529529
Construct a (lazy) representation of the diagonal concatenation of the arguments.
530530
To avoid fallback to the generic `SparseArrays.blockdiag`, there must be a `LinearMap`
@@ -533,7 +533,7 @@ object among the first 8 arguments.
533533
SparseArrays.blockdiag
534534

535535
"""
536-
cat(As::Union{LinearMap,AbstractVecOrMat}...; dims=(1,2))::BlockDiagonalMap
536+
cat(As::Union{LinearMap,AbstractVecOrMatOrQ}...; dims=(1,2))::BlockDiagonalMap
537537
538538
Construct a (lazy) representation of the diagonal concatenation of the arguments.
539539
To avoid fallback to the generic `Base.cat`, there must be a `LinearMap`

src/show.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ end
88
Base.show(io::IO, A::LinearMap) = print(io, map_show(io, A, 0))
99

1010
map_show(io::IO, A::LinearMap, i) = ' '^i * map_summary(A) * _show(io, A, i)
11-
map_show(io::IO, A::AbstractVecOrMat, i) = ' '^i * summary(A)
11+
map_show(io::IO, A::AbstractVecOrMatOrQ, i) = ' '^i * summary(A)
1212
_show(io::IO, ::LinearMap, _) = ""
1313
function _show(io::IO, A::FunctionMap{T,F,Nothing}, _) where {T,F}
1414
"($(A.f); ismutating=$(A._ismutating), issymmetric=$(A._issymmetric), ishermitian=$(A._ishermitian), isposdef=$(A._isposdef))"

src/wrappedmap.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,24 @@ WrappedMap(lmap::MapOrVecOrMat{T}; kwargs...) where {T} = WrappedMap{T}(lmap; kw
2323

2424
# cheap property checks (usually by type)
2525
_issymmetric(A::AbstractMatrix) = false
26+
_issymmetric(A::AbstractQ) = false
2627
_issymmetric(A::AbstractSparseMatrix) = issymmetric(A)
2728
_issymmetric(A::LinearMap) = issymmetric(A)
2829
_issymmetric(A::LinearAlgebra.RealHermSymComplexSym) = issymmetric(A)
2930
_issymmetric(A::Union{Bidiagonal,Diagonal,SymTridiagonal,Tridiagonal}) = issymmetric(A)
3031

3132
_ishermitian(A::AbstractMatrix) = false
33+
_ishermitian(A::AbstractQ) = false
3234
_ishermitian(A::AbstractSparseMatrix) = ishermitian(A)
3335
_ishermitian(A::LinearMap) = ishermitian(A)
3436
_ishermitian(A::LinearAlgebra.RealHermSymComplexHerm) = ishermitian(A)
3537
_ishermitian(A::Union{Bidiagonal,Diagonal,SymTridiagonal,Tridiagonal}) = ishermitian(A)
3638

3739
_isposdef(A::AbstractMatrix) = false
40+
_isposdef(A::AbstractQ) = false
3841
_isposdef(A::LinearMap) = isposdef(A)
3942

40-
const VecOrMatMap{T} = WrappedMap{T,<:AbstractVecOrMat}
43+
const VecOrMatMap{T} = WrappedMap{T,<:AbstractVecOrMatOrQ}
4144

4245
MulStyle(A::VecOrMatMap) = MulStyle(A.lmap)
4346

test/wrappedmap.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,12 @@ using Test, LinearMaps, LinearAlgebra
113113
@test issymmetric(LinearMap(M)) == issymmetric(M)
114114
@test ishermitian(LinearMap(M)) == ishermitian(M)
115115
end
116+
117+
# AbstractQ
118+
Q = qr(rand(10, 20)).Q
119+
Qmap = @inferred LinearMap(Q)
120+
@test size(Qmap) == (10, 10)
121+
@test !issymmetric(Qmap)
122+
@test !ishermitian(Qmap)
123+
@test !isposdef(Qmap)
116124
end

0 commit comments

Comments
 (0)