Skip to content

Commit b2f5afd

Browse files
committed
first FEM solve working
1 parent 7cd4ff6 commit b2f5afd

File tree

9 files changed

+160
-27
lines changed

9 files changed

+160
-27
lines changed

src/ContinuumArrays.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import BandedMatrices: AbstractBandedLayout
88

99
include("QuasiArrays/QuasiArrays.jl")
1010
using .QuasiArrays
11-
import .QuasiArrays: _length, checkindex, Adjoint, Transpose, slice, QSlice
11+
import .QuasiArrays: cardinality, checkindex, Adjoint, Transpose, slice, QSlice, SubQuasiArray
1212

1313
export Spline, LinearSpline, HeavisideSpline, DiracDelta, Derivative
1414

@@ -20,7 +20,7 @@ struct AlephInfinity{N} <: Integer end
2020
const ℵ₁ = AlephInfinity{1}()
2121

2222

23-
_length(::AbstractInterval) = ℵ₁
23+
cardinality(::AbstractInterval) = ℵ₁
2424
*(ℵ::AlephInfinity) =
2525

2626

src/QuasiArrays/QuasiArrays.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ module QuasiArrays
22
using Base, LinearAlgebra, LazyArrays
33
import Base: getindex, size, axes, length, ==, isequal, iterate, CartesianIndices, LinearIndices,
44
Indices, IndexStyle, getindex, setindex!, parent, vec, convert, similar, zero,
5-
map, eachindex, eltype, first, last
5+
map, eachindex, eltype, first, last, firstindex, lastindex
66
import Base: @_inline_meta, DimOrInd, OneTo, @_propagate_inbounds_meta, @_noinline_meta,
77
DimsInteger, error_if_canonical_getindex, @propagate_inbounds, _return_type, _default_type,
88
_maybetail, tail, _getindex, _maybe_reshape, index_ndims, _unsafe_getindex,
99
index_shape, to_shape, unsafe_length, @nloops, @ncall, Slice, unalias
1010
import Base: ViewIndex, Slice, ScalarIndex, RangeIndex, view, viewindexing, ensure_indexable, index_dimsum,
11-
check_parent_index_match, reindex, _isdisjoint
11+
check_parent_index_match, reindex, _isdisjoint, unsafe_indices,
12+
parentindices
1213
import Base: *, /, \, +, -, inv
1314

1415
import Base.Broadcast: materialize
@@ -25,15 +26,15 @@ AbstractQuasiMatrix{T} = AbstractQuasiArray{T,2}
2526
AbstractQuasiVecOrMat{T} = Union{AbstractQuasiVector{T}, AbstractQuasiMatrix{T}}
2627

2728

28-
_length(d) = length(d)
29+
cardinality(d) = length(d)
2930

30-
size(A::AbstractQuasiArray) = _length.(axes(A))
31+
size(A::AbstractQuasiArray) = cardinality.(axes(A))
3132
axes(A::AbstractQuasiArray) = error("Override axes for $(typeof(A))")
3233

3334
include("indices.jl")
3435
include("abstractquasiarray.jl")
3536
include("multidimensional.jl")
36-
include("subarray.jl")
37+
include("subquasiarray.jl")
3738
include("matmul.jl")
3839

3940
include("adjtrans.jl")

src/QuasiArrays/indices.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ struct QSlice{T,AX} <: AbstractQuasiVector{T}
157157
end
158158
QSlice(axis) = QSlice{eltype(axis),typeof(axis)}(axis)
159159
QSlice(S::QSlice) = S
160+
==(A::QSlice, B::QSlice) = A.axis == B.axis
160161
axes(S::QSlice) = (S,)
161162
unsafe_indices(S::QSlice) = (S,)
162163
axes1(S::QSlice) = S
@@ -169,7 +170,10 @@ last(S::QSlice) = last(S.axis)
169170
size(S::QSlice) = (length(S.axis),)
170171
length(S::QSlice) = length(S.axis)
171172
unsafe_length(S::QSlice) = unsafe_length(S.axis)
173+
cardinality(S::QSlice) = cardinality(S.axis)
172174
getindex(S::QSlice, i::Real) = (@_inline_meta; @boundscheck checkbounds(S, i); i)
173175
getindex(S::QSlice, i::AbstractVector{<:Real}) = (@_inline_meta; @boundscheck checkbounds(S, i); i)
174176
show(io::IO, r::QSlice) = print(io, "QSlice(", r.axis, ")")
175177
iterate(S::QSlice, s...) = iterate(S.axis, s...)
178+
179+
checkindex(::Type{Bool}, inds::QSlice, i::Real) = i inds.axis

src/QuasiArrays/matmul.jl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ function getindex(M::QuasiMatMulVec, k::Real)
1919
ret
2020
end
2121

22+
function getindex(M::QuasiMatMulVec, k::AbstractArray)
23+
A,B = M.factors
24+
ret = zeros(eltype(M),length(k))
25+
@inbounds for j = 1:size(A,2)
26+
ret .+= Mul(view(A,k,j) , B[j])
27+
end
28+
ret
29+
end
30+
31+
2232
QuasiMatMulMat{styleA, styleB, T, V} = QuasiArrayMulArray{styleA, styleB, 2, 2, T, V}
2333
QuasiMatMulQuasiMat{styleA, styleB, T, V} = QuasiArrayMulQuasiArray{styleA, styleB, 2, 2, T, V}
2434

@@ -28,5 +38,5 @@ QuasiMatMulQuasiMat{styleA, styleB, T, V} = QuasiArrayMulQuasiArray{styleA, styl
2838
*(A::AbstractArray, B::AbstractQuasiArray) = materialize(Mul(A,B))
2939
inv(A::AbstractQuasiArray) = materialize(Inv(A))
3040

31-
*(A::AbstractQuasiArray, B::Mul) = Mul(A, B.factors...)
32-
*(A::Mul, B::AbstractQuasiArray) = Mul(A.factors..., B)
41+
*(A::AbstractQuasiArray, B::Mul) = materialize(Mul(A, B.factors...))
42+
*(A::Mul, B::AbstractQuasiArray) = materialize(Mul(A.factors..., B))

src/QuasiArrays/multidimensional.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ end
77
@inline to_indices(A, inds, I::Tuple{Colon, Vararg{Any}}) =
88
(uncolon(inds, I), to_indices(A, _maybetail(inds), tail(I))...)
99

10+
@inline index_dimsum(::AbstractQuasiArray{Bool}, I...) = (true, index_dimsum(I...)...)
11+
@inline function index_dimsum(::AbstractQuasiArray{<:Any,N}, I...) where N
12+
(ntuple(x->true, Val(N))..., index_dimsum(I...)...)
13+
end
14+
1015
slice(d::AbstractVector) = Slice(d)
1116
slice(d) = QSlice(d)
1217

src/QuasiArrays/subarray.jl renamed to src/QuasiArrays/subquasiarray.jl

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ check_parent_index_match(parent::AbstractQuasiArray{T,N}, ::NTuple{N, Bool}) whe
3333
viewindexing(I::Tuple{AbstractQuasiArray, Vararg{Any}}) = IndexCartesian()
3434

3535
# Simple utilities
36-
size(V::SubQuasiArray) = (@_inline_meta; map(n->unsafe_length(n), axes(V)))
36+
size(V::SubQuasiArray) = (@_inline_meta; map(n->cardinality(n), axes(V)))
3737

3838
similar(V::SubQuasiArray, T::Type, dims::Dims) = similar(V.parent, T, dims)
3939

@@ -84,6 +84,22 @@ end
8484
unsafe_view(V::SubQuasiArray, I::Vararg{ViewIndex,N}) where {N} =
8585
(@_inline_meta; _maybe_reindex(V, I))
8686

87+
_maybe_reindex(V, I) = (@_inline_meta; _maybe_reindex(V, I, I))
88+
# _maybe_reindex(V, I, ::Tuple{AbstractArray{<:AbstractCartesianIndex}, Vararg{Any}}) =
89+
# (@_inline_meta; SubArray(V, I))
90+
# # But allow arrays of CartesianIndex{1}; they behave just like arrays of Ints
91+
# _maybe_reindex(V, I, A::Tuple{AbstractArray{<:AbstractCartesianIndex{1}}, Vararg{Any}}) =
92+
# (@_inline_meta; _maybe_reindex(V, I, tail(A)))
93+
_maybe_reindex(V, I, A::Tuple{Any, Vararg{Any}}) = (@_inline_meta; _maybe_reindex(V, I, tail(A)))
94+
95+
_subarray(A::AbstractArray, idxs) = SubArray(A, idxs)
96+
_subarray(A::AbstractQuasiArray, idxs) = SubQuasiArray(A, idxs)
97+
98+
function _maybe_reindex(V, I, ::Tuple{})
99+
@_inline_meta
100+
@inbounds idxs = to_indices(V.parent, reindex(V, V.indices, I))
101+
_subarray(V.parent, idxs)
102+
end
87103
## Re-indexing is the heart of a view, transforming A[i, j][x, y] to A[i[x], j[y]]
88104
#
89105
# Recursively look through the heads of the parent- and sub-indices, considering
@@ -115,42 +131,42 @@ end
115131

116132
# In general, we simply re-index the parent indices by the provided ones
117133
SlowSubQuasiArray{T,N,P,I} = SubQuasiArray{T,N,P,I,false}
118-
function getindex(V::SlowSubQuasiArray{T,N}, I::Vararg{Int,N}) where {T,N}
134+
function getindex(V::SlowSubQuasiArray{T,N}, I::Vararg{Real,N}) where {T,N}
119135
@_inline_meta
120136
@boundscheck checkbounds(V, I...)
121137
@inbounds r = V.parent[reindex(V, V.indices, I)...]
122138
r
123139
end
124140

125141
FastSubQuasiArray{T,N,P,I} = SubQuasiArray{T,N,P,I,true}
126-
function getindex(V::FastSubQuasiArray, i::Int)
142+
function getindex(V::FastSubQuasiArray, i::Real)
127143
@_inline_meta
128144
@boundscheck checkbounds(V, i)
129145
@inbounds r = V.parent[V.offset1 + V.stride1*i]
130146
r
131147
end
132148
# We can avoid a multiplication if the first parent index is a Colon or AbstractUnitRange
133149
FastContiguousSubQuasiArray{T,N,P,I<:Tuple{Union{Slice, AbstractUnitRange}, Vararg{Any}}} = SubQuasiArray{T,N,P,I,true}
134-
function getindex(V::FastContiguousSubQuasiArray, i::Int)
150+
function getindex(V::FastContiguousSubQuasiArray, i::Real)
135151
@_inline_meta
136152
@boundscheck checkbounds(V, i)
137153
@inbounds r = V.parent[V.offset1 + i]
138154
r
139155
end
140156

141-
function setindex!(V::SlowSubQuasiArray{T,N}, x, I::Vararg{Int,N}) where {T,N}
157+
function setindex!(V::SlowSubQuasiArray{T,N}, x, I::Vararg{Real,N}) where {T,N}
142158
@_inline_meta
143159
@boundscheck checkbounds(V, I...)
144160
@inbounds V.parent[reindex(V, V.indices, I)...] = x
145161
V
146162
end
147-
function setindex!(V::FastSubQuasiArray, x, i::Int)
163+
function setindex!(V::FastSubQuasiArray, x, i::Real)
148164
@_inline_meta
149165
@boundscheck checkbounds(V, i)
150166
@inbounds V.parent[V.offset1 + V.stride1*i] = x
151167
V
152168
end
153-
function setindex!(V::FastContiguousSubQuasiArray, x, i::Int)
169+
function setindex!(V::FastContiguousSubQuasiArray, x, i::Real)
154170
@_inline_meta
155171
@boundscheck checkbounds(V, i)
156172
@inbounds V.parent[V.offset1 + i] = x
@@ -239,7 +255,7 @@ _pointer(V::SubQuasiArray, i::Int) = pointer(V, Base._ind2sub(axes(V), i))
239255
axes(S::SubQuasiArray) = (@_inline_meta; _indices_sub(S, S.indices...))
240256
_indices_sub(S::SubQuasiArray) = ()
241257
_indices_sub(S::SubQuasiArray, ::Real, I...) = (@_inline_meta; _indices_sub(S, I...))
242-
function _indices_sub(S::SubQuasiArray, i1::AbstractQuasiArray, I...)
258+
function _indices_sub(S::SubQuasiArray, i1::Union{AbstractQuasiArray,AbstractArray}, I...)
243259
@_inline_meta
244260
(unsafe_indices(i1)..., _indices_sub(S, I...)...)
245261
end

src/bases/splines.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ function copyto!(dest::Mul2{<:Any,<:Any,<:HeavisideSpline},
8686
bandwidths(A) == (0,1) || throw(ArgumentError("Not implemented"))
8787

8888
d = diff(x)
89-
A[band(0)] .= (-).(d)
90-
A[band(1)] .= d
89+
A[band(0)] .= inv.((-).(d))
90+
A[band(1)] .= inv.(d)
9191

9292
dest
9393
end

src/operators.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ end
2020

2121

2222
function materialize(M::Mul2{<:Any,<:Any,<:QuasiArrays.Adjoint{<:Any,<:DiracDelta},<:AbstractQuasiVector})
23-
A, B = M.A, M.B
24-
axes(A,2) == axes(A,1) || throw(DimensionMismatch())
23+
A, B = M.factors
24+
axes(A,2) == axes(B,1) || throw(DimensionMismatch())
2525
B[parent(A).x]
2626
end
2727

@@ -31,7 +31,7 @@ function materialize(M::Mul2{<:Any,<:Any,<:QuasiArrays.Adjoint{<:Any,<:DiracDelt
3131
B[parent(A).x,:]
3232
end
3333

34-
struct Derivative{T,A} <: AbstractQuasiVector{T}
34+
struct Derivative{T,A} <: AbstractQuasiMatrix{T}
3535
axis::A
3636
end
3737

@@ -40,3 +40,11 @@ Derivative(axis) = Derivative{Float64}(axis)
4040

4141
axes(D::Derivative) = (D.axis, D.axis)
4242
==(a::Derivative, b::Derivative) = a.axis == b.axis
43+
44+
45+
function materialize(M::Mul2{<:Any,<:Any,<:Derivative,<:SubQuasiArray})
46+
A, B = M.factors
47+
axes(A,2) == axes(B,1) || throw(DimensionMismatch())
48+
P = parent(B)
49+
(Derivative(axes(P,1))*P)[parentindices(B)...]
50+
end

test/runtests.jl

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using ContinuumArrays, LazyArrays, IntervalSets, FillArrays, LinearAlgebra, BandedMatrices, Test
22
import ContinuumArrays: ℵ₁, materialize
3+
import ContinuumArrays.QuasiArrays: SubQuasiArray
34

45
@testset "DiracDelta" begin
56
δ = DiracDelta(-1..3)
@@ -31,7 +32,6 @@ end
3132

3233
@test_throws BoundsError H[[0.1,2.1], 1]
3334

34-
3535
f = H*[1,2]
3636
@test axes(f) == (1.0..3.0,)
3737
@test f[1.1] 1
@@ -89,18 +89,107 @@ end
8989
DL = D*L
9090
@test M.factors == tuple(D', (D*L).factors...)
9191

92-
@test materialize(Mul(L', D', D, L)) == materialize(L'D'*D*L) ==
92+
@test materialize(Mul(L', D', D, L)) == (L'D'*D*L) ==
9393
[1.0 -1 0; -1.0 2.0 -1.0; 0.0 -1.0 1.0]
9494

9595
@test materialize(Mul(L', D', D, L)) isa BandedMatrix
96-
@test materialize(L'D'*D*L) isa BandedMatrix
96+
@test (L'D'*D*L) isa BandedMatrix
9797

9898
@test bandwidths(materialize(L'D'*D*L)) == (1,1)
9999
end
100100

101101
@testset "Views" begin
102102
L = LinearSpline(0:2)
103103
@test view(L,0.1,1)[1] == L[0.1,1]
104+
105+
L = LinearSpline(0:2)
106+
B1 = L[:,1]
107+
@test B1 isa SubQuasiArray{Float64,1}
108+
@test size(B1) == (ℵ₁,)
109+
@test B1[0.1] == L[0.1,1]
110+
@test_throws BoundsError B1[2.2]
111+
112+
B = L[:,1:2]
113+
@test B isa SubQuasiArray{Float64,2}
114+
@test B[0.1,:] == L[0.1,1:2]
115+
116+
B = L[:,2:end-1]
117+
@test B[0.1,:] == [0.1]
118+
end
119+
120+
A = randn(4,4)
121+
@which lastindex(A,2)
122+
123+
@time begin
124+
L = LinearSpline(range(0,stop=1,length=10))[:,2:end-1]
125+
D = Derivative(axes(L,1))
126+
127+
D*L
128+
129+
Derivative(0..1)*parent(L)
130+
131+
132+
133+
134+
M = Mul(D,L)
135+
A, B = M.factors
136+
axes(A,2) == axes(B,1) || throw(DimensionMismatch())
137+
P = parent(B)
138+
(Derivative(axes(P,1))*P)[parentindices(P)...]
139+
140+
@which axes(D,2)
141+
142+
axes(D,2)
143+
D*L
144+
A = -(L'D'D*L)
145+
f = L*exp.(L.points)
146+
147+
A \ (L'f)
148+
149+
u = A[2:end-1,2:end-1] \ (L'f)[2:end-1]
150+
151+
cond(A[2:end-1,2:end-1])
152+
153+
A[2:end-1,2:end-1] *u - (L'f)[2:end-1]
154+
155+
v = L*[0; u; 0]
156+
157+
158+
v[0.2]
159+
using Plots
160+
plot(0:0.01:1,getindex.(Ref(v),0:0.01:1))
161+
plot!(u1)
162+
ui
163+
164+
using ApproxFun
165+
166+
x = Fun(0..1)
167+
u1 = [Dirichlet(Chebyshev(0..1)); ApproxFun.Derivative()^2] \ [[0,0], exp(x)]
168+
169+
plot(u1)
170+
171+
u_ex = L*u1.(L.points)
172+
173+
xx = 0:0.01:1;
174+
plot(xx,getindex.(Ref(D*u_ex),xx))
175+
176+
getindex.(Ref(D*u_ex),xx)
177+
plot!(u1')
178+
179+
f[0.1]-exp(0.1)
180+
181+
(D*v)'*(D*v)
182+
183+
184+
185+
L'f
186+
187+
188+
189+
190+
191+
(L'f)
192+
193+
(L'f)
194+
104195
end
105-
L = LinearSpline(0:2)
106-
L[:,1]

0 commit comments

Comments
 (0)