Skip to content

Commit e575b5f

Browse files
authored
Overload axes for ScaledMap and LinearCombination (#162)
1 parent 13faa0f commit e575b5f

File tree

8 files changed

+68
-5
lines changed

8 files changed

+68
-5
lines changed

Project.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "LinearMaps"
22
uuid = "7a12625a-238d-50fd-b39a-03d52299707e"
3-
version = "3.4.1"
3+
version = "3.5.0"
44

55
[deps]
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
@@ -12,11 +12,12 @@ julia = "1"
1212
[extras]
1313
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
1414
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
15+
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
1516
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
1617
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1718
Quaternions = "94ee1d12-ae83-5a48-8b1c-48b8ff168ae0"
1819
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1920
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2021

2122
[targets]
22-
test = ["Aqua", "BenchmarkTools", "InteractiveUtils", "LinearAlgebra", "Quaternions", "SparseArrays", "Test"]
23+
test = ["Aqua", "BenchmarkTools", "BlockArrays", "InteractiveUtils", "LinearAlgebra", "Quaternions", "SparseArrays", "Test"]

docs/src/history.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Version history
22

3+
## What's new in v3.5
4+
5+
* `WrappedMap`, `ScaledMap`, and `LinearCombination`, instead of using the default `axes(A)
6+
= map(oneto, size(A))`, now forward calls to `axes` to the underlying wrapped linear map.
7+
This allows allocating operations such as `*` to determine the appropriate storage and axes
8+
type of their outputs. For example, linear maps that wrap `BlockArrays` will, upon
9+
multiplicative action, produce a `BlockArrays.PseudoBlockVector` with block structure
10+
inherited from the operator's *output* axes `axes(A,1)`.
11+
312
## What's new in v3.4
413

514
* In `WrappedMap` constructors, as implicitly called in addition and mutliplication

src/LinearMaps.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ julia> A(x)
111111
"""
112112
function Base.:(*)(A::LinearMap, x::AbstractVector)
113113
check_dim_mul(A, x)
114-
return mul!(similar(x, promote_type(eltype(A), eltype(x)), size(A, 1)), A, x)
114+
T = promote_type(eltype(A), eltype(x))
115+
y = similar(x, T, axes(A)[1])
116+
return mul!(y, A, x)
115117
end
116118
if VERSION v"1.3"
117119
(L::LinearMap)(x::AbstractVector) = L*x

src/linearcombination.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ struct LinearCombination{T, As<:LinearMapTuple} <: LinearMap{T}
22
maps::As
33
function LinearCombination{T, As}(maps::As) where {T, As}
44
N = length(maps)
5-
sz = size(maps[1])
5+
ax = axes(maps[1])
66
for n in eachindex(maps)
77
A = maps[n]
8-
size(A) == sz || throw(DimensionMismatch("LinearCombination"))
8+
axes(A) == ax || throw(DimensionMismatch("LinearCombination"))
99
@assert promote_type(T, eltype(A)) == T "eltype $(eltype(A)) cannot be promoted to $T in LinearCombination constructor"
1010
end
1111
new{T, As}(maps)
@@ -18,6 +18,7 @@ MulStyle(A::LinearCombination) = MulStyle(A.maps...)
1818

1919
# basic methods
2020
Base.size(A::LinearCombination) = size(A.maps[1])
21+
Base.axes(A::LinearMaps.LinearCombination) = axes(A.maps[1])
2122
# following conditions are sufficient but not necessary
2223
LinearAlgebra.issymmetric(A::LinearCombination) = all(issymmetric, A.maps)
2324
LinearAlgebra.ishermitian(A::LinearCombination) = all(ishermitian, A.maps)

src/scaledmap.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ ScaledMap(λ::RealOrComplex, lmap::LinearMap{<:RealOrComplex}) =
1818

1919
# basic methods
2020
Base.size(A::ScaledMap) = size(A.lmap)
21+
Base.axes(A::ScaledMap) = axes(A.lmap)
2122
Base.isreal(A::ScaledMap) = isreal(A.λ) && isreal(A.lmap)
2223
LinearAlgebra.issymmetric(A::ScaledMap) = issymmetric(A.lmap)
2324
LinearAlgebra.ishermitian(A::ScaledMap) = isreal(A.λ) && ishermitian(A.lmap)

src/wrappedmap.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Base.:(==)(A::VecOrMatMap, B::VecOrMatMap) =
5959
# properties
6060
Base.size(A::WrappedMap) = size(A.lmap)
6161
Base.size(A::WrappedMap{<:Any,<:AbstractVector}) = (Int(length(A.lmap))::Int, 1)
62+
Base.axes(A::WrappedMap) = axes(A.lmap)
6263
LinearAlgebra.issymmetric(A::WrappedMap) = A._issymmetric
6364
LinearAlgebra.ishermitian(A::WrappedMap) = A._ishermitian
6465
LinearAlgebra.isposdef(A::WrappedMap) = A._isposdef

test/nontradaxes.jl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using Test, LinearMaps, LinearAlgebra, BlockArrays
2+
3+
@testset "Non-traditional axes" begin
4+
5+
A = rand(ComplexF64,2,4)
6+
B = PseudoBlockMatrix{ComplexF64}(undef, [2,3], [3,4])
7+
8+
ax1 = axes(B)[1]
9+
ax2 = axes(B)[2]
10+
fill!(B,0)
11+
B[Block(1),Block(2)] .= A
12+
13+
N = @inferred LinearMap(B)
14+
@test axes(N) == (ax1,ax2)
15+
16+
@test eltype(N) == eltype(B)
17+
18+
u = similar(Array{ComplexF64}, ax2)
19+
v = PseudoBlockVector{ComplexF64}(undef, [3,5])
20+
w = PseudoBlockVector{ComplexF64}(undef, [4,3])
21+
# v = similar(Array{ComplexF64}, blockedrange([3,5]))
22+
# w = similar(Array{ComplexF64}, blockedrange([4,3]))
23+
24+
for i in eachindex(u) u[i] = rand(ComplexF64) end
25+
for i in eachindex(v) v[i] = rand(ComplexF64) end
26+
for i in eachindex(w) w[i] = rand(ComplexF64) end
27+
28+
@test B*u == N*u
29+
@test_throws DimensionMismatch N*v
30+
31+
# Lu = L*u
32+
Nu = N*u
33+
34+
@test axes(Nu)[1] == axes(N)[1] == axes(B)[1]
35+
@test blocklengths(axes(Nu)[1]) == blocklengths(axes(N)[1]) == blocklengths(axes(B)[1]) == [2,3]
36+
37+
C = B + 2N
38+
@test axes(C) === axes(B) === axes(N)
39+
@test C*u 3*Nu
40+
41+
Cu = C*u
42+
@test axes(C)[1] == ax1
43+
@test blocklengths(axes(C)[1]) == blocklengths(ax1)
44+
end

test/runtests.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,7 @@ include("conversion.jl")
3636
include("left.jl")
3737

3838
include("fillmap.jl")
39+
40+
if VERSION v"1.1"
41+
include("nontradaxes.jl")
42+
end

0 commit comments

Comments
 (0)