@@ -38,12 +38,30 @@ function InnerProductStyle(::Type{TT}) where {TT <: AbstractTensorMap}
3838 return InnerProductStyle (spacetype (TT))
3939end
4040
41+ # storage types and promotion system
42+ # ----------------------------------
4143@doc """
4244 storagetype(t::AbstractTensorMap) -> Type{A<:AbstractVector}
4345 storagetype(T::Type{<:AbstractTensorMap}) -> Type{A<:AbstractVector}
4446
4547Return the type of vector that stores the data of a tensor.
48+ If this is not overloaded for a given tensor type, the default value of `storagetype(scalartype(t))` is returned.
49+
50+ See also [`similarstoragetype`](@ref).
4651""" storagetype
52+ storagetype (t) = storagetype (typeof (t))
53+ function storagetype (:: Type{T} ) where {T <: AbstractTensorMap }
54+ if T isa Union
55+ # attempt to be slightly more specific by promoting unions
56+ Ma = storagetype (T. a)
57+ Mb = storagetype (T. b)
58+ return promote_storagetype (Ma, Mb)
59+ else
60+ # fallback definition by using scalartype
61+ return similarstoragetype (scalartype (T))
62+ end
63+ end
64+ storagetype (T:: Type ) = throw (MethodError (storagetype, T))
4765
4866# storage type determination and promotion - hooks for specializing
4967# the default implementation tries to leverarge inference and `similar`
@@ -69,6 +87,8 @@ appropriate storage types. Additionally this registers the default storage type
6987 used in constructor-like calls, and therefore will return the exact same type for a `DenseVector`
7088 input. The latter is used in `similar`-like calls, and therefore will return the type of calling
7189 `similar` on the given `DenseVector`, which need not coincide with the original type.
90+
91+ See also [`promote_storagetype`](@ref).
7292""" similarstoragetype
7393
7494# implement in type domain
@@ -102,6 +122,74 @@ similarstoragetype(::Type{D}, ::Type{T}) where {D <: AbstractDict{<:Sector, <:Ab
102122# default storage type for numbers
103123similarstoragetype (:: Type{T} ) where {T <: Number } = Vector{T}
104124
125+ @doc """
126+ promote_storagetype([T], A, B, C...)
127+ promote_storagetype([T], TA, TB, TC...)
128+
129+ Determine an appropriate storage type for the combination of tensors `A` and `B`, or tensors of type `TA` and `TB`.
130+ Optionally, a scalartype `T` for the destination can be supplied that might differ from the inputs.
131+ """ promote_storagetype
132+
133+ @inline promote_storagetype (A:: AbstractTensorMap , B:: AbstractTensorMap , Cs:: AbstractTensorMap... ) =
134+ promote_storagetype (storagetype (A), storagetype (B), map (storagetype, Cs)... )
135+ @inline promote_storagetype (:: Type{T} , A:: AbstractTensorMap , B:: AbstractTensorMap , Cs:: AbstractTensorMap... ) where {T <: Number } =
136+ promote_storagetype (similarstoragetype (A, T), similarstoragetype (B, T), map (Base. Fix2 (similarstoragetype, T), Cs)... )
137+
138+ @inline function promote_storagetype (
139+ :: Type{A} , :: Type{B} , Cs:: Type{<:AbstractTensorMap} ...
140+ ) where {A <: AbstractTensorMap , B <: AbstractTensorMap }
141+ return promote_storagetype (storagetype (A), storagetype (B), map (storagetype, Cs)... )
142+ end
143+ @inline function promote_storagetype (
144+ :: Type{T} , :: Type{A} , :: Type{B} , Cs:: Type{<:AbstractTensorMap} ...
145+ ) where {T <: Number , A <: AbstractTensorMap , B <: AbstractTensorMap }
146+ return promote_storagetype (similarstoragetype (A, T), similarstoragetype (B, T), map (Base. Fix2 (similarstoragetype, T), Cs)... )
147+ end
148+
149+ # promotion system in the same spirit as base/promotion.jl
150+ promote_storagetype (:: Type{Base.Bottom} , :: Type{Base.Bottom} ) = Base. Bottom
151+ promote_storagetype (:: Type{T} , :: Type{T} ) where {T} = T
152+ promote_storagetype (:: Type{T} , :: Type{Base.Bottom} ) where {T} = T
153+ promote_storagetype (:: Type{Base.Bottom} , :: Type{T} ) where {T} = T
154+
155+ function promote_storagetype (:: Type{T} , :: Type{S} ) where {T, S}
156+ @inline
157+ # Try promote_storage_rule in both orders. Typically only one is defined,
158+ # and there is a fallback returning Bottom below, so the common case is
159+ # promote_storagetype(T, S) =>
160+ # promote_storage_result(T, S, result, Bottom) =>
161+ # typejoin(result, Bottom) => result
162+ return promote_storage_result (T, S, promote_storage_rule (T, S), promote_storage_rule (S, T))
163+ end
164+
165+ @inline promote_storagetype (T, S, U) = promote_storagetype (promote_storagetype (T, S), U)
166+ @inline promote_storagetype (T, S, U, V... ) = promote_storagetype (promote_storagetype (T, S), U, V... )
167+
168+ @doc """
169+ promote_storage_rule(type1, type2)
170+
171+ Specifies what type should be used by [`promote_storagetype`](@ref) when given values of types `type1` and
172+ `type2`. This function should not be called directly, but should have definitions added to
173+ it for new types as appropriate.
174+ """ promote_storage_rule
175+
176+ promote_storage_rule (:: Type , :: Type ) = Base. Bottom
177+ # Define some methods to avoid needing to enumerate unrelated possibilities when presented
178+ # with Type{<:T}, and return a value in general accordance with the result given by promote_type
179+ promote_storage_rule (:: Type{Base.Bottom} , slurp... ) = Base. Bottom
180+ promote_storage_rule (:: Type{Base.Bottom} , :: Type{Base.Bottom} , slurp... ) = Base. Bottom # not strictly necessary, since the next method would match unambiguously anyways
181+ promote_storage_rule (:: Type{Base.Bottom} , :: Type{T} , slurp... ) where {T} = T
182+ promote_storage_rule (:: Type{T} , :: Type{Base.Bottom} , slurp... ) where {T} = T
183+
184+ promote_storage_result (:: Type , :: Type , :: Type{T} , :: Type{S} ) where {T, S} = (@inline ; promote_storagetype (T, S))
185+ # If no promote_storage_rule is defined, both directions give Bottom => error
186+ promote_storage_result (T:: Type , S:: Type , :: Type{Base.Bottom} , :: Type{Base.Bottom} ) =
187+ throw (ArgumentError (" No promotion rule defined for storagetype `$T ` and `$S `" ))
188+
189+ # promotion rules for common vector types
190+ promote_storage_rule (:: Type{T} , :: Type{S} ) where {T <: DenseVector , S <: DenseVector } =
191+ T === S ? T : throw (ArgumentError (" No promotion rule defined for storagetype `$T ` and `$S `" ))
192+
105193# tensor characteristics: space and index information
106194# -----------------------------------------------------
107195"""
224312# tensor characteristics: work on instances and pass to type
225313# ------------------------------------------------------------
226314InnerProductStyle (t:: AbstractTensorMap ) = InnerProductStyle (typeof (t))
227- storagetype (t) = storagetype (typeof (t))
228- storagetype (T:: Type ) = throw (MethodError (storagetype, T))
315+
229316blocktype (t:: AbstractTensorMap ) = blocktype (typeof (t))
230317
231318numout (t:: AbstractTensorMap ) = numout (typeof (t))
0 commit comments