diff --git a/NDTensors/Project.toml b/NDTensors/Project.toml index 280e3f502c..30a8b7007c 100644 --- a/NDTensors/Project.toml +++ b/NDTensors/Project.toml @@ -1,7 +1,7 @@ name = "NDTensors" uuid = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf" authors = ["Matthew Fishman "] -version = "0.3.49" +version = "0.3.50" [deps] Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" diff --git a/NDTensors/src/abstractarray/set_types.jl b/NDTensors/src/abstractarray/set_types.jl index 49702b7b6f..823c2fa11e 100644 --- a/NDTensors/src/abstractarray/set_types.jl +++ b/NDTensors/src/abstractarray/set_types.jl @@ -1,4 +1,5 @@ -using .TypeParameterAccessors: TypeParameterAccessors, set_ndims +using .TypeParameterAccessors: TypeParameterAccessors + """ # Do we still want to define things like this? TODO: Use `Accessors.jl` notation: @@ -14,13 +15,3 @@ TODO: Use `Accessors.jl` notation: function TypeParameterAccessors.set_ndims(numbertype::Type{<:Number}, ndims) return numbertype end - -""" -`set_indstype` should be overloaded for -types with structured dimensions, -like `OffsetArrays` or named indices -(such as ITensors). -""" -function set_indstype(arraytype::Type{<:AbstractArray}, dims::Tuple) - return set_ndims(arraytype, length(dims)) -end diff --git a/NDTensors/src/abstractarray/similar.jl b/NDTensors/src/abstractarray/similar.jl index 2a751f48d1..440b1b86b8 100644 --- a/NDTensors/src/abstractarray/similar.jl +++ b/NDTensors/src/abstractarray/similar.jl @@ -1,4 +1,5 @@ -using .TypeParameterAccessors: IsWrappedArray, unwrap_array_type, set_eltype +using Base: DimOrInd, Dims, OneTo +using .TypeParameterAccessors: IsWrappedArray, unwrap_array_type, set_eltype, similartype ## Custom `NDTensors.similar` implementation. ## More extensive than `Base.similar`. @@ -96,58 +97,3 @@ end # Use the `size` to determine the dimensions # NDTensors.similar similar(array::AbstractArray) = NDTensors.similar(typeof(array), size(array)) - -## similartype - -function similartype(arraytype::Type{<:AbstractArray}, eltype::Type, dims::Tuple) - return similartype(similartype(arraytype, eltype), dims) -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, eltype::Type -) where {ArrayT; !IsWrappedArray{ArrayT}} - return set_eltype(arraytype, eltype) -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, dims::Tuple -) where {ArrayT; !IsWrappedArray{ArrayT}} - return set_indstype(arraytype, dims) -end - -function similartype(arraytype::Type{<:AbstractArray}, dims::DimOrInd...) - return similartype(arraytype, dims) -end - -function similartype(arraytype::Type{<:AbstractArray}) - return similartype(arraytype, eltype(arraytype)) -end - -## Wrapped arrays -@traitfn function similartype( - arraytype::Type{ArrayT}, eltype::Type -) where {ArrayT; IsWrappedArray{ArrayT}} - return similartype(unwrap_array_type(arraytype), eltype) -end - -@traitfn function similartype( - arraytype::Type{ArrayT}, dims::Tuple -) where {ArrayT; IsWrappedArray{ArrayT}} - return similartype(unwrap_array_type(arraytype), dims) -end - -# This is for uniform `Diag` storage which uses -# a Number as the data type. -# TODO: Delete this when we change to using a -# `FillArray` instead. This is a stand-in -# to make things work with the current design. -function similartype(numbertype::Type{<:Number}) - return numbertype -end - -# Instances -function similartype(array::AbstractArray, eltype::Type, dims...) - return similartype(typeof(array), eltype, dims...) -end -similartype(array::AbstractArray, eltype::Type) = similartype(typeof(array), eltype) -similartype(array::AbstractArray, dims...) = similartype(typeof(array), dims...) diff --git a/NDTensors/src/blocksparse/blockdims.jl b/NDTensors/src/blocksparse/blockdims.jl index bb68c6144a..8de0439417 100644 --- a/NDTensors/src/blocksparse/blockdims.jl +++ b/NDTensors/src/blocksparse/blockdims.jl @@ -1,3 +1,5 @@ +using .TypeParameterAccessors: TypeParameterAccessors + """ BlockDim @@ -18,7 +20,9 @@ const BlockDims{N} = NTuple{N,BlockDim} Base.ndims(ds::Type{<:BlockDims{N}}) where {N} = N -similartype(::Type{<:BlockDims}, ::Type{Val{N}}) where {N} = BlockDims{N} +function TypeParameterAccessors.similartype(::Type{<:BlockDims}, ::Type{Val{N}}) where {N} + return BlockDims{N} +end Base.copy(ds::BlockDims) = ds diff --git a/NDTensors/src/blocksparse/blocksparsetensor.jl b/NDTensors/src/blocksparse/blocksparsetensor.jl index 896fafdb91..ce515e4c00 100644 --- a/NDTensors/src/blocksparse/blocksparsetensor.jl +++ b/NDTensors/src/blocksparse/blocksparsetensor.jl @@ -1,3 +1,5 @@ +using .TypeParameterAccessors: similartype + # # BlockSparseTensor (Tensor using BlockSparse storage) # diff --git a/NDTensors/src/blocksparse/diagblocksparse.jl b/NDTensors/src/blocksparse/diagblocksparse.jl index a8b46b17cb..42882102d7 100644 --- a/NDTensors/src/blocksparse/diagblocksparse.jl +++ b/NDTensors/src/blocksparse/diagblocksparse.jl @@ -1,3 +1,5 @@ +using .TypeParameterAccessors: similartype + export DiagBlockSparse, DiagBlockSparseTensor # DiagBlockSparse can have either Vector storage, in which case diff --git a/NDTensors/src/blocksparse/similar.jl b/NDTensors/src/blocksparse/similar.jl index d9e87bd67c..5a8395b1a7 100644 --- a/NDTensors/src/blocksparse/similar.jl +++ b/NDTensors/src/blocksparse/similar.jl @@ -1,3 +1,5 @@ +using .TypeParameterAccessors: similartype + # NDTensors.similar function similar(storagetype::Type{<:BlockSparse}, blockoffsets::BlockOffsets, dims::Tuple) data = similar(datatype(storagetype), nnz(blockoffsets, dims)) diff --git a/NDTensors/src/diag/similar.jl b/NDTensors/src/diag/similar.jl index 368d396480..bf7113aab7 100644 --- a/NDTensors/src/diag/similar.jl +++ b/NDTensors/src/diag/similar.jl @@ -1,3 +1,5 @@ +using NDTensors.TypeParameterAccessors: TypeParameterAccessors + # NDTensors.similar function similar(storagetype::Type{<:Diag}, dims::Dims) return setdata(storagetype, similar(datatype(storagetype), mindim(dims))) @@ -5,7 +7,7 @@ end # TODO: Redesign UniformDiag to make it handled better # by generic code. -function similartype(storagetype::Type{<:UniformDiag}, eltype::Type) +function TypeParameterAccessors.similartype(storagetype::Type{<:UniformDiag}, eltype::Type) # This will also set the `datatype`. return set_eltype(storagetype, eltype) end diff --git a/NDTensors/src/dims.jl b/NDTensors/src/dims.jl index 663309c8b6..c49895f18b 100644 --- a/NDTensors/src/dims.jl +++ b/NDTensors/src/dims.jl @@ -1,4 +1,5 @@ using .DiagonalArrays: DiagonalArrays +using .TypeParameterAccessors: TypeParameterAccessors export dense, dims, dim, mindim, diaglength @@ -52,7 +53,7 @@ dim_to_stride(ds, k::Int) = dim_to_strides(ds)[k] # code (it helps to construct a Tuple(::NTuple{N,Int}) where the # only known thing for dispatch is a concrete type such # as Dims{4}) -similartype(::Type{<:Dims}, ::Type{Val{N}}) where {N} = Dims{N} +TypeParameterAccessors.similartype(::Type{<:Dims}, ::Type{Val{N}}) where {N} = Dims{N} # This is to help with ITensor compatibility dim(i::Int) = i diff --git a/NDTensors/src/empty/empty.jl b/NDTensors/src/empty/empty.jl index 645019dacd..3aeda04710 100644 --- a/NDTensors/src/empty/empty.jl +++ b/NDTensors/src/empty/empty.jl @@ -1,3 +1,4 @@ +using .TypeParameterAccessors: TypeParameterAccessors, set_eltype, similartype # # Represents a tensor order that could be set to any order. @@ -5,18 +6,20 @@ struct EmptyOrder end -function similartype(StoreT::Type{<:TensorStorage{EmptyNumber}}, ElT::Type) +function TypeParameterAccessors.similartype( + StoreT::Type{<:TensorStorage{EmptyNumber}}, ElT::Type +) return set_eltype(StoreT, ElT) end -function similartype( +function TypeParameterAccessors.similartype( StoreT::Type{<:TensorStorage{EmptyNumber}}, DataT::Type{<:AbstractArray} ) return set_datatype(StoreT, DataT) end ## TODO fix this similartype to use set eltype for BlockSparse -function similartype( +function TypeParameterAccessors.similartype( ::Type{StoreT}, ::Type{ElT} ) where {StoreT<:BlockSparse{EmptyNumber},ElT} return BlockSparse{ElT,similartype(datatype(StoreT), ElT),ndims(StoreT)} diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/TypeParameterAccessors.jl b/NDTensors/src/lib/TypeParameterAccessors/src/TypeParameterAccessors.jl index 01f750a164..adafed6567 100644 --- a/NDTensors/src/lib/TypeParameterAccessors/src/TypeParameterAccessors.jl +++ b/NDTensors/src/lib/TypeParameterAccessors/src/TypeParameterAccessors.jl @@ -13,6 +13,7 @@ include("set_parameters.jl") include("specify_parameters.jl") include("default_parameters.jl") include("base/abstractarray.jl") +include("base/similartype.jl") include("base/array.jl") include("base/linearalgebra.jl") include("base/stridedviews.jl") diff --git a/NDTensors/src/lib/TypeParameterAccessors/src/base/similartype.jl b/NDTensors/src/lib/TypeParameterAccessors/src/base/similartype.jl new file mode 100644 index 0000000000..c51bf80b6e --- /dev/null +++ b/NDTensors/src/lib/TypeParameterAccessors/src/base/similartype.jl @@ -0,0 +1,62 @@ +""" +`set_indstype` should be overloaded for +types with structured dimensions, +like `OffsetArrays` or named indices +(such as ITensors). +""" +function set_indstype(arraytype::Type{<:AbstractArray}, dims::Tuple) + return set_ndims(arraytype, length(dims)) +end + +function similartype(arraytype::Type{<:AbstractArray}, eltype::Type, dims::Tuple) + return similartype(similartype(arraytype, eltype), dims) +end + +@traitfn function similartype( + arraytype::Type{ArrayT}, eltype::Type +) where {ArrayT; !IsWrappedArray{ArrayT}} + return set_eltype(arraytype, eltype) +end + +@traitfn function similartype( + arraytype::Type{ArrayT}, dims::Tuple +) where {ArrayT; !IsWrappedArray{ArrayT}} + return set_indstype(arraytype, dims) +end + +function similartype(arraytype::Type{<:AbstractArray}, dims::Base.DimOrInd...) + return similartype(arraytype, dims) +end + +function similartype(arraytype::Type{<:AbstractArray}) + return similartype(arraytype, eltype(arraytype)) +end + +## Wrapped arrays +@traitfn function similartype( + arraytype::Type{ArrayT}, eltype::Type +) where {ArrayT; IsWrappedArray{ArrayT}} + return similartype(unwrap_array_type(arraytype), eltype) +end + +@traitfn function similartype( + arraytype::Type{ArrayT}, dims::Tuple +) where {ArrayT; IsWrappedArray{ArrayT}} + return similartype(unwrap_array_type(arraytype), dims) +end + +# This is for uniform `Diag` storage which uses +# a Number as the data type. +# TODO: Delete this when we change to using a +# `FillArray` instead. This is a stand-in +# to make things work with the current design. +function similartype(numbertype::Type{<:Number}) + return numbertype +end + +# Instances +function similartype(array::AbstractArray, eltype::Type, dims...) + return similartype(typeof(array), eltype, dims...) +end +similartype(array::AbstractArray, eltype::Type) = similartype(typeof(array), eltype) +similartype(array::AbstractArray, dims...) = similartype(typeof(array), dims...) diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/runtests.jl b/NDTensors/src/lib/TypeParameterAccessors/test/runtests.jl index b7260866f0..7c5ffc416d 100644 --- a/NDTensors/src/lib/TypeParameterAccessors/test/runtests.jl +++ b/NDTensors/src/lib/TypeParameterAccessors/test/runtests.jl @@ -5,5 +5,6 @@ using Test: @testset include("test_defaults.jl") include("test_custom_types.jl") include("test_wrappers.jl") + include("test_similartype.jl") end end diff --git a/NDTensors/src/lib/TypeParameterAccessors/test/test_similartype.jl b/NDTensors/src/lib/TypeParameterAccessors/test/test_similartype.jl new file mode 100644 index 0000000000..703f9ba1e1 --- /dev/null +++ b/NDTensors/src/lib/TypeParameterAccessors/test/test_similartype.jl @@ -0,0 +1,15 @@ +@eval module $(gensym()) +using Test: @test, @test_broken, @testset +using LinearAlgebra: Adjoint +using NDTensors.TypeParameterAccessors: similartype +@testset "TypeParameterAccessors similartype" begin + @test similartype(Array, Float64, (2, 2)) == Matrix{Float64} + # TODO: Is this a good definition? Probably it should be left unspecified. + @test similartype(Array) == Array{Any} + @test similartype(Array, Float64) == Array{Float64} + @test similartype(Array, (2, 2)) == Matrix + @test similartype(Adjoint{Float32,Matrix{Float32}}, Float64, (2, 2, 2)) == + Array{Float64,3} + @test similartype(Adjoint{Float32,Matrix{Float32}}, Float64) == Matrix{Float64} +end +end diff --git a/NDTensors/src/tensor/set_types.jl b/NDTensors/src/tensor/set_types.jl index f92c8109e9..e17683ed17 100644 --- a/NDTensors/src/tensor/set_types.jl +++ b/NDTensors/src/tensor/set_types.jl @@ -17,7 +17,7 @@ end # TODO: Modify the `storagetype` according to `inds`, such as the dimensions? # TODO: Make a version that accepts `indstype::Type`? -function set_indstype(tensortype::Type{<:Tensor}, inds::Tuple) +function TypeParameterAccessors.set_indstype(tensortype::Type{<:Tensor}, inds::Tuple) return Tensor{eltype(tensortype),length(inds),storagetype(tensortype),typeof(inds)} end diff --git a/NDTensors/src/tensor/similar.jl b/NDTensors/src/tensor/similar.jl index 0eb56d969b..266500cf17 100644 --- a/NDTensors/src/tensor/similar.jl +++ b/NDTensors/src/tensor/similar.jl @@ -1,3 +1,5 @@ +using .TypeParameterAccessors: TypeParameterAccessors, set_indstype, similartype + # NDTensors.similar similar(tensor::Tensor) = setstorage(tensor, similar(storage(tensor))) @@ -56,11 +58,11 @@ function Base.similar(tensor::Tensor, eltype::Type, dims::Dims) return NDTensors.similar(tensor, eltype, dims) end -function similartype(tensortype::Type{<:Tensor}, eltype::Type) +function TypeParameterAccessors.similartype(tensortype::Type{<:Tensor}, eltype::Type) return set_storagetype(tensortype, similartype(storagetype(tensortype), eltype)) end -function similartype(tensortype::Type{<:Tensor}, dims::Tuple) +function TypeParameterAccessors.similartype(tensortype::Type{<:Tensor}, dims::Tuple) tensortype_new_inds = set_indstype(tensortype, dims) # Need to pass `dims` in case that information is needed to make a storage type, # for example `BlockSparse` needs the number of dimensions. diff --git a/NDTensors/src/tensorstorage/similar.jl b/NDTensors/src/tensorstorage/similar.jl index d309b32727..374a3235f3 100644 --- a/NDTensors/src/tensorstorage/similar.jl +++ b/NDTensors/src/tensorstorage/similar.jl @@ -1,3 +1,5 @@ +using .TypeParameterAccessors: TypeParameterAccessors, set_ndims, similartype + # NDTensors.similar similar(storage::TensorStorage) = setdata(storage, NDTensors.similar(data(storage))) @@ -61,14 +63,16 @@ Base.similar(storage::TensorStorage, eltype::Type) = NDTensors.similar(storage, ## Base.similar(storage::TensorStorage, dims::Dims...) = NDTensors.similar(storage, dims...) ## Base.similar(storage::TensorStorage, dims::DimOrInd...) = NDTensors.similar(storage, dims...) -function similartype(storagetype::Type{<:TensorStorage}, eltype::Type) +function TypeParameterAccessors.similartype( + storagetype::Type{<:TensorStorage}, eltype::Type +) # TODO: Don't convert to an `AbstractVector` with `set_ndims(datatype, 1)`, once we support # more general data types. # return set_datatype(storagetype, NDTensors.similartype(datatype(storagetype), eltype)) return set_datatype(storagetype, set_ndims(similartype(datatype(storagetype), eltype), 1)) end -function similartype(storagetype::Type{<:TensorStorage}, dims::Tuple) +function TypeParameterAccessors.similartype(storagetype::Type{<:TensorStorage}, dims::Tuple) # TODO: In the future, set the dimensions of the data type based on `dims`, once # more general data types beyond `AbstractVector` are supported. # `similartype` unwraps any wrapped data.