Skip to content

Commit a0a02c7

Browse files
authored
transform by factorization (#35)
* transform by factorization * update quasiarrays * Update ContinuumArrays.jl * Update Project.toml * add WeightedBasis * mass matrix C.O.V. * Update bases.jl * Update Project.toml * Increase coverage * v0.2
1 parent 10a7ebd commit a0a02c7

File tree

6 files changed

+105
-20
lines changed

6 files changed

+105
-20
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
*.jl.mem
44
deps/deps.jl
55
.DS_Store
6+
Manifest.toml

.travis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ os:
55
- osx
66
- windows
77
julia:
8-
- 1.1
9-
- 1.2
108
- 1.3
119
- nightly
1210
matrix:

Project.toml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
name = "ContinuumArrays"
22
uuid = "7ae1f121-cc2c-504b-ac30-9b923412ae5c"
3-
version = "0.1"
3+
version = "0.2"
44

55
[deps]
6+
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
67
BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
8+
FastTransforms = "057dd010-8810-581a-b7be-e3fc3b93f78c"
79
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
810
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
911
LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02"
1012
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1113
QuasiArrays = "c4ea9172-b204-11e9-377d-29865faadc5c"
1214

1315
[compat]
14-
BandedMatrices = "0.14.1"
16+
BandedMatrices = "0.14.2"
1517
FillArrays = "0.8.2"
1618
IntervalSets = "0.3.2"
17-
LazyArrays = "0.14.7, 0.15"
18-
QuasiArrays = "0.0.6, 0.1"
19-
julia = "1.1"
19+
LazyArrays = "0.14.11"
20+
QuasiArrays = "0.1"
21+
julia = "1.3"
2022

2123
[extras]
24+
FastTransforms = "057dd010-8810-581a-b7be-e3fc3b93f78c"
2225
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2326

2427
[targets]

src/ContinuumArrays.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import FillArrays: AbstractFill, getindex_value, SquareEye
1515
import QuasiArrays: cardinality, checkindex, QuasiAdjoint, QuasiTranspose, Inclusion, SubQuasiArray,
1616
QuasiDiagonal, MulQuasiArray, MulQuasiMatrix, MulQuasiVector, QuasiMatMulMat, quasimulapplystyle,
1717
ApplyQuasiArray, ApplyQuasiMatrix, LazyQuasiArrayApplyStyle, AbstractQuasiArrayApplyStyle,
18-
LazyQuasiArray, LazyQuasiVector, LazyQuasiMatrix, LazyLayout, LazyQuasiArrayStyle, quasildivapplystyle
18+
LazyQuasiArray, LazyQuasiVector, LazyQuasiMatrix, LazyLayout, LazyQuasiArrayStyle, quasildivapplystyle, _factorize
1919

2020
export Spline, LinearSpline, HeavisideSpline, DiracDelta, Derivative, fullmaterialize, ℵ₁, Inclusion, Basis, WeightedBasis, grid, transform, affine
2121

@@ -181,9 +181,10 @@ affine(a, b) = affine(Inclusion(a), Inclusion(b))
181181

182182
const QInfAxes = Union{Inclusion,AbstractAffineQuasiVector}
183183

184+
184185
sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes}) = V
185186
sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes,QInfAxes}) = V
186-
sub_materialize(_, V::AbstractQuasiArray, ::Tuple{<:Any,QInfAxes}) = V
187+
sub_materialize(_, V::AbstractQuasiArray, ::Tuple{Any,QInfAxes}) = V
187188
sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes,Any}) = V
188189

189190

src/bases/bases.jl

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ abstract type AbstractBasisLayout <: MemoryLayout end
99
struct BasisLayout <: AbstractBasisLayout end
1010
struct SubBasisLayout <: AbstractBasisLayout end
1111
struct MappedBasisLayout <: AbstractBasisLayout end
12+
struct WeightedBasisLayout <: AbstractBasisLayout end
1213

1314
abstract type AbstractAdjointBasisLayout <: MemoryLayout end
1415
struct AdjointBasisLayout <: AbstractAdjointBasisLayout end
@@ -21,8 +22,8 @@ MemoryLayout(::Type{<:Weight}) = WeightLayout()
2122
adjointlayout(::Type, ::BasisLayout) = AdjointBasisLayout()
2223
adjointlayout(::Type, ::SubBasisLayout) = AdjointSubBasisLayout()
2324
adjointlayout(::Type, ::MappedBasisLayout) = AdjointMappedBasisLayout()
24-
broadcastlayout(::Type{typeof(*)}, ::WeightLayout, ::BasisLayout) = BasisLayout()
25-
broadcastlayout(::Type{typeof(*)}, ::WeightLayout, ::SubBasisLayout) = SubBasisLayout()
25+
broadcastlayout(::Type{typeof(*)}, ::WeightLayout, ::BasisLayout) = WeightedBasisLayout()
26+
broadcastlayout(::Type{typeof(*)}, ::WeightLayout, ::SubBasisLayout) = WeightedBasisLayout()
2627

2728
combine_mul_styles(::AbstractBasisLayout) = LazyQuasiArrayApplyStyle()
2829
combine_mul_styles(::AbstractAdjointBasisLayout) = LazyQuasiArrayApplyStyle()
@@ -88,18 +89,46 @@ end
8889
_grid(_, P) = error("Overload Grid")
8990
_grid(::MappedBasisLayout, P) = igetindex.(Ref(parentindices(P)[1]), grid(demap(P)))
9091
_grid(::SubBasisLayout, P) = grid(parent(P))
92+
_grid(::WeightedBasisLayout, P) = grid(last(P.args))
9193
grid(P) = _grid(MemoryLayout(typeof(P)), P)
9294

93-
function transform(L)
95+
struct TransformFactorization{T,Grid,Plan,IPlan} <: Factorization{T}
96+
grid::Grid
97+
plan::Plan
98+
iplan::IPlan
99+
end
100+
101+
TransformFactorization(grid, plan) =
102+
TransformFactorization{promote_type(eltype(grid),eltype(plan)),typeof(grid),typeof(plan),Nothing}(grid, plan, nothing)
103+
104+
105+
TransformFactorization(grid, ::Nothing, iplan) =
106+
TransformFactorization{promote_type(eltype(grid),eltype(iplan)),typeof(grid),Nothing,typeof(iplan)}(grid, nothing, iplan)
107+
108+
grid(T::TransformFactorization) = T.grid
109+
110+
\(a::TransformFactorization{<:Any,<:Any,Nothing}, b::AbstractQuasiVector) = a.iplan \ convert(Array, b[a.grid])
111+
\(a::TransformFactorization, b::AbstractQuasiVector) = a.plan * convert(Array, b[a.grid])
112+
113+
\(a::TransformFactorization{<:Any,<:Any,Nothing}, b::AbstractVector) = a.iplan \ b
114+
\(a::TransformFactorization, b::AbstractVector) = a.plan * b
115+
116+
function _factorize(::AbstractBasisLayout, L)
94117
p = grid(L)
95-
p,L[p,:]
118+
TransformFactorization(p, nothing, factorize(L[p,:]))
96119
end
97120

98-
function transform_ldiv(A, B, _)
99-
p,T = transform(A)
100-
T \ convert(Array, B[p])
121+
struct ProjectionFactorization{T, FAC<:Factorization{T}, INDS} <: Factorization{T}
122+
F::FAC
123+
inds::INDS
101124
end
102125

126+
\(a::ProjectionFactorization, b::AbstractQuasiVector) = (a.F \ b)[a.inds]
127+
\(a::ProjectionFactorization, b::AbstractVector) = (a.F \ b)[a.inds]
128+
129+
_factorize(::SubBasisLayout, L) = ProjectionFactorization(factorize(parent(L)), parentindices(L)[2])
130+
131+
transform_ldiv(A, B, _) = factorize(A) \ B
103132
transform_ldiv(A, B) = transform_ldiv(A, B, axes(A))
104133

105134
copy(L::Ldiv{<:AbstractBasisLayout,<:Any,<:Any,<:AbstractQuasiVector}) =
@@ -116,7 +145,7 @@ end
116145

117146

118147
function copy(L::Ldiv{<:AbstractBasisLayout,BroadcastLayout{typeof(*)},<:AbstractQuasiMatrix,<:AbstractQuasiVector})
119-
p,T = transform(L.A)
148+
p,T = factorize(L.A)
120149
T \ L.B[p]
121150
end
122151

@@ -126,6 +155,25 @@ end
126155
# *(arguments(S)...)
127156

128157

158+
159+
# mass matrix
160+
# y = p(x), dy = p'(x) * dx
161+
# \int_a^b f(y) g(y) dy = \int_{-1}^1 f(p(x))*g(p(x)) * p'(x) dx
162+
163+
164+
_sub_getindex(A, kr, jr) = A[kr, jr]
165+
_sub_getindex(A, ::Slice, ::Slice) = A
166+
167+
function copy(M::QMul2{<:QuasiAdjoint{<:Any,<:SubQuasiArray{<:Any,2,<:AbstractQuasiMatrix,<:Tuple{<:AbstractAffineQuasiVector,<:Any}}},
168+
<:SubQuasiArray{<:Any,2,<:AbstractQuasiMatrix,<:Tuple{<:AbstractAffineQuasiVector,<:Any}}})
169+
Ac, B = M.args
170+
A = Ac'
171+
PA,PB = parent(A),parent(B)
172+
kr,jr = parentindices(B)
173+
_sub_getindex((PA'PB)/kr.A,parentindices(A)[2],jr)
174+
end
175+
176+
129177
# Differentiation of sub-arrays
130178
function copy(M::QMul2{<:Derivative,<:SubQuasiArray{<:Any,2,<:AbstractQuasiMatrix,<:Tuple{<:Inclusion,<:Any}}})
131179
A, B = M.args
@@ -155,7 +203,7 @@ end
155203

156204
# we represent as a Mul with a banded matrix
157205
sublayout(::AbstractBasisLayout, ::Type{<:Tuple{<:Inclusion,<:AbstractUnitRange}}) = SubBasisLayout()
158-
sublayout(::BasisLayout, ::Type{<:Tuple{<:AbstractAffineQuasiVector,<:AbstractUnitRange}}) = MappedBasisLayout()
206+
sublayout(::AbstractBasisLayout, ::Type{<:Tuple{<:AbstractAffineQuasiVector,<:AbstractUnitRange}}) = MappedBasisLayout()
159207

160208
@inline sub_materialize(::AbstractBasisLayout, V::AbstractQuasiArray) = V
161209
@inline sub_materialize(::AbstractBasisLayout, V::AbstractArray) = V

test/runtests.jl

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using ContinuumArrays, QuasiArrays, LazyArrays, IntervalSets, FillArrays, LinearAlgebra, BandedMatrices, Test
2-
import ContinuumArrays: ℵ₁, materialize, SimplifyStyle, AffineQuasiVector, BasisLayout, AdjointBasisLayout, SubBasisLayout, MappedBasisLayout, igetindex
1+
using ContinuumArrays, QuasiArrays, LazyArrays, IntervalSets, FillArrays, LinearAlgebra, BandedMatrices, FastTransforms, Test
2+
import ContinuumArrays: ℵ₁, materialize, SimplifyStyle, AffineQuasiVector, BasisLayout, AdjointBasisLayout, SubBasisLayout,
3+
MappedBasisLayout, igetindex, TransformFactorization, Weight, WeightedBasisLayout
34
import QuasiArrays: SubQuasiArray, MulQuasiMatrix, Vec, Inclusion, QuasiDiagonal, LazyQuasiArrayApplyStyle, LazyQuasiArrayStyle
45
import LazyArrays: MemoryLayout, ApplyStyle, Applied, colsupport, arguments, ApplyLayout, LdivApplyStyle
56

@@ -228,6 +229,7 @@ end
228229
L = LinearSpline([1,2,3])
229230
x = axes(L,1)
230231
@test (L \ x) == [1,2,3]
232+
@test factorize(L[:,2:end-1]) isa ContinuumArrays.ProjectionFactorization
231233

232234
L = LinearSpline(range(0,1; length=10_000))
233235
x = axes(L,1)
@@ -347,6 +349,8 @@ end
347349
y = 2x .- 1
348350
L = LinearSpline(range(-1,stop=1,length=10))
349351
@test L[y,:][0.1,:] == L[2*0.1-1,:]
352+
@test L[y,:]'L[y,:] isa SymTridiagonal
353+
@test L[y,:]'L[y,:] == 1/2*(L'L)
350354

351355
D = Derivative(axes(L,1))
352356
H = HeavisideSpline(L.points)
@@ -368,6 +372,7 @@ end
368372
@test B[0.1,1] == L[2*0.1-1,2]
369373
@test B\B == Eye(8)
370374
@test L[y,:] \ B == Eye(10)[:,2:end-1]
375+
@test B'B == (1/2)*(L'L)[2:end-1,2:end-1]
371376
end
372377

373378
@testset "diff" begin
@@ -382,4 +387,33 @@ end
382387
K = x .- x'
383388
@test K[0.1,0.2] == K[Inclusion(0..0.5), Inclusion(0..0.5)][0.1,0.2] == 0.1 - 0.2
384389
@test_throws BoundsError K[Inclusion(0..0.5), Inclusion(0..0.5)][1,1]
390+
end
391+
392+
struct Chebyshev <: Basis{Float64}
393+
n::Int
394+
end
395+
396+
struct ChebyshevWeight <: Weight{Float64} end
397+
398+
399+
Base.axes(T::Chebyshev) = (Inclusion(-1..1), Base.OneTo(T.n))
400+
ContinuumArrays.grid(T::Chebyshev) = chebyshevpoints(Float64, T.n; kind=1)
401+
Base.axes(T::ChebyshevWeight) = (Inclusion(-1..1),)
402+
403+
LinearAlgebra.factorize(L::Chebyshev) =
404+
TransformFactorization(grid(L), plan_chebyshevtransform(Array{Float64}(undef, size(L,2))))
405+
406+
@testset "Chebyshev" begin
407+
T = Chebyshev(5)
408+
x = axes(T,1)
409+
F = factorize(T)
410+
g = grid(F)
411+
@test T \ exp.(x) == F \ exp.(x) == F \ exp.(g) == chebyshevtransform(exp.(g); kind=1)
412+
413+
w = ChebyshevWeight()
414+
wT = w .* T
415+
wT2 = w .* T[:,2:4]
416+
@test MemoryLayout(typeof(wT)) == WeightedBasisLayout()
417+
@test MemoryLayout(typeof(wT2)) == WeightedBasisLayout()
418+
@test grid(wT) == grid(wT2) == grid(T)
385419
end

0 commit comments

Comments
 (0)