Skip to content

Commit fbfb2b7

Browse files
authored
[ITensors] Better constructors from arrays (#1696)
1 parent 6bac903 commit fbfb2b7

5 files changed

Lines changed: 88 additions & 22 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ITensors"
22
uuid = "9136182c-28ba-11e9-034c-db9fb085ebd5"
33
authors = ["Matthew Fishman <mfishman@flatironinstitute.org>", "Miles Stoudenmire <mstoudenmire@flatironinstitute.org>"]
4-
version = "0.9.17"
4+
version = "0.9.18"
55

66
[deps]
77
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

src/itensor.jl

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ function emptyITensor((::Type{ElT}) = EmptyNumber) where {ElT <: Number}
306306
return itensor(EmptyTensor(ElT, ()))
307307
end
308308

309-
using NDTensors.TypeParameterAccessors: set_eltype, type_parameters, specify_type_parameters
309+
using NDTensors: AllowAlias, NeverAlias
310310
"""
311311
ITensor([ElT::Type, ]A::AbstractArray, inds)
312312
ITensor([ElT::Type, ]A::AbstractArray, inds::Index...)
@@ -350,17 +350,35 @@ T[i => 1, j => 1] == 3.3
350350
"""
351351
function ITensor(
352352
as::AliasStyle,
353-
eltype::Type{<:Number},
353+
elt::Type{<:Number},
354354
A::AbstractArray{<:Number},
355355
inds::Indices;
356356
kwargs...,
357357
)
358-
length(A) dim(inds) && throw(
359-
DimensionMismatch(
360-
"In ITensor(::AbstractArray, inds), length of AbstractArray ($(length(A))) must match total dimension of IndexSet ($(dim(inds)))",
361-
),
362-
)
363-
data = set_eltype(typeof(A), eltype)(as, A)
358+
check_dims(A, inds)
359+
# Other cases already handle when `elt ≡ eltype(A)`
360+
# so here we only need to handle when they differ
361+
# (which always involves a copy).
362+
# This is equivalent to `copy!(similar(A, elt), A)`.
363+
data = AbstractArray{elt}(A)
364+
return itensor(Dense(data), inds)
365+
end
366+
367+
function ITensor(
368+
as::AliasStyle,
369+
eltype::Type{T},
370+
A::AbstractArray{T},
371+
inds::Indices;
372+
kwargs...,
373+
) where {T <: Number}
374+
check_dims(A, inds)
375+
data = if as AllowAlias()
376+
A
377+
elseif as NeverAlias()
378+
copy(A)
379+
else
380+
error("Unknown AliasStyle: $as")
381+
end
364382
return itensor(Dense(data), inds)
365383
end
366384

@@ -381,6 +399,15 @@ function ITensor(
381399
return ITensor(as, eltype, Matrix(A), inds; kwargs...)
382400
end
383401

402+
function check_dims(A::AbstractArray, inds::Indices)
403+
length(A) dim(inds) && throw(
404+
DimensionMismatch(
405+
"In ITensor(::AbstractArray, inds), length of AbstractArray ($(length(A))) must match total dimension of IndexSet ($(dim(inds)))",
406+
),
407+
)
408+
return nothing
409+
end
410+
384411
function ITensor(
385412
as::AliasStyle, eltype::Type{<:Number}, A::AbstractArray{<:Number}, is...; kwargs...
386413
)
@@ -470,13 +497,36 @@ The version `diagitensor` might output an ITensor whose storage data
470497
is an alias of the input vector data in order to minimize operations.
471498
"""
472499
function diag_itensor(
473-
as::AliasStyle, eltype::Type{<:Number}, v::AbstractVector{<:Number}, is::Indices
500+
as::AliasStyle, elt::Type{<:Number}, v::AbstractVector{<:Number}, is::Indices
474501
)
502+
check_diag_dims(v, is)
503+
# Other cases already handle when `elt ≡ eltype(v)`
504+
# so here we only need to handle when they differ
505+
# (which always involves a copy).
506+
# This is equivalent to `copy!(similar(v, elt), v)`.
507+
data = AbstractVector{elt}(v)
508+
return itensor(Diag(data), is)
509+
end
510+
511+
function diag_itensor(
512+
as::AliasStyle, elt::Type{T}, v::AbstractVector{T}, is::Indices
513+
) where {T <: Number}
514+
check_diag_dims(v, is)
515+
data = if as AllowAlias()
516+
v
517+
elseif as NeverAlias()
518+
copy(v)
519+
else
520+
error("Unknown AliasStyle: $as")
521+
end
522+
return itensor(Diag(data), is)
523+
end
524+
525+
function check_diag_dims(v::AbstractVector, is::Indices)
475526
length(v) mindim(is) && error(
476527
"Length of vector for diagonal must equal minimum of the dimension of the input indices",
477528
)
478-
data = set_eltype(typeof(v), eltype)(as, v)
479-
return itensor(Diag(data), is)
529+
return nothing
480530
end
481531

482532
function diag_itensor(
@@ -671,16 +721,6 @@ zero(T::ITensor)::ITensor = itensor(zero(tensor(T)))
671721
# Construct from Array
672722
#
673723

674-
# Helper functions for different view behaviors
675-
# TODO: Move to NDTensors.jl
676-
function (arraytype::Type{<:AbstractArray})(::NeverAlias, A::AbstractArray)
677-
return specify_type_parameters(arraytype, type_parameters(A))(A)
678-
end
679-
680-
function (arraytype::Type{<:AbstractArray})(::AllowAlias, A::AbstractArray)
681-
return convert(specify_type_parameters(arraytype, type_parameters(A)), A)
682-
end
683-
684724
"""
685725
Array{ElT, N}(T::ITensor, i:Index...)
686726
Array{ElT}(T::ITensor, i:Index...)

test/base/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
[deps]
22
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
33
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
4+
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
45
HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
56
ITensors = "9136182c-28ba-11e9-034c-db9fb085ebd5"
7+
JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb"
68
NDTensors = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf"
79
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
810
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"

test/base/test_diagitensor.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,15 @@ using Test
106106
end
107107
end
108108

109+
@testset "diag_itensor constructor from Range" begin
110+
t = diag_itensor(1:d, i, j)
111+
@test ITensors.data(t) == 1:d
112+
@test ITensors.data(t) isa Vector{Float64}
113+
114+
t = diag_itensor(Int, 1:d, i, j)
115+
@test ITensors.data(t) 1:d
116+
end
117+
109118
@testset "reductions (sum, prod)" for elt in (
110119
Float32, Float64, Complex{Float32}, Complex{Float64},
111120
)

test/base/test_itensor.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,21 @@ end
995995
@test storage(T) isa NDTensors.Dense{Float64}
996996
end
997997

998+
@testset "Construct from Range" begin
999+
# https://github.com/ITensor/ITensors.jl/issues/1691
1000+
1001+
# Automatic conversion to float.
1002+
i, j = Index.((2, 2))
1003+
t = ITensor(1:4, (i, j))
1004+
@test ITensors.data(t) == 1:4
1005+
@test ITensors.data(t) isa Vector{Float64}
1006+
1007+
# Preserve integer element type.
1008+
i, j = Index.((2, 2))
1009+
t = ITensor(Int, 1:4, (i, j))
1010+
@test ITensors.data(t) 1:4
1011+
end
1012+
9981013
@testset "ITensor Array constructor view behavior" begin
9991014
d = 2
10001015
i = Index(d)

0 commit comments

Comments
 (0)