Skip to content

Commit

Permalink
[ITensor] [ENHANCEMENT] Generalize ITensor constructor a little (#1039)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtfishman authored Jan 6, 2023
1 parent e3e8f5b commit 2f7c173
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 3 deletions.
4 changes: 3 additions & 1 deletion NDTensors/src/generic_tensor_operations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ end
# Trait returning true if the two tensors or storage types can
# contract with each other.
@traitdef CanContract{X,Y}
@traitimpl CanContract{X,Y} < -can_contract(X, Y)
#! format: off
@traitimpl CanContract{X,Y} <- can_contract(X, Y)
#! format: on

# Assume storage types can contract with each other
can_contract(T1::Type, T2::Type) = true
Expand Down
8 changes: 7 additions & 1 deletion src/indexset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ NDTensors.dim(is::IndexSet, pos::Int) = dim(is[pos])
Return a new Indices with the indices daggered (flip
all of the arrow directions).
"""
dag(is::Indices) = map(i -> dag(i), is)
function dag(is::Indices)
return isempty(is) ? is : map(i -> dag(i), is)
end

# TODO: move to NDTensors
NDTensors.dim(is::Tuple, pos::Integer) = dim(is[pos])
Expand Down Expand Up @@ -539,6 +541,10 @@ function replaceinds(is::Indices, rep_inds::Pair{<:Index,<:Index}...)
return replaceinds(is, zip(rep_inds...)...)
end

# Handle case of empty indices being replaced
replaceinds(is::Indices) = is
replaceinds(is::Indices, rep_inds::Tuple{}) = is

function replaceinds(is::Indices, rep_inds::Vector{<:Pair{<:Index,<:Index}})
return replaceinds(is, rep_inds...)
end
Expand Down
12 changes: 11 additions & 1 deletion src/itensor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ function ITensor(
as::AliasStyle,
eltype::Type{<:Number},
A::AbstractArray{<:Number},
inds::Indices{Index{Int}};
inds::Indices;
kwargs...,
)
length(A) dim(inds) && throw(
Expand All @@ -349,6 +349,16 @@ function ITensor(
return itensor(Dense(data), inds)
end

function ITensor(
as::AliasStyle, eltype::Type{<:Number}, A::AbstractArray{<:Number}, inds; kwargs...
)
is = indices(inds)
if !isa(is, Indices)
error("Indices $inds are not valid for constructing an ITensor.")
end
return ITensor(as, eltype, A, is; kwargs...)
end

# Convert `Adjoint` to `Matrix`
function ITensor(
as::AliasStyle, eltype::Type{<:Number}, A::Adjoint, inds::Indices{Index{Int}}; kwargs...
Expand Down
7 changes: 7 additions & 0 deletions test/indexset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,13 @@ using Compat
end
end
end

@testset "dag" begin
is = [Index(2), Index(3)]
@test is == dag(is)
is = Index[]
@test dag(is) == Index[]
end
end

nothing
23 changes: 23 additions & 0 deletions test/itensor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,25 @@ end
T[i => 1, j => 1] = 3.3
@test M[1, 1] == 1
@test T[i => 1, j => 1] == 3.3

# Empty indices
A = randn(1)
T = itensor(A, Index[])
@test A[] == T[]
T = itensor(A, Index[], Index[])
@test A[] == T[]
T = itensor(A, Any[])
@test A[] == T[]

A = randn(1, 1)
T = itensor(A, Index[])
@test A[] == T[]
T = itensor(A, Index[], Index[])
@test A[] == T[]
T = itensor(A, Any[], Any[])
@test A[] == T[]

@test_throws ErrorException itensor(rand(1), Int[1])
end

@testset "Construct from AbstractArray" begin
Expand Down Expand Up @@ -1138,6 +1157,10 @@ end
@test hasinds(rA1, s2, l, l')
@test hasinds(A1, s1, l, l')

@test replaceinds(A1, [] => []) == A1
@test replaceinds(A1, ()) == A1
@test replaceinds(A1) == A1

# Pair notation (like Julia's replace function)
rA1 = replaceind(A1, s1 => s2)
@test hasinds(rA1, s2, l, l')
Expand Down

0 comments on commit 2f7c173

Please sign in to comment.