comparison LazyTensors/src/lazy_operations.jl @ 263:b577b5f64530 boundary_conditions

Add lazy elementwise operations for array with scalar
author Vidar Stiernström <vidar.stiernstrom@it.uu.se>
date Wed, 04 Dec 2019 19:02:18 +0100
parents d4cd4882ee9f
children 8ffd9c2e2119
comparison
equal deleted inserted replaced
262:f1e90a92ad74 263:b577b5f64530
36 # # Should we overload some other infix binary operator? 36 # # Should we overload some other infix binary operator?
37 # →(tm::TensorMapping{T,R,D}, o::AbstractArray{T,D}) where {T,R,D} = LazyTensorMappingApplication(tm,o) 37 # →(tm::TensorMapping{T,R,D}, o::AbstractArray{T,D}) where {T,R,D} = LazyTensorMappingApplication(tm,o)
38 # TODO: We need to be really careful about good error messages. 38 # TODO: We need to be really careful about good error messages.
39 # For example what happens if you try to multiply LazyTensorMappingApplication with a TensorMapping(wrong order)? 39 # For example what happens if you try to multiply LazyTensorMappingApplication with a TensorMapping(wrong order)?
40 40
41 41 """
42 42 LazyElementwiseOperation{T,D,Op,T1,T2} <: LazyArray{T,D}
43 """
44 LazyElementwiseOperation{T,D,Op, T1<:AbstractArray{T,D}, T2 <: AbstractArray{T,D}} <: AbstractArray{T,D}
45
46 Struct allowing for lazy evaluation of elementwise operations on AbstractArrays. 43 Struct allowing for lazy evaluation of elementwise operations on AbstractArrays.
47 44
48 A LazyElementwiseOperation contains two AbstractArrays of equal size, 45 A LazyElementwiseOperation contains two AbstractArrays of equal size,
49 together with an operation. The operations are carried out when the 46 together with an operation. The operations are carried out when the
50 LazyElementwiseOperation is indexed. 47 LazyElementwiseOperation is indexed.
51 """ 48 """
52 struct LazyElementwiseOperation{T,D,Op, T1<:AbstractArray{T,D}, T2 <: AbstractArray{T,D}} <: LazyArray{T,D} 49 struct LazyElementwiseOperation{T,D,Op, T1, T2} <: LazyArray{T,D}
53 a::T1 50 a::T1
54 b::T2 51 b::T2
55 52
56 @inline function LazyElementwiseOperation{T,D,Op}(a::T1,b::T2) where {T,D,Op, T1<:AbstractArray{T,D}, T2<:AbstractArray{T,D}} 53 @inline function LazyElementwiseOperation{T,D,Op}(a::T1,b::T2) where {T,D,Op, T1<:AbstractArray{T,D}, T2<:AbstractArray{T,D}}
57 @boundscheck if size(a) != size(b) 54 @boundscheck if size(a) != size(b)
58 throw(DimensionMismatch("dimensions must match")) 55 throw(DimensionMismatch("dimensions must match"))
59 end 56 end
60 return new{T,D,Op,T1,T2}(a,b) 57 return new{T,D,Op,T1,T2}(a,b)
61 end 58 end
59
60 @inline function LazyElementwiseOperation{T,D,Op}(a::T1,b::T2) where {T,D,Op, T1<:AbstractArray{T,D}, T2<:Real}
61 return new{T,D,Op,T1,T2}(a,b)
62 end
63
64 @inline function LazyElementwiseOperation{T,D,Op}(a::T1,b::T2) where {T,D,Op, T1<:Real, T2<:AbstractArray{T,D}}
65 return new{T,D,Op,T1,T2}(a,b)
66 end
62 end 67 end
63 # TODO: Move Op to be the first parameter? Compare to Binary operations 68 # TODO: Move Op to be the first parameter? Compare to Binary operations
64 69
65 Base.size(v::LazyElementwiseOperation) = size(v.a) 70 Base.size(v::LazyElementwiseOperation) = size(v.a)
66 71
67 # TODO: Make sure boundschecking is done properly and that the lenght of the vectors are equal 72 # TODO: Make sure boundschecking is done properly and that the lenght of the vectors are equal
68 # NOTE: Boundschecking in getindex functions now assumes that the size of the 73 # NOTE: Boundschecking in getindex functions now assumes that the size of the
69 # vectors in the LazyElementwiseOperation are the same size. If we remove the 74 # vectors in the LazyElementwiseOperation are the same size. If we remove the
70 # size assertion in the constructor we might have to handle 75 # size assertion in the constructor we might have to handle
71 # boundschecking differently. 76 # boundschecking differently.
72 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:+}, I::Vararg{Int,D}) where {T,D} 77 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:+,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:AbstractArray{T,D},T2<:AbstractArray{T,D}}
73 @boundscheck if !checkbounds(Bool,leo.a,I...) 78 @boundscheck if !checkbounds(Bool,leo.a,I...)
74 throw(BoundsError([leo],I...)) 79 throw(BoundsError([leo],I...))
75 end 80 end
76 return leo.a[I...] + leo.b[I...] 81 return leo.a[I...] + leo.b[I...]
77 end 82 end
78 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:-}, I::Vararg{Int,D}) where {T,D} 83
84 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:-,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:AbstractArray{T,D},T2<:AbstractArray{T,D}}
79 @boundscheck if !checkbounds(Bool,leo.a,I...) 85 @boundscheck if !checkbounds(Bool,leo.a,I...)
80 throw(BoundsError([leo],I...)) 86 throw(BoundsError([leo],I...))
81 end 87 end
82 return leo.a[I...] - leo.b[I...] 88 return leo.a[I...] - leo.b[I...]
83 end 89 end
84 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:*}, I::Vararg{Int,D}) where {T,D} 90
91 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:*,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:AbstractArray{T,D},T2<:AbstractArray{T,D}}
85 @boundscheck if !checkbounds(Bool,leo.a,I...) 92 @boundscheck if !checkbounds(Bool,leo.a,I...)
86 throw(BoundsError([leo],I...)) 93 throw(BoundsError([leo],I...))
87 end 94 end
88 return leo.a[I...] * leo.b[I...] 95 return leo.a[I...] * leo.b[I...]
89 end 96 end
90 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:/}, I::Vararg{Int,D}) where {T,D} 97
98 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:/,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:AbstractArray{T,D},T2<:AbstractArray{T,D}}
91 @boundscheck if !checkbounds(Bool,leo.a,I...) 99 @boundscheck if !checkbounds(Bool,leo.a,I...)
92 throw(BoundsError([leo],I...)) 100 throw(BoundsError([leo],I...))
93 end 101 end
94 return leo.a[I...] / leo.b[I...] 102 return leo.a[I...] / leo.b[I...]
103 end
104
105 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:+,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:AbstractArray{T,D},T2<:Real}
106 @boundscheck if !checkbounds(Bool,leo.a,I...)
107 throw(BoundsError([leo],I...))
108 end
109 return leo.a[I...] + leo.b
110 end
111
112 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:-,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:AbstractArray{T,D},T2<:Real}
113 @boundscheck if !checkbounds(Bool,leo.a,I...)
114 throw(BoundsError([leo],I...))
115 end
116 return leo.a[I...] - leo.b
117 end
118
119 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:*,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:AbstractArray{T,D},T2<:Real}
120 @boundscheck if !checkbounds(Bool,leo.a,I...)
121 throw(BoundsError([leo],I...))
122 end
123 return leo.a[I...] * leo.b
124 end
125
126 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:/,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:AbstractArray{T,D},T2<:Real}
127 @boundscheck if !checkbounds(Bool,leo.a,I...)
128 throw(BoundsError([leo],I...))
129 end
130 return leo.a[I...] / leo.b
131 end
132
133 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:+,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:Real,T2<:AbstractArray{T,D}}
134 @boundscheck if !checkbounds(Bool,leo.b,I...)
135 throw(BoundsError([leo],I...))
136 end
137 return leo.a + leo.b[I...]
138 end
139
140 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:-,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:Real,T2<:AbstractArray{T,D}}
141 @boundscheck if !checkbounds(Bool,leo.b,I...)
142 throw(BoundsError([leo],I...))
143 end
144 return leo.a - leo.b[I...]
145 end
146
147 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:*,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:Real,T2<:AbstractArray{T,D}}
148 @boundscheck if !checkbounds(Bool,leo.b,I...)
149 throw(BoundsError([leo],I...))
150 end
151 return leo.a * leo.b[I...]
152 end
153
154 Base.@propagate_inbounds @inline function Base.getindex(leo::LazyElementwiseOperation{T,D,:/,T1,T2}, I::Vararg{Int,D}) where {T,D,T1<:Real,T2<:AbstractArray{T,D}}
155 @boundscheck if !checkbounds(Bool,leo.b,I...)
156 throw(BoundsError([leo],I...))
157 end
158 return leo.a / leo.b[I...]
95 end 159 end
96 160
97 # Define lazy operations for AbstractArrays. Operations constructs a LazyElementwiseOperation which 161 # Define lazy operations for AbstractArrays. Operations constructs a LazyElementwiseOperation which
98 # can later be indexed into. Lazy operations are denoted by the usual operator followed by a tilde 162 # can later be indexed into. Lazy operations are denoted by the usual operator followed by a tilde
99 Base.@propagate_inbounds +̃(a::AbstractArray{T,D}, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:+}(a,b) 163 Base.@propagate_inbounds +̃(a::AbstractArray{T,D}, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:+}(a,b)
100 Base.@propagate_inbounds -̃(a::AbstractArray{T,D}, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:-}(a,b) 164 Base.@propagate_inbounds -̃(a::AbstractArray{T,D}, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:-}(a,b)
101 Base.@propagate_inbounds *̃(a::AbstractArray{T,D}, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:*}(a,b) 165 Base.@propagate_inbounds *̃(a::AbstractArray{T,D}, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:*}(a,b)
102 Base.@propagate_inbounds /̃(a::AbstractArray{T,D}, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:/}(a,b) 166 Base.@propagate_inbounds /̃(a::AbstractArray{T,D}, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:/}(a,b)
103 167
168 Base.@propagate_inbounds +̃(a::AbstractArray{T,D}, b::Real) where {T,D} = LazyElementwiseOperation{T,D,:+}(a,b)
169 Base.@propagate_inbounds -̃(a::AbstractArray{T,D}, b::Real) where {T,D} = LazyElementwiseOperation{T,D,:-}(a,b)
170 Base.@propagate_inbounds *̃(a::AbstractArray{T,D}, b::Real) where {T,D} = LazyElementwiseOperation{T,D,:*}(a,b)
171 Base.@propagate_inbounds /̃(a::AbstractArray{T,D}, b::Real) where {T,D} = LazyElementwiseOperation{T,D,:/}(a,b)
172
173 Base.@propagate_inbounds +̃(a::Real, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:+}(a,b)
174 Base.@propagate_inbounds -̃(a::Real, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:-}(a,b)
175 Base.@propagate_inbounds *̃(a::Real, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:*}(a,b)
176 Base.@propagate_inbounds /̃(a::Real, b::AbstractArray{T,D}) where {T,D} = LazyElementwiseOperation{T,D,:/}(a,b)
177
178
179
104 # NOTE: Är det knas att vi har till exempel * istället för .* ?? 180 # NOTE: Är det knas att vi har till exempel * istället för .* ??
105 # Oklart om det ens går att lösa.. 181 # Oklart om det ens går att lösa..
106 Base.@propagate_inbounds Base.:+(a::LazyArray{T,D}, b::LazyArray{T,D}) where {T,D} = a +̃ b 182 Base.@propagate_inbounds Base.:+(a::LazyArray{T,D}, b::LazyArray{T,D}) where {T,D} = a +̃ b
107 Base.@propagate_inbounds Base.:+(a::LazyArray{T,D}, b::AbstractArray{T,D}) where {T,D} = a +̃ b 183 Base.@propagate_inbounds Base.:+(a::LazyArray{T,D}, b::AbstractArray{T,D}) where {T,D} = a +̃ b
108 Base.@propagate_inbounds Base.:+(a::AbstractArray{T,D}, b::LazyArray{T,D}) where {T,D} = a +̃ b 184 Base.@propagate_inbounds Base.:+(a::AbstractArray{T,D}, b::LazyArray{T,D}) where {T,D} = a +̃ b