|
1 | 1 | module ContinuumArrays
|
2 |
| -using IntervalSets, LinearAlgebra, LazyArrays, FillArrays, BandedMatrices, QuasiArrays, InfiniteArrays |
| 2 | +using IntervalSets, LinearAlgebra, LazyArrays, FillArrays, BandedMatrices, QuasiArrays, InfiniteArrays, StaticArrays, BlockArrays |
3 | 3 | import Base: @_inline_meta, @_propagate_inbounds_meta, axes, getindex, convert, prod, *, /, \, +, -, ==, ^,
|
4 |
| - IndexStyle, IndexLinear, ==, OneTo, tail, similar, copyto!, copy, diff, |
| 4 | + IndexStyle, IndexLinear, ==, OneTo, _maybetail, tail, similar, copyto!, copy, diff, |
5 | 5 | first, last, show, isempty, findfirst, findlast, findall, Slice, union, minimum, maximum, sum, _sum,
|
6 |
| - getproperty, isone, iszero, zero, abs, <, ≤, >, ≥, string, summary |
| 6 | + getproperty, isone, iszero, zero, abs, <, ≤, >, ≥, string, summary, to_indices |
7 | 7 | import Base.Broadcast: materialize, BroadcastStyle, broadcasted
|
8 | 8 | import LazyArrays: MemoryLayout, Applied, ApplyStyle, flatten, _flatten, colsupport, most, combine_mul_styles, AbstractArrayApplyStyle,
|
9 | 9 | adjointlayout, arguments, _mul_arguments, call, broadcastlayout, layout_getindex, UnknownLayout,
|
10 | 10 | sublayout, sub_materialize, ApplyLayout, BroadcastLayout, combine_mul_styles, applylayout,
|
11 | 11 | simplifiable, _simplify
|
12 | 12 | import LinearAlgebra: pinv, dot, norm2
|
13 | 13 | import BandedMatrices: AbstractBandedLayout, _BandedMatrix
|
| 14 | +import BlockArrays: block, blockindex, unblock, blockedrange, _BlockedUnitRange, _BlockArray |
14 | 15 | import FillArrays: AbstractFill, getindex_value, SquareEye
|
15 | 16 | import ArrayLayouts: mul
|
16 | 17 | import QuasiArrays: cardinality, checkindex, QuasiAdjoint, QuasiTranspose, Inclusion, SubQuasiArray,
|
17 | 18 | QuasiDiagonal, MulQuasiArray, MulQuasiMatrix, MulQuasiVector, QuasiMatMulMat,
|
18 | 19 | ApplyQuasiArray, ApplyQuasiMatrix, LazyQuasiArrayApplyStyle, AbstractQuasiArrayApplyStyle, AbstractQuasiLazyLayout,
|
19 | 20 | LazyQuasiArray, LazyQuasiVector, LazyQuasiMatrix, LazyLayout, LazyQuasiArrayStyle, _factorize
|
20 |
| -import InfiniteArrays: Infinity |
| 21 | +import InfiniteArrays: Infinity, InfAxes |
21 | 22 |
|
22 |
| -export Spline, LinearSpline, HeavisideSpline, DiracDelta, Derivative, ℵ₁, Inclusion, Basis, WeightedBasis, grid, transform, affine |
| 23 | +export Spline, LinearSpline, HeavisideSpline, DiracDelta, Derivative, ℵ₁, Inclusion, Basis, WeightedBasis, grid, transform, affine, .. |
23 | 24 |
|
24 | 25 | ####
|
25 | 26 | # Interval indexing support
|
@@ -90,177 +91,43 @@ function dot(x::Inclusion{T,<:AbstractInterval}, y::Inclusion{V,<:AbstractInterv
|
90 | 91 | end
|
91 | 92 |
|
92 | 93 |
|
93 |
| -function checkindex(::Type{Bool}, inds::Inclusion{<:Any,<:AbstractInterval}, r::Inclusion{<:Any,<:AbstractInterval}) |
94 |
| - @_propagate_inbounds_meta |
95 |
| - isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r))) |
96 |
| -end |
97 |
| - |
98 |
| - |
99 |
| -### |
100 |
| -# Maps |
101 |
| -### |
102 |
| - |
103 |
| -""" |
104 |
| -A subtype of `Map` is used as a one-to-one map between two domains |
105 |
| -via `view`. The domain of the map `m` is `axes(m,1)` and the range |
106 |
| -is `union(m)`. |
107 |
| -
|
108 |
| -Maps must also overload `invmap` to give the inverse of the map, which |
109 |
| -is equivalent to `invmap(m)[x] == findfirst(isequal(x), m)`. |
110 |
| -""" |
111 |
| - |
112 |
| -abstract type Map{T} <: AbstractQuasiVector{T} end |
113 |
| - |
114 |
| -invmap(M::Map) = error("Overload invmap(::$(typeof(M)))") |
115 |
| - |
116 |
| - |
117 |
| -Base.in(x, m::Map) = x in union(m) |
118 |
| -Base.issubset(d::Map, b::IntervalSets.Domain) = union(d) ⊆ b |
119 |
| -Base.union(d::Map) = axes(invmap(d),1) |
120 |
| - |
121 |
| -for find in (:findfirst, :findlast) |
122 |
| - @eval function $find(f::Base.Fix2{typeof(isequal)}, d::Map) |
123 |
| - f.x in d || return nothing |
124 |
| - $find(isequal(invmap(d)[f.x]), union(d)) |
125 |
| - end |
126 |
| -end |
127 |
| - |
128 |
| -@eval function findall(f::Base.Fix2{typeof(isequal)}, d::Map) |
129 |
| - f.x in d || return eltype(axes(d,1))[] |
130 |
| - findall(isequal(invmap(d)[f.x]), union(d)) |
131 |
| -end |
132 |
| - |
133 |
| -function Base.getindex(d::Map, x::Inclusion) |
134 |
| - x == axes(d,1) || throw(BoundsError(d, x)) |
135 |
| - d |
136 |
| -end |
137 |
| - |
138 |
| -# Affine map represents A*x .+ b |
139 |
| -abstract type AbstractAffineQuasiVector{T,AA,X,B} <: Map{T} end |
140 |
| - |
141 |
| -summary(io::IO, a::AbstractAffineQuasiVector) = print(io, "$(a.A) * $(a.x) .+ ($(a.b))") |
142 |
| - |
143 |
| -struct AffineQuasiVector{T,AA,X,B} <: AbstractAffineQuasiVector{T,AA,X,B} |
144 |
| - A::AA |
145 |
| - x::X |
146 |
| - b::B |
147 |
| -end |
148 |
| - |
149 |
| -AffineQuasiVector(A::AA, x::X, b::B) where {AA,X,B} = |
150 |
| - AffineQuasiVector{promote_type(eltype(AA), eltype(X), eltype(B)),AA,X,B}(A,x,b) |
151 |
| - |
152 |
| -AffineQuasiVector(A, x) = AffineQuasiVector(A, x, zero(promote_type(eltype(A),eltype(x)))) |
153 |
| -AffineQuasiVector(x) = AffineQuasiVector(one(eltype(x)), x) |
154 |
| - |
155 |
| -AffineQuasiVector(A, x::AffineQuasiVector, b) = AffineQuasiVector(A*x.A, x.x, A*x.b .+ b) |
156 |
| - |
157 |
| -axes(A::AbstractAffineQuasiVector) = axes(A.x) |
158 |
| - |
159 |
| -affine_getindex(A, k) = A.A*A.x[k] .+ A.b |
160 |
| -Base.unsafe_getindex(A::AbstractAffineQuasiVector, k) = A.A*Base.unsafe_getindex(A.x,k) .+ A.b |
161 |
| -getindex(A::AbstractAffineQuasiVector, k::Number) = affine_getindex(A, k) |
162 |
| -function getindex(A::AbstractAffineQuasiVector, k::Inclusion) |
163 |
| - @boundscheck A.x[k] # throws bounds error if k ≠ x |
164 |
| - A |
165 |
| -end |
166 |
| - |
167 |
| -getindex(A::AbstractAffineQuasiVector, ::Colon) = copy(A) |
168 |
| - |
169 |
| -copy(A::AbstractAffineQuasiVector) = A |
170 |
| - |
171 |
| -inbounds_getindex(A::AbstractAffineQuasiVector{<:Any,<:Any,<:Inclusion}, k::Number) = A.A*k .+ A.b |
172 |
| -isempty(A::AbstractAffineQuasiVector) = isempty(A.x) |
173 |
| -==(a::AbstractAffineQuasiVector, b::AbstractAffineQuasiVector) = a.A == b.A && a.x == b.x && a.b == b.b |
174 |
| - |
175 |
| -BroadcastStyle(::Type{<:AbstractAffineQuasiVector}) = LazyQuasiArrayStyle{1}() |
176 |
| - |
177 |
| -for op in(:*, :\, :+, :-) |
178 |
| - @eval broadcasted(::LazyQuasiArrayStyle{1}, ::typeof($op), a::Number, x::Inclusion) = broadcast($op, a, AffineQuasiVector(x)) |
179 |
| -end |
180 |
| -for op in(:/, :+, :-) |
181 |
| - @eval broadcasted(::LazyQuasiArrayStyle{1}, ::typeof($op), x::Inclusion, a::Number) = broadcast($op, AffineQuasiVector(x), a) |
182 |
| -end |
183 |
| - |
184 |
| -broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(*), a::Number, x::AbstractAffineQuasiVector) = AffineQuasiVector(a, x) |
185 |
| -broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(\), a::Number, x::AbstractAffineQuasiVector) = AffineQuasiVector(inv(a), x) |
186 |
| -broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(/), x::AbstractAffineQuasiVector, a::Number) = AffineQuasiVector(inv(a), x) |
187 |
| -broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(+), a::Number, x::AbstractAffineQuasiVector) = AffineQuasiVector(one(eltype(x)), x, a) |
188 |
| -broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(+), x::AbstractAffineQuasiVector, b::Number) = AffineQuasiVector(one(eltype(x)), x, b) |
189 |
| -broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(-), a::Number, x::AbstractAffineQuasiVector) = AffineQuasiVector(-one(eltype(x)), x, a) |
190 |
| -broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(-), x::AbstractAffineQuasiVector, b::Number) = AffineQuasiVector(one(eltype(x)), x, -b) |
191 |
| - |
192 |
| -function checkindex(::Type{Bool}, inds::Inclusion{<:Any,<:AbstractInterval}, r::AbstractAffineQuasiVector) |
193 |
| - @_propagate_inbounds_meta |
194 |
| - isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r))) |
195 |
| -end |
196 |
| - |
197 |
| -minimum(d::AbstractAffineQuasiVector) = signbit(d.A) ? last(d) : first(d) |
198 |
| -maximum(d::AbstractAffineQuasiVector) = signbit(d.A) ? first(d) : last(d) |
199 |
| - |
200 |
| -union(d::AbstractAffineQuasiVector) = Inclusion(minimum(d)..maximum(d)) |
201 |
| -invmap(d::AbstractAffineQuasiVector) = affine(union(d), axes(d,1)) |
202 |
| - |
203 |
| - |
204 |
| - |
| 94 | +include("maps.jl") |
205 | 95 |
|
| 96 | +const QInfAxes = Union{Inclusion,AbstractAffineQuasiVector} |
206 | 97 |
|
207 |
| -struct AffineMap{T,D,R} <: AbstractAffineQuasiVector{T,T,D,T} |
208 |
| - domain::D |
209 |
| - range::R |
210 |
| -end |
211 | 98 |
|
212 |
| -AffineMap(domain::AbstractQuasiVector{T}, range::AbstractQuasiVector{V}) where {T,V} = |
213 |
| - AffineMap{promote_type(T,V), typeof(domain),typeof(range)}(domain,range) |
| 99 | +sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes}) = V |
| 100 | +sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes,QInfAxes}) = V |
| 101 | +sub_materialize(_, V::AbstractQuasiArray, ::Tuple{Any,QInfAxes}) = V |
| 102 | +sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes,Any}) = V |
214 | 103 |
|
215 |
| -measure(x::Inclusion) = last(x)-first(x) |
| 104 | +# ambiguity error |
| 105 | +sub_materialize(_, V::AbstractQuasiArray, ::Tuple{InfAxes,QInfAxes}) = V |
| 106 | +sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes,InfAxes}) = V |
216 | 107 |
|
217 |
| -function getproperty(A::AffineMap, d::Symbol) |
218 |
| - domain, range = getfield(A, :domain), getfield(A, :range) |
219 |
| - d == :x && return domain |
220 |
| - d == :A && return measure(range)/measure(domain) |
221 |
| - d == :b && return (last(domain)*first(range) - first(domain)*last(range))/measure(domain) |
222 |
| - getfield(A, d) |
223 |
| -end |
| 108 | +# |
| 109 | +# BlockQuasiArrays |
224 | 110 |
|
225 |
| -function getindex(A::AffineMap, k::Number) |
226 |
| - # ensure we exactly hit range |
227 |
| - k == first(A.domain) && return first(A.range) |
228 |
| - k == last(A.domain) && return last(A.range) |
229 |
| - affine_getindex(A, k) |
| 111 | +BlockArrays.blockaxes(::Inclusion) = blockaxes(Base.OneTo(1)) # just use 1 block |
| 112 | +function BlockArrays.blockaxes(A::AbstractQuasiArray{T,N}, d) where {T,N} |
| 113 | + @_inline_meta |
| 114 | + d::Integer <= N ? blockaxes(A)[d] : Base.OneTo(1) |
230 | 115 | end
|
231 | 116 |
|
| 117 | +@inline to_indices(A::AbstractQuasiArray, inds, I::Tuple{Block{1}, Vararg{Any}}) = |
| 118 | + (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) |
| 119 | +@inline to_indices(A::AbstractQuasiArray, inds, I::Tuple{BlockRange{1,R}, Vararg{Any}}) where R = |
| 120 | + (unblock(A, inds, I), to_indices(A, _maybetail(inds), tail(I))...) |
| 121 | +@inline to_indices(A::AbstractQuasiArray, inds, I::Tuple{BlockIndex{1}, Vararg{Any}}) = |
| 122 | + (inds[1][I[1]], to_indices(A, _maybetail(inds), tail(I))...) |
232 | 123 |
|
233 |
| -first(A::AffineMap) = first(A.range) |
234 |
| -last(A::AffineMap) = last(A.range) |
235 |
| - |
236 |
| -affine(a::AbstractQuasiVector, b::AbstractQuasiVector) = AffineMap(a, b) |
237 |
| -affine(a, b::AbstractQuasiVector) = affine(Inclusion(a), b) |
238 |
| -affine(a::AbstractQuasiVector, b) = affine(a, Inclusion(b)) |
239 |
| -affine(a, b) = affine(Inclusion(a), Inclusion(b)) |
240 |
| - |
241 |
| - |
242 |
| -# mapped vectors |
243 |
| -const AffineMappedQuasiVector = SubQuasiArray{<:Any, 1, <:Any, <:Tuple{AbstractAffineQuasiVector}} |
244 |
| -const AffineMappedQuasiMatrix = SubQuasiArray{<:Any, 2, <:Any, <:Tuple{AbstractAffineQuasiVector,Slice}} |
245 |
| - |
246 |
| -==(a::AffineMappedQuasiVector, b::AffineMappedQuasiVector) = parentindices(a) == parentindices(b) && parent(a) == parent(b) |
247 |
| - |
248 |
| -_sum(V::AffineMappedQuasiVector, ::Colon) = parentindices(V)[1].A \ sum(parent(V)) |
249 |
| - |
250 |
| -# pretty print for bases |
251 |
| -summary(io::IO, P::AffineMappedQuasiMatrix) = print(io, "$(parent(P)) affine mapped to $(parentindices(P)[1].x.domain)") |
252 |
| -summary(io::IO, P::AffineMappedQuasiVector) = print(io, "$(parent(P)) affine mapped to $(parentindices(P)[1].x.domain)") |
253 |
| - |
254 |
| -const QInfAxes = Union{Inclusion,AbstractAffineQuasiVector} |
255 |
| - |
256 |
| - |
257 |
| -sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes}) = V |
258 |
| -sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes,QInfAxes}) = V |
259 |
| -sub_materialize(_, V::AbstractQuasiArray, ::Tuple{Any,QInfAxes}) = V |
260 |
| -sub_materialize(_, V::AbstractQuasiArray, ::Tuple{QInfAxes,Any}) = V |
| 124 | +checkpoints(d::AbstractInterval{T}) where T = width(d) .* SVector{3,float(T)}(0.823972,0.01,0.3273484) .+ leftendpoint(d) |
| 125 | +checkpoints(x::Inclusion) = checkpoints(x.domain) |
| 126 | +checkpoints(A::AbstractQuasiMatrix) = checkpoints(axes(A,1)) |
261 | 127 |
|
262 | 128 |
|
263 | 129 | include("operators.jl")
|
264 | 130 | include("bases/bases.jl")
|
| 131 | +include("basisconcat.jl") |
265 | 132 |
|
266 | 133 | end
|
0 commit comments