@@ -2,7 +2,8 @@ module ContinuumArrays
2
2
using IntervalSets, LinearAlgebra, LazyArrays, FillArrays, BandedMatrices, QuasiArrays
3
3
import Base: @_inline_meta , @_propagate_inbounds_meta , axes, getindex, convert, prod, * , / , \ , + , - , == ,
4
4
IndexStyle, IndexLinear, == , OneTo, tail, similar, copyto!, copy, diff,
5
- first, last, show, isempty, findfirst, findlast, findall, Slice, union, minimum, maximum, sum, _sum
5
+ first, last, show, isempty, findfirst, findlast, findall, Slice, union, minimum, maximum, sum, _sum,
6
+ getproperty
6
7
import Base. Broadcast: materialize, BroadcastStyle, broadcasted
7
8
import LazyArrays: MemoryLayout, Applied, ApplyStyle, flatten, _flatten, colsupport,
8
9
adjointlayout, LdivApplyStyle, arguments, _arguments, call, broadcastlayout, lazy_getindex,
@@ -16,7 +17,7 @@ import QuasiArrays: cardinality, checkindex, QuasiAdjoint, QuasiTranspose, Inclu
16
17
ApplyQuasiArray, ApplyQuasiMatrix, LazyQuasiArrayApplyStyle, AbstractQuasiArrayApplyStyle,
17
18
LazyQuasiArray, LazyQuasiVector, LazyQuasiMatrix, LazyLayout, LazyQuasiArrayStyle, quasildivapplystyle
18
19
19
- export Spline, LinearSpline, HeavisideSpline, DiracDelta, Derivative, fullmaterialize, ℵ₁, Inclusion, Basis, WeightedBasis, grid, transform
20
+ export Spline, LinearSpline, HeavisideSpline, DiracDelta, Derivative, fullmaterialize, ℵ₁, Inclusion, Basis, WeightedBasis, grid, transform, affine
20
21
21
22
# ###
22
23
# Interval indexing support
@@ -70,7 +71,9 @@ BroadcastStyle(::Type{<:QuasiTranspose{<:Any,<:Inclusion{<:Any,<:AbstractInterva
70
71
# ##
71
72
72
73
# Affine map represents A*x .+ b
73
- struct AffineQuasiVector{T,AA,X,B} <: AbstractQuasiVector{T}
74
+ abstract type AbstractAffineQuasiVector{T,AA,X,B} <: AbstractQuasiVector{T} end
75
+
76
+ struct AffineQuasiVector{T,AA,X,B} <: AbstractAffineQuasiVector{T,AA,X,B}
74
77
A:: AA
75
78
x:: X
76
79
b:: B
@@ -84,22 +87,23 @@ AffineQuasiVector(x) = AffineQuasiVector(one(eltype(x)), x)
84
87
85
88
AffineQuasiVector (A, x:: AffineQuasiVector , b) = AffineQuasiVector (A* x. A, x. x, A* x. b .+ b)
86
89
87
- axes (A:: AffineQuasiVector ) = axes (A. x)
88
- getindex (A:: AffineQuasiVector , k:: Number ) = A. A* A. x[k] .+ A. b
89
- function getindex (A:: AffineQuasiVector , k:: Inclusion )
90
+ axes (A:: AbstractAffineQuasiVector ) = axes (A. x)
91
+ affine_getindex (A, k) = A. A* A. x[k] .+ A. b
92
+ getindex (A:: AbstractAffineQuasiVector , k:: Number ) = affine_getindex (A, k)
93
+ function getindex (A:: AbstractAffineQuasiVector , k:: Inclusion )
90
94
@boundscheck A. x[k] # throws bounds error if k ≠ x
91
95
A
92
96
end
93
97
94
- getindex (A:: AffineQuasiVector , :: Colon ) = copy (A)
98
+ getindex (A:: AbstractAffineQuasiVector , :: Colon ) = copy (A)
95
99
96
- copy (A:: AffineQuasiVector ) = A
100
+ copy (A:: AbstractAffineQuasiVector ) = A
97
101
98
- inbounds_getindex (A:: AffineQuasiVector {<:Any,<:Any,<:Inclusion} , k:: Number ) = A. A* k .+ A. b
99
- isempty (A:: AffineQuasiVector ) = isempty (A. x)
100
- == (a:: AffineQuasiVector , b:: AffineQuasiVector ) = a. A == b. A && a. x == b. x && a. b == b. b
102
+ inbounds_getindex (A:: AbstractAffineQuasiVector {<:Any,<:Any,<:Inclusion} , k:: Number ) = A. A* k .+ A. b
103
+ isempty (A:: AbstractAffineQuasiVector ) = isempty (A. x)
104
+ == (a:: AbstractAffineQuasiVector , b:: AbstractAffineQuasiVector ) = a. A == b. A && a. x == b. x && a. b == b. b
101
105
102
- BroadcastStyle (:: Type{<:AffineQuasiVector } ) = LazyQuasiArrayStyle {1} ()
106
+ BroadcastStyle (:: Type{<:AbstractAffineQuasiVector } ) = LazyQuasiArrayStyle {1} ()
103
107
104
108
for op in (:* , :\ , :+ , :- )
105
109
@eval broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof ($ op), a:: Number , x:: Inclusion ) = broadcast ($ op, a, AffineQuasiVector (x))
@@ -108,31 +112,74 @@ for op in(:/, :+, :-)
108
112
@eval broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof ($ op), x:: Inclusion , a:: Number ) = broadcast ($ op, AffineQuasiVector (x), a)
109
113
end
110
114
111
- broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (* ), a:: Number , x:: AffineQuasiVector ) = AffineQuasiVector (a, x)
112
- broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (\ ), a:: Number , x:: AffineQuasiVector ) = AffineQuasiVector (inv (a), x)
113
- broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (/ ), x:: AffineQuasiVector , a:: Number ) = AffineQuasiVector (inv (a), x)
114
- broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (+ ), a:: Number , x:: AffineQuasiVector ) = AffineQuasiVector (one (eltype (x)), x, a)
115
- broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (+ ), x:: AffineQuasiVector , b:: Number ) = AffineQuasiVector (one (eltype (x)), x, b)
116
- broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (- ), a:: Number , x:: AffineQuasiVector ) = AffineQuasiVector (- one (eltype (x)), x, a)
117
- broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (- ), x:: AffineQuasiVector , b:: Number ) = AffineQuasiVector (one (eltype (x)), x, - b)
115
+ broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (* ), a:: Number , x:: AbstractAffineQuasiVector ) = AffineQuasiVector (a, x)
116
+ broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (\ ), a:: Number , x:: AbstractAffineQuasiVector ) = AffineQuasiVector (inv (a), x)
117
+ broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (/ ), x:: AbstractAffineQuasiVector , a:: Number ) = AffineQuasiVector (inv (a), x)
118
+ broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (+ ), a:: Number , x:: AbstractAffineQuasiVector ) = AffineQuasiVector (one (eltype (x)), x, a)
119
+ broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (+ ), x:: AbstractAffineQuasiVector , b:: Number ) = AffineQuasiVector (one (eltype (x)), x, b)
120
+ broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (- ), a:: Number , x:: AbstractAffineQuasiVector ) = AffineQuasiVector (- one (eltype (x)), x, a)
121
+ broadcasted (:: LazyQuasiArrayStyle{1} , :: typeof (- ), x:: AbstractAffineQuasiVector , b:: Number ) = AffineQuasiVector (one (eltype (x)), x, - b)
118
122
119
- function checkindex (:: Type{Bool} , inds:: Inclusion{<:Any,<:AbstractInterval} , r:: AffineQuasiVector{<:Any,<:Any,<:Inclusion{<:Any,<:AbstractInterval}} )
123
+ function checkindex (:: Type{Bool} , inds:: Inclusion{<:Any,<:AbstractInterval} , r:: AbstractAffineQuasiVector )
120
124
@_propagate_inbounds_meta
121
125
isempty (r) | (checkindex (Bool, inds, first (r)) & checkindex (Bool, inds, last (r)))
122
126
end
123
127
124
- igetindex (d:: AffineQuasiVector , x) = d. A \ (x .- d. b)
128
+ affine_igetindex (d, x) = d. A \ (x .- d. b)
129
+ igetindex (d:: AbstractAffineQuasiVector , x) = affine_igetindex (d, x)
125
130
126
131
for find in (:findfirst , :findlast , :findall )
127
- @eval $ find (f:: Base.Fix2{typeof(isequal)} , d:: AffineQuasiVector ) = $ find (isequal (igetindex (d, f. x)), d. x)
132
+ @eval $ find (f:: Base.Fix2{typeof(isequal)} , d:: AbstractAffineQuasiVector ) = $ find (isequal (igetindex (d, f. x)), d. x)
133
+ end
134
+
135
+ minimum (d:: AbstractAffineQuasiVector ) = signbit (d. A) ? last (d) : first (d)
136
+ maximum (d:: AbstractAffineQuasiVector ) = signbit (d. A) ? first (d) : last (d)
137
+
138
+ union (d:: AbstractAffineQuasiVector ) = Inclusion (minimum (d).. maximum (d))
139
+
140
+
141
+ struct AffineMap{T,D,R} <: AbstractAffineQuasiVector{T,T,D,T}
142
+ domain:: D
143
+ range:: R
144
+ end
145
+
146
+ AffineMap (domain:: AbstractQuasiVector{T} , range:: AbstractQuasiVector{V} ) where {T,V} =
147
+ AffineMap {promote_type(T,V), typeof(domain),typeof(range)} (domain,range)
148
+
149
+ measure (x:: Inclusion ) = last (x)- first (x)
150
+
151
+ function getproperty (A:: AffineMap , d:: Symbol )
152
+ d == :x && return A. domain
153
+ d == :A && return measure (A. range)/ measure (A. domain)
154
+ d == :b && return (last (A. domain)* first (A. range) - first (A. domain)* last (A. range))/ measure (A. domain)
155
+ getfield (A, d)
156
+ end
157
+
158
+ function getindex (A:: AffineMap , k:: Number )
159
+ # ensure we exactly hit range
160
+ k == first (A. domain) && return first (A. range)
161
+ k == last (A. domain) && return last (A. range)
162
+ affine_getindex (A, k)
128
163
end
129
164
130
- minimum (d:: AffineQuasiVector{<:Real,<:Real,<:Inclusion} ) = signbit (d. A) ? last (d) : first (d)
131
- maximum (d:: AffineQuasiVector{<:Real,<:Real,<:Inclusion} ) = signbit (d. A) ? first (d) : last (d)
165
+ function igetindex (A:: AffineMap , k:: Number )
166
+ # ensure we exactly hit range
167
+ k == first (A. range) && return first (A. domain)
168
+ k == last (A. range) && return last (A. domain)
169
+ affine_igetindex (A, k)
170
+ end
171
+
172
+ first (A:: AffineMap ) = first (A. range)
173
+ last (A:: AffineMap ) = last (A. range)
174
+
175
+ affine (a:: AbstractQuasiVector , b:: AbstractQuasiVector ) = AffineMap (a, b)
176
+ affine (a, b:: AbstractQuasiVector ) = affine (Inclusion (a), b)
177
+ affine (a:: AbstractQuasiVector , b) = affine (a, Inclusion (b))
178
+ affine (a, b) = affine (Inclusion (a), Inclusion (b))
179
+
132
180
133
- union (d:: AffineQuasiVector{<:Real,<:Real,<:Inclusion} ) = Inclusion (minimum (d).. maximum (d))
134
181
135
- const QInfAxes = Union{Inclusion,AffineQuasiVector }
182
+ const QInfAxes = Union{Inclusion,AbstractAffineQuasiVector }
136
183
137
184
sub_materialize (_, V:: AbstractQuasiArray , :: Tuple{QInfAxes} ) = V
138
185
sub_materialize (_, V:: AbstractQuasiArray , :: Tuple{QInfAxes,QInfAxes} ) = V
0 commit comments