Skip to content

Commit 25f0535

Browse files
committed
add the code
1 parent af9a627 commit 25f0535

File tree

7 files changed

+148
-94
lines changed

7 files changed

+148
-94
lines changed

src/LinearMaps.jl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ const MapOrVecOrMat{T} = Union{LinearMap{T}, AbstractVecOrMat{T}}
1616
const MapOrMatrix{T} = Union{LinearMap{T}, AbstractMatrix{T}}
1717
const RealOrComplex = Union{Real, Complex}
1818

19+
const LinearMapTuple = Tuple{Vararg{LinearMap}}
20+
const LinearMapVector = AbstractVector{<:LinearMap}
21+
const LinearMapTupleOrVector = Union{LinearMapTuple,LinearMapVector}
22+
1923
Base.eltype(::LinearMap{T}) where {T} = T
2024

2125
abstract type MulStyle end
@@ -69,6 +73,21 @@ convert_to_lmaps(A) = (convert_to_lmaps_(A),)
6973
@inline convert_to_lmaps(A, B, Cs...) =
7074
(convert_to_lmaps_(A), convert_to_lmaps_(B), convert_to_lmaps(Cs...)...)
7175

76+
_front(As::Tuple) = Base.front(As)
77+
_front(As::AbstractVector) = @inbounds @views As[1:end-1]
78+
_tail(As::Tuple) = Base.tail(As)
79+
_tail(As::AbstractVector) = @inbounds @views As[2:end]
80+
81+
_combine(A::LinearMap, B::LinearMap) = tuple(A, B)
82+
_combine(A::LinearMap, Bs::LinearMapTuple) = tuple(A, Bs...)
83+
_combine(As::LinearMapTuple, B::LinearMap) = tuple(As..., B)
84+
_combine(As::LinearMapTuple, Bs::LinearMapTuple) = tuple(As..., Bs...)
85+
_combine(A::LinearMap, Bs::LinearMapVector) = vcat(A, Bs...)
86+
_combine(As::LinearMapVector, B::LinearMap) = vcat(As..., B)
87+
_combine(As::LinearMapVector, Bs::LinearMapTuple) = vcat(As..., Bs...)
88+
_combine(As::LinearMapTuple, Bs::LinearMapVector) = vcat(As..., Bs...)
89+
_combine(As::LinearMapVector, Bs::LinearMapVector) = vcat(As..., Bs...)
90+
7291
# The (internal) multiplication logic is as follows:
7392
# - `*(A, x)` calls `mul!(y, A, x)` for appropriately-sized y
7493
# - `mul!` checks consistency of the sizes, and calls `_unsafe_mul!`,
@@ -233,8 +252,6 @@ function _unsafe_mul!(y::AbstractMatrix, A::LinearMap, x::AbstractMatrix, α, β
233252
return _generic_mapmat_mul!(y, A, x, α, β)
234253
end
235254

236-
const LinearMapTuple = Tuple{Vararg{LinearMap}}
237-
238255
include("left.jl") # left multiplication by a transpose or adjoint vector
239256
include("transpose.jl") # transposing linear maps
240257
include("wrappedmap.jl") # wrap a matrix of linear map in a new type, thereby allowing to alter its properties

src/blockmap.jl

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
struct BlockMap{T,
2-
As<:LinearMapTuple,
2+
As<:LinearMapTupleOrVector,
33
Rs<:Tuple{Vararg{Int}},
4-
Rranges<:Tuple{Vararg{UnitRange{Int}}},
5-
Cranges<:Tuple{Vararg{UnitRange{Int}}}} <: LinearMap{T}
4+
Rranges<:Vector{UnitRange{Int}},
5+
Cranges<:Vector{UnitRange{Int}}} <: LinearMap{T}
66
maps::As
77
rows::Rs
88
rowranges::Rranges
99
colranges::Cranges
1010
function BlockMap{T,As,Rs}(maps::As, rows::Rs) where
11-
{T, As<:LinearMapTuple, Rs<:Tuple{Vararg{Int}}}
11+
{T, As<:LinearMapTupleOrVector, Rs<:Tuple{Vararg{Int}}}
1212
for TA in Base.Generator(eltype, maps)
1313
promote_type(T, TA) == T ||
1414
error("eltype $TA cannot be promoted to $T in BlockMap constructor")
@@ -19,15 +19,17 @@ struct BlockMap{T,
1919
end
2020
end
2121

22-
BlockMap{T}(maps::As, rows::Rs) where {T, As<:LinearMapTuple, Rs} =
22+
BlockMap{T}(maps::As, rows::Rs) where {T, As<:LinearMapTupleOrVector, Rs} =
2323
BlockMap{T, As, Rs}(maps, rows)
24+
BlockMap(maps::As, rows::Rs) where {As<:LinearMapTupleOrVector, Rs} =
25+
BlockMap{promote_type(map(eltype, maps)...), As, Rs}(maps, rows)
2426

2527
MulStyle(A::BlockMap) = MulStyle(A.maps...)
2628

27-
function _getranges(maps, dim, inds=ntuple(identity, Val(length(maps))))
28-
sizes = map(i -> size(maps[i], dim)::Int, inds)
29-
ends = cumsum(sizes)
30-
starts = (1, (1 .+ Base.front(ends))...)
29+
function _getranges(maps, dim, inds=1:length(maps))
30+
ends = map(i -> size(maps[i], dim)::Int, inds)
31+
cumsum!(ends, ends)
32+
starts = vcat(1, 1 .+ @views ends[1:end-1])
3133
return UnitRange.(starts, ends)
3234
end
3335

@@ -40,14 +42,15 @@ block linear map obtained from `hvcat(rows, maps...)`.
4042
"""
4143
function rowcolranges(maps, rows)
4244
# find indices of the row-wise first maps
43-
firstmapinds = cumsum((1, Base.front(rows)...))
45+
firstmapinds = vcat(1, Base.front(rows)...)
46+
cumsum!(firstmapinds, firstmapinds)
4447
# compute rowranges from first dimension of the row-wise first maps
4548
rowranges = _getranges(maps, 1, firstmapinds)
4649

4750
# compute ranges from second dimension as if all in one row
4851
temp = _getranges(maps, 2)
4952
# introduce "line breaks"
50-
colranges = ntuple(Val(length(maps))) do i
53+
colranges = map(1:length(maps)) do i
5154
# for each map find the index of the respective row-wise first map
5255
# something-trick just to assure the compiler that the index is an Int
5356
@inbounds firstmapind = firstmapinds[something(findlast(<=(i), firstmapinds), 1)]
@@ -277,7 +280,7 @@ end
277280
############
278281

279282
Base.:(==)(A::BlockMap, B::BlockMap) =
280-
(eltype(A) == eltype(B) && A.maps == B.maps && A.rows == B.rows)
283+
(eltype(A) == eltype(B) && all(A.maps .== B.maps) && all(A.rows .== B.rows))
281284

282285
############
283286
# multiplication helper functions
@@ -350,9 +353,9 @@ function _transblockmul!(y, A::BlockMap, x, α, β, transform)
350353
# subsequent block rows of A (block columns of A'),
351354
# add results to corresponding parts of y
352355
# TODO: think about multithreading
353-
for (row, xi) in zip(Base.tail(rows), Base.tail(xinds))
354-
xrow = selectdim(x, 1, xi)
355-
for _ in 1:row
356+
@inbounds for i in 2:length(rows)
357+
xrow = selectdim(x, 1, xinds[i])
358+
for _ in 1:rows[i]
356359
mapind +=1
357360
yrow = selectdim(y, 1, yinds[mapind])
358361
_unsafe_mul!(yrow, transform(maps[mapind]), xrow, α, true)
@@ -397,12 +400,12 @@ end
397400
# BlockDiagonalMap
398401
############
399402
struct BlockDiagonalMap{T,
400-
As<:LinearMapTuple,
401-
Ranges<:Tuple{Vararg{UnitRange{Int}}}} <: LinearMap{T}
403+
As<:LinearMapTupleOrVector,
404+
Ranges<:Vector{UnitRange{Int}}} <: LinearMap{T}
402405
maps::As
403406
rowranges::Ranges
404407
colranges::Ranges
405-
function BlockDiagonalMap{T, As}(maps::As) where {T, As<:LinearMapTuple}
408+
function BlockDiagonalMap{T, As}(maps::As) where {T, As<:LinearMapTupleOrVector}
406409
for TA in Base.Generator(eltype, maps)
407410
promote_type(T, TA) == T ||
408411
error("eltype $TA cannot be promoted to $T in BlockDiagonalMap constructor")
@@ -413,7 +416,7 @@ struct BlockDiagonalMap{T,
413416
end
414417
end
415418

416-
BlockDiagonalMap{T}(maps::As) where {T, As<:LinearMapTuple} =
419+
BlockDiagonalMap{T}(maps::As) where {T, As<:LinearMapTupleOrVector} =
417420
BlockDiagonalMap{T,As}(maps)
418421
BlockDiagonalMap(maps::LinearMap...) =
419422
BlockDiagonalMap{promote_type(map(eltype, maps)...)}(maps)
@@ -478,7 +481,7 @@ LinearAlgebra.transpose(A::BlockDiagonalMap{T}) where {T} =
478481
BlockDiagonalMap{T}(map(transpose, A.maps))
479482

480483
Base.:(==)(A::BlockDiagonalMap, B::BlockDiagonalMap) =
481-
(eltype(A) == eltype(B) && A.maps == B.maps)
484+
(eltype(A) == eltype(B) && all(A.maps .== B.maps))
482485

483486
for (In, Out) in ((AbstractVector, AbstractVecOrMat), (AbstractMatrix, AbstractMatrix))
484487
@eval begin
@@ -496,7 +499,7 @@ end
496499
function _blockscaling!(y, A::BlockDiagonalMap, x, α, β)
497500
maps, yinds, xinds = A.maps, A.rowranges, A.colranges
498501
# TODO: think about multi-threading here
499-
@inbounds for i in eachindex(yinds, maps, xinds)
502+
@inbounds for i in 1:length(maps)
500503
_unsafe_mul!(selectdim(y, 1, yinds[i]), maps[i], selectdim(x, 1, xinds[i]), α, β)
501504
end
502505
return y

src/composition.jl

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
struct CompositeMap{T, As<:LinearMapTuple} <: LinearMap{T}
1+
struct CompositeMap{T, As<:LinearMapTupleOrVector} <: LinearMap{T}
22
maps::As # stored in order of application to vector
33
function CompositeMap{T, As}(maps::As) where {T, As}
44
N = length(maps)
@@ -12,7 +12,7 @@ struct CompositeMap{T, As<:LinearMapTuple} <: LinearMap{T}
1212
new{T, As}(maps)
1313
end
1414
end
15-
CompositeMap{T}(maps::As) where {T, As<:LinearMapTuple} = CompositeMap{T, As}(maps)
15+
CompositeMap{T}(maps::As) where {T, As<:LinearMapTupleOrVector} = CompositeMap{T, As}(maps)
1616

1717
# basic methods
1818
Base.size(A::CompositeMap) = (size(A.maps[end], 1), size(A.maps[1], 2))
@@ -26,8 +26,18 @@ for (f, _f, g) in ((:issymmetric, :_issymmetric, :transpose),
2626
LinearAlgebra.$f(A::CompositeMap) = $_f(A.maps)
2727
$_f(maps::Tuple{}) = true
2828
$_f(maps::Tuple{<:LinearMap}) = $f(maps[1])
29-
$_f(maps::Tuple{Vararg{LinearMap}}) =
29+
$_f(maps::LinearMapTuple) =
3030
maps[end] == $g(maps[1]) && $_f(Base.front(Base.tail(maps)))
31+
function $_f(maps::LinearMapVector)
32+
n = length(maps)
33+
if n == 0
34+
return true
35+
elseif n == 1
36+
return $f(maps[1])
37+
else
38+
return maps[end] == $g(maps[1]) && $_f(maps[2:end-1])
39+
end
40+
end
3141
# since the introduction of ScaledMap, the following cases cannot occur
3242
# function $_f(maps::Tuple{Vararg{LinearMap}}) # length(maps) >= 2
3343
# if maps[1] isa UniformScalingMap{<:RealOrComplex}
@@ -45,23 +55,34 @@ end
4555
LinearAlgebra.isposdef(A::CompositeMap) = _isposdef(A.maps)
4656
_isposdef(maps::Tuple{}) = true # empty product is equivalent to "I" which is pos. def.
4757
_isposdef(maps::Tuple{<:LinearMap}) = isposdef(maps[1])
48-
function _isposdef(maps::Tuple{Vararg{LinearMap}})
58+
function _isposdef(maps::LinearMapTuple)
4959
(maps[end] == adjoint(maps[1]) || maps[end] == maps[1]) &&
50-
isposdef(maps[1]) && _isposdef(Base.front(Base.tail(maps)))
60+
isposdef(maps[1]) && _isposdef(Base.front(Base.tail(maps)))
61+
end
62+
function _isposdef(maps::LinearMapVector)
63+
n = length(maps)
64+
if n == 0
65+
return true
66+
elseif n == 1
67+
return isposdef(maps[1])
68+
else
69+
return (maps[end] == adjoint(maps[1]) || maps[end] == maps[1]) &&
70+
isposdef(maps[1]) && _isposdef(maps[2:end-1])
71+
end
5172
end
5273

5374
# scalar multiplication and division (non-commutative case)
5475
function Base.:(*)(α::Number, A::LinearMap)
5576
T = promote_type(typeof(α), eltype(A))
56-
return CompositeMap{T}(tuple(A, UniformScalingMap(α, size(A, 1))))
77+
return CompositeMap{T}(_combine(A, UniformScalingMap(α, size(A, 1))))
5778
end
5879
function Base.:(*)(α::Number, A::CompositeMap)
5980
T = promote_type(typeof(α), eltype(A))
6081
Alast = last(A.maps)
6182
if Alast isa UniformScalingMap
62-
return CompositeMap{T}(tuple(Base.front(A.maps)..., α * Alast))
83+
return CompositeMap{T}(_combine(_front(A.maps), α * Alast))
6384
else
64-
return CompositeMap{T}(tuple(A.maps..., UniformScalingMap(α, size(A, 1))))
85+
return CompositeMap{T}(_combine(A.maps, UniformScalingMap(α, size(A, 1))))
6586
end
6687
end
6788
# needed for disambiguation
@@ -71,15 +92,15 @@ function Base.:(*)(α::RealOrComplex, A::CompositeMap{<:RealOrComplex})
7192
end
7293
function Base.:(*)(A::LinearMap, α::Number)
7394
T = promote_type(typeof(α), eltype(A))
74-
return CompositeMap{T}(tuple(UniformScalingMap(α, size(A, 2)), A))
95+
return CompositeMap{T}(_combine(UniformScalingMap(α, size(A, 2)), A))
7596
end
7697
function Base.:(*)(A::CompositeMap, α::Number)
7798
T = promote_type(typeof(α), eltype(A))
7899
Afirst = first(A.maps)
79100
if Afirst isa UniformScalingMap
80-
return CompositeMap{T}(tuple(Afirst * α, Base.tail(A.maps)...))
101+
return CompositeMap{T}(_combine(Afirst * α, _tail(A.maps)))
81102
else
82-
return CompositeMap{T}(tuple(UniformScalingMap(α, size(A, 2)), A.maps...))
103+
return CompositeMap{T}(_combine(UniformScalingMap(α, size(A, 2)), A.maps))
83104
end
84105
end
85106
# needed for disambiguation
@@ -110,19 +131,19 @@ julia> LinearMap(ones(Int, 3, 3)) * CS * I * rand(3, 3);
110131
"""
111132
function Base.:(*)(A₁::LinearMap, A₂::LinearMap)
112133
T = promote_type(eltype(A₁), eltype(A₂))
113-
return CompositeMap{T}(tuple(A₂, A₁))
134+
return CompositeMap{T}(_combine(A₂, A₁))
114135
end
115136
function Base.:(*)(A₁::LinearMap, A₂::CompositeMap)
116137
T = promote_type(eltype(A₁), eltype(A₂))
117-
return CompositeMap{T}(tuple(A₂.maps..., A₁))
138+
return CompositeMap{T}(_combine(A₂.maps, A₁))
118139
end
119140
function Base.:(*)(A₁::CompositeMap, A₂::LinearMap)
120141
T = promote_type(eltype(A₁), eltype(A₂))
121-
return CompositeMap{T}(tuple(A₂, A₁.maps...))
142+
return CompositeMap{T}(_combine(A₂, A₁.maps))
122143
end
123144
function Base.:(*)(A₁::CompositeMap, A₂::CompositeMap)
124145
T = promote_type(eltype(A₁), eltype(A₂))
125-
return CompositeMap{T}(tuple(A₂.maps..., A₁.maps...))
146+
return CompositeMap{T}(_combine(A₂.maps, A₁.maps))
126147
end
127148
# needed for disambiguation
128149
Base.:(*)(A₁::ScaledMap, A₂::CompositeMap) = A₁.λ * (A₁.lmap * A₂)
@@ -135,7 +156,8 @@ LinearAlgebra.adjoint(A::CompositeMap{T}) where {T} =
135156
CompositeMap{T}(map(adjoint, reverse(A.maps)))
136157

137158
# comparison of CompositeMap objects
138-
Base.:(==)(A::CompositeMap, B::CompositeMap) = (eltype(A) == eltype(B) && A.maps == B.maps)
159+
Base.:(==)(A::CompositeMap, B::CompositeMap) =
160+
(eltype(A) == eltype(B) && all(A.maps .== B.maps))
139161

140162
# multiplication with vectors/matrices
141163
_unsafe_mul!(y::AbstractVecOrMat, A::CompositeMap, x::AbstractVector) =

src/conversion.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ function SparseArrays.sparse(A::BlockMap)
136136
return hvcat(
137137
A.rows,
138138
convert(SparseMatrixCSC, first(A.maps)),
139-
convert.(AbstractMatrix, Base.tail(A.maps))...
139+
convert.(AbstractArray, _tail(A.maps))...
140140
)
141141
end
142142
Base.Matrix{T}(A::BlockDiagonalMap) where {T} = Base._cat((1,2), convert.(Matrix{T}, A.maps)...)
@@ -152,7 +152,7 @@ Base.convert(::Type{AbstractMatrix}, A::KroneckerMap) =
152152
function SparseArrays.sparse(A::KroneckerMap)
153153
return kron(
154154
convert(SparseMatrixCSC, first(A.maps)),
155-
convert.(AbstractMatrix, Base.tail(A.maps))...
155+
convert.(AbstractMatrix, _tail(A.maps))...
156156
)
157157
end
158158

0 commit comments

Comments
 (0)