comparison src/LazyTensors/lazy_tensor_operations.jl @ 1954:b0915f43b122 feature/sbp_operators/laplace_curvilinear

Merge feature/grids/geometry_functions
author Jonatan Werpers <jonatan@werpers.com>
date Sat, 08 Feb 2025 09:38:58 +0100
parents ed50eec18365
children
comparison
equal deleted inserted replaced
1953:835b1dcee38e 1954:b0915f43b122
50 50
51 range_size(tmt::TensorTranspose) = domain_size(tmt.tm) 51 range_size(tmt::TensorTranspose) = domain_size(tmt.tm)
52 domain_size(tmt::TensorTranspose) = range_size(tmt.tm) 52 domain_size(tmt::TensorTranspose) = range_size(tmt.tm)
53 53
54 54
55 struct ElementwiseTensorOperation{Op,T,R,D,TT<:NTuple{N, LazyTensor{T,R,D}} where N} <: LazyTensor{T,R,D} 55 """
56 TensorNegation{T,R,D,...} <: LazyTensor{T,R,D}
57
58 The negation of a LazyTensor.
59 """
60 struct TensorNegation{T,R,D,TM<:LazyTensor{T,R,D}} <: LazyTensor{T,R,D}
61 tm::TM
62 end
63
64 apply(tm::TensorNegation, v, I...) = -apply(tm.tm, v, I...)
65 apply_transpose(tm::TensorNegation, v, I...) = -apply_transpose(tm.tm, v, I...)
66
67 range_size(tm::TensorNegation) = range_size(tm.tm)
68 domain_size(tm::TensorNegation) = domain_size(tm.tm)
69
70
71 """
72 TensorSum{T,R,D,...} <: LazyTensor{T,R,D}
73
74 The lazy sum of 2 or more lazy tensors.
75 """
76 struct TensorSum{T,R,D,TT<:NTuple{N, LazyTensor{T,R,D}} where N} <: LazyTensor{T,R,D}
56 tms::TT 77 tms::TT
57 78
58 function ElementwiseTensorOperation{Op,T,R,D}(tms::TT) where {Op,T,R,D, TT<:NTuple{N, LazyTensor{T,R,D}} where N} 79 function TensorSum{T,R,D}(tms::TT) where {T,R,D, TT<:NTuple{N, LazyTensor{T,R,D}} where N}
59 @boundscheck map(tms) do tm 80 @boundscheck map(tms) do tm
60 check_domain_size(tm, domain_size(tms[1])) 81 check_domain_size(tm, domain_size(tms[1]))
61 check_range_size(tm, range_size(tms[1])) 82 check_range_size(tm, range_size(tms[1]))
62 end 83 end
63 84
64 return new{Op,T,R,D,TT}(tms) 85 return new{T,R,D,TT}(tms)
65 end 86 end
66 end 87 end
67 # TBD: Can we introduce negation of LazyTensors? It could be done generically 88
68 # with a ScalingTensor but also using specializations for specific tensor 89 """
69 # types. This would allow simplification of ElementwiseTensorOperation to 90 TensorSum(ts::Vararg{LazyTensor})
70 # TensorSum. The implementation of `-` can be done using negation and the 91
71 # TensorSum type. We should make sure this doesn't impact the efficiency of 92 The lazy sum of the tensors `ts`.
72 # for example SATs. 93 """
73 94 function TensorSum(ts::Vararg{LazyTensor})
74 95 T = eltype(ts[1])
75 function ElementwiseTensorOperation{:+}(ts::Vararg{LazyTensor}) 96 R = range_dim(ts[1])
76 return ElementwiseTensorOperation{:+,eltype(ts[1]), range_dim(ts[1]), domain_dim(ts[1])}(ts) 97 D = domain_dim(ts[1])
77 end 98 return TensorSum{T,R,D}(ts)
78 99 end
79 # The following methods for :+ are intended to reduce the depth of the tree of operations in some caes 100
80 function ElementwiseTensorOperation{:+}(t1::ElementwiseTensorOperation{:+}, t2::ElementwiseTensorOperation{:+}) 101 function apply(tmBinOp::TensorSum{T,R,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,R}) where {T,R,D}
81 ElementwiseTensorOperation{:+}(t1.tms..., t2.tms...) 102 return sum(tmBinOp.tms) do tm
82 end
83
84 function ElementwiseTensorOperation{:+}(t1::ElementwiseTensorOperation{:+}, t2::LazyTensor)
85 ElementwiseTensorOperation{:+}(t1.tms..., t2)
86 end
87
88 function ElementwiseTensorOperation{:+}(t1::LazyTensor, t2::ElementwiseTensorOperation{:+})
89 ElementwiseTensorOperation{:+}(t1, t2.tms...)
90 end
91
92 function ElementwiseTensorOperation{:-}(t1::LazyTensor, t2::LazyTensor)
93 return ElementwiseTensorOperation{:-,eltype(t1), range_dim(t1), domain_dim(t1)}((t1,t2))
94 end
95
96 function apply(tmBinOp::ElementwiseTensorOperation{:+,T,R,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,R}) where {T,R,D}
97 vs = map(tmBinOp.tms) do tm
98 apply(tm,v,I...) 103 apply(tm,v,I...)
99 end 104 end
100 105 end
101 return +(vs...) 106
102 end 107 function apply_transpose(tmBinOp::TensorSum{T,R,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,R}) where {T,R,D}
103 function apply(tmBinOp::ElementwiseTensorOperation{:-,T,R,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,R}) where {T,R,D} 108 return sum(tmBinOp.tms) do tm
104 apply(tmBinOp.tms[1], v, I...) - apply(tmBinOp.tms[2], v, I...) 109 apply_transpose(tm,v,I...)
105 end 110 end
106 111 end
107 range_size(tmBinOp::ElementwiseTensorOperation) = range_size(tmBinOp.tms[1]) 112
108 domain_size(tmBinOp::ElementwiseTensorOperation) = domain_size(tmBinOp.tms[1]) 113 range_size(tmBinOp::TensorSum) = range_size(tmBinOp.tms[1])
114 domain_size(tmBinOp::TensorSum) = domain_size(tmBinOp.tms[1])
109 115
110 116
111 """ 117 """
112 TensorComposition{T,R,K,D} 118 TensorComposition{T,R,K,D}
113 119
155 return tmi 161 return tmi
156 end 162 end
157 163
158 Base.:*(a::T, tm::LazyTensor{T}) where T = TensorComposition(ScalingTensor{T,range_dim(tm)}(a,range_size(tm)), tm) 164 Base.:*(a::T, tm::LazyTensor{T}) where T = TensorComposition(ScalingTensor{T,range_dim(tm)}(a,range_size(tm)), tm)
159 Base.:*(tm::LazyTensor{T}, a::T) where T = a*tm 165 Base.:*(tm::LazyTensor{T}, a::T) where T = a*tm
160 Base.:-(tm::LazyTensor) = (-one(eltype(tm)))*tm
161 166
162 """ 167 """
163 InflatedTensor{T,R,D} <: LazyTensor{T,R,D} 168 InflatedTensor{T,R,D} <: LazyTensor{T,R,D}
164 169
165 An inflated `LazyTensor` with dimensions added before and after its actual dimensions. 170 An inflated `LazyTensor` with dimensions added before and after its actual dimensions.
203 itm.tm, 208 itm.tm,
204 IdentityTensor(itm.after.size..., after.size...), 209 IdentityTensor(itm.after.size..., after.size...),
205 ) 210 )
206 end 211 end
207 212
208 InflatedTensor(before::IdentityTensor, tm::LazyTensor{T}) where T = InflatedTensor(before,tm,IdentityTensor{T}()) 213 InflatedTensor(before::IdentityTensor, tm::LazyTensor) = InflatedTensor(before,tm,IdentityTensor{eltype(tm)}())
209 InflatedTensor(tm::LazyTensor{T}, after::IdentityTensor) where T = InflatedTensor(IdentityTensor{T}(),tm,after) 214 InflatedTensor(tm::LazyTensor, after::IdentityTensor) = InflatedTensor(IdentityTensor{eltype(tm)}(),tm,after)
210 # Resolve ambiguity between the two previous methods 215 # Resolve ambiguity between the two previous methods
211 InflatedTensor(I1::IdentityTensor{T}, I2::IdentityTensor{T}) where T = InflatedTensor(I1,I2,IdentityTensor{T}()) 216 InflatedTensor(I1::IdentityTensor, I2::IdentityTensor) = InflatedTensor(I1,I2,IdentityTensor{promote_type(eltype(I1), eltype(I2))}())
212 217
213 # TODO: Implement some pretty printing in terms of ⊗. E.g InflatedTensor(I(3),B,I(2)) -> I(3)⊗B⊗I(2) 218 # TODO: Implement some pretty printing in terms of ⊗. E.g InflatedTensor(I(3),B,I(2)) -> I(3)⊗B⊗I(2)
214 219
215 function range_size(itm::InflatedTensor) 220 function range_size(itm::InflatedTensor)
216 return concatenate_tuples( 221 return concatenate_tuples(
297 itm2 = InflatedTensor(IdentityTensor{T}(domain_size(tm1)),tm2) 302 itm2 = InflatedTensor(IdentityTensor{T}(domain_size(tm1)),tm2)
298 303
299 return itm1∘itm2 304 return itm1∘itm2
300 end 305 end
301 306
302 LazyOuterProduct(t1::IdentityTensor{T}, t2::IdentityTensor{T}) where T = IdentityTensor{T}(t1.size...,t2.size...) 307 LazyOuterProduct(t1::IdentityTensor, t2::IdentityTensor) = IdentityTensor{promote_type(eltype(t1),eltype(t2))}(t1.size...,t2.size...)
303 LazyOuterProduct(t1::LazyTensor, t2::IdentityTensor) = InflatedTensor(t1, t2) 308 LazyOuterProduct(t1::LazyTensor, t2::IdentityTensor) = InflatedTensor(t1, t2)
304 LazyOuterProduct(t1::IdentityTensor, t2::LazyTensor) = InflatedTensor(t1, t2) 309 LazyOuterProduct(t1::IdentityTensor, t2::LazyTensor) = InflatedTensor(t1, t2)
305 310
306 LazyOuterProduct(tms::Vararg{LazyTensor}) = foldl(LazyOuterProduct, tms) 311 LazyOuterProduct(tms::Vararg{LazyTensor}) = foldl(LazyOuterProduct, tms)
307 312