comparison src/LazyTensors/lazy_tensor_operations.jl @ 1002:271aa6ae1055 refactor/lazy_tensors

Split out a file for tensor types
author Jonatan Werpers <jonatan@werpers.com>
date Fri, 18 Mar 2022 22:18:04 +0100
parents a3df203861d3
children becd95ba0fce
comparison
equal deleted inserted replaced
1001:a3df203861d3 1002:271aa6ae1055
1 # TBD: Is there a good way to split this file?
2 # TODO: Split out functions for composition
3 # TODO: We need to be really careful about good error messages. 1 # TODO: We need to be really careful about good error messages.
4 # TODO: Go over type parameters 2 # TODO: Go over type parameters
3
5 4
6 """ 5 """
7 LazyTensorApplication{T,R,D} <: LazyArray{T,R} 6 LazyTensorApplication{T,R,D} <: LazyArray{T,R}
8 7
9 Struct for lazy application of a LazyTensor. Created using `*`. 8 Struct for lazy application of a LazyTensor. Created using `*`.
52 apply_transpose(tmt::LazyTensorTranspose{T,R,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,R}) where {T,R,D} = apply(tmt.tm, v, I...) 51 apply_transpose(tmt::LazyTensorTranspose{T,R,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,R}) where {T,R,D} = apply(tmt.tm, v, I...)
53 52
54 range_size(tmt::LazyTensorTranspose) = domain_size(tmt.tm) 53 range_size(tmt::LazyTensorTranspose) = domain_size(tmt.tm)
55 domain_size(tmt::LazyTensorTranspose) = range_size(tmt.tm) 54 domain_size(tmt::LazyTensorTranspose) = range_size(tmt.tm)
56 55
57 # TODO: Rename this 56
58 struct LazyTensorBinaryOperation{Op,T,R,D,T1<:LazyTensor{T,R,D},T2<:LazyTensor{T,R,D}} <: LazyTensor{T,D,R} 57 struct LazyTensorBinaryOperation{Op,T,R,D,T1<:LazyTensor{T,R,D},T2<:LazyTensor{T,R,D}} <: LazyTensor{T,D,R}
59 tm1::T1 58 tm1::T1
60 tm2::T2 59 tm2::T2
61 60
62 function LazyTensorBinaryOperation{Op,T,R,D}(tm1::T1,tm2::T2) where {Op,T,R,D, T1<:LazyTensor{T,R,D},T2<:LazyTensor{T,R,D}} 61 function LazyTensorBinaryOperation{Op,T,R,D}(tm1::T1,tm2::T2) where {Op,T,R,D, T1<:LazyTensor{T,R,D},T2<:LazyTensor{T,R,D}}
98 97
99 function apply_transpose(c::LazyTensorComposition{T,R,K,D}, v::AbstractArray{<:Any,R}, I::Vararg{Any,D}) where {T,R,K,D} 98 function apply_transpose(c::LazyTensorComposition{T,R,K,D}, v::AbstractArray{<:Any,R}, I::Vararg{Any,D}) where {T,R,K,D}
100 apply_transpose(c.t2, c.t1'*v, I...) 99 apply_transpose(c.t2, c.t1'*v, I...)
101 end 100 end
102 101
103
104 """
105 LazyLinearMap{T,R,D,...}(A, range_indicies, domain_indicies)
106
107 LazyTensor defined by the AbstractArray A. `range_indicies` and `domain_indicies` define which indicies of A should
108 be considerd the range and domain of the LazyTensor. Each set of indices must be ordered in ascending order.
109
110 For instance, if A is a m x n matrix, and range_size = (1,), domain_size = (2,), then the LazyLinearMap performs the
111 standard matrix-vector product on vectors of size n.
112 """
113 struct LazyLinearMap{T,R,D, RD, AA<:AbstractArray{T,RD}} <: LazyTensor{T,R,D}
114 A::AA
115 range_indicies::NTuple{R,Int}
116 domain_indicies::NTuple{D,Int}
117
118 function LazyLinearMap(A::AA, range_indicies::NTuple{R,Int}, domain_indicies::NTuple{D,Int}) where {T,R,D, RD, AA<:AbstractArray{T,RD}}
119 if !issorted(range_indicies) || !issorted(domain_indicies)
120 throw(DomainError("range_indicies and domain_indicies must be sorted in ascending order"))
121 end
122
123 return new{T,R,D,RD,AA}(A,range_indicies,domain_indicies)
124 end
125 end
126
127 range_size(llm::LazyLinearMap) = size(llm.A)[[llm.range_indicies...]]
128 domain_size(llm::LazyLinearMap) = size(llm.A)[[llm.domain_indicies...]]
129
130 function apply(llm::LazyLinearMap{T,R,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,R}) where {T,R,D}
131 view_index = ntuple(i->:,ndims(llm.A))
132 for i ∈ 1:R
133 view_index = Base.setindex(view_index, Int(I[i]), llm.range_indicies[i])
134 end
135 A_view = @view llm.A[view_index...]
136 return sum(A_view.*v)
137 end
138
139 function apply_transpose(llm::LazyLinearMap{T,R,D}, v::AbstractArray{<:Any,R}, I::Vararg{Any,D}) where {T,R,D}
140 apply(LazyLinearMap(llm.A, llm.domain_indicies, llm.range_indicies), v, I...)
141 end
142
143
144 """
145 IdentityTensor{T,D} <: LazyTensor{T,D,D}
146
147 The lazy identity LazyTensor for a given size. Usefull for building up higher dimensional tensor mappings from lower
148 dimensional ones through outer products. Also used in the Implementation for InflatedLazyTensor.
149 """
150 struct IdentityTensor{T,D} <: LazyTensor{T,D,D}
151 size::NTuple{D,Int}
152 end
153
154 IdentityTensor{T}(size::NTuple{D,Int}) where {T,D} = IdentityTensor{T,D}(size)
155 IdentityTensor{T}(size::Vararg{Int,D}) where {T,D} = IdentityTensor{T,D}(size)
156 IdentityTensor(size::Vararg{Int,D}) where D = IdentityTensor{Float64,D}(size)
157
158 range_size(tmi::IdentityTensor) = tmi.size
159 domain_size(tmi::IdentityTensor) = tmi.size
160
161 apply(tmi::IdentityTensor{T,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,D}) where {T,D} = v[I...]
162 apply_transpose(tmi::IdentityTensor{T,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,D}) where {T,D} = v[I...]
163 102
164 """ 103 """
165 LazyTensorComposition(tm, tmi::IdentityTensor) 104 LazyTensorComposition(tm, tmi::IdentityTensor)
166 LazyTensorComposition(tmi::IdentityTensor, tm) 105 LazyTensorComposition(tmi::IdentityTensor, tm)
167 106
180 function LazyTensorComposition(tm::IdentityTensor{T,D}, tmi::IdentityTensor{T,D}) where {T,D} 119 function LazyTensorComposition(tm::IdentityTensor{T,D}, tmi::IdentityTensor{T,D}) where {T,D}
181 @boundscheck check_domain_size(tm, range_size(tmi)) 120 @boundscheck check_domain_size(tm, range_size(tmi))
182 return tmi 121 return tmi
183 end 122 end
184 123
185 """
186 ScalingTensor{T,D} <: LazyTensor{T,D,D}
187
188 A lazy tensor that scales its input with `λ`.
189 """
190 struct ScalingTensor{T,D} <: LazyTensor{T,D,D}
191 λ::T
192 size::NTuple{D,Int}
193 end
194
195 LazyTensors.apply(tm::ScalingTensor{T,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,D}) where {T,D} = tm.λ*v[I...]
196 LazyTensors.apply_transpose(tm::ScalingTensor{T,D}, v::AbstractArray{<:Any,D}, I::Vararg{Any,D}) where {T,D} = tm.λ*v[I...]
197
198 LazyTensors.range_size(m::ScalingTensor) = m.size
199 LazyTensors.domain_size(m::ScalingTensor) = m.size
200 124
201 """ 125 """
202 InflatedLazyTensor{T,R,D} <: LazyTensor{T,R,D} 126 InflatedLazyTensor{T,R,D} <: LazyTensor{T,R,D}
203 127
204 An inflated `LazyTensor` with dimensions added before and afer its actual dimensions. 128 An inflated `LazyTensor` with dimensions added before and afer its actual dimensions.
219 D_after = domain_dim(after) 143 D_after = domain_dim(after)
220 D = D_before+D_middle+D_after 144 D = D_before+D_middle+D_after
221 return new{T,R,D,D_before,R_middle,D_middle,D_after, typeof(tm)}(before, tm, after) 145 return new{T,R,D,D_before,R_middle,D_middle,D_after, typeof(tm)}(before, tm, after)
222 end 146 end
223 end 147 end
148
224 """ 149 """
225 InflatedLazyTensor(before, tm, after) 150 InflatedLazyTensor(before, tm, after)
226 InflatedLazyTensor(before,tm) 151 InflatedLazyTensor(before,tm)
227 InflatedLazyTensor(tm,after) 152 InflatedLazyTensor(tm,after)
228 153