From 1a2712ca6c630ebd0f062fa9d1dff38bcb20f968 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Sat, 11 Jan 2025 19:48:52 -0500 Subject: [PATCH 1/9] Add missing functionality like tagging and priming --- src/ITensorBase.jl | 40 +++++++++++++++++++++++++++++++++++++--- src/quirks.jl | 4 ++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/quirks.jl diff --git a/src/ITensorBase.jl b/src/ITensorBase.jl index f5b931b..62695ee 100644 --- a/src/ITensorBase.jl +++ b/src/ITensorBase.jl @@ -1,5 +1,6 @@ module ITensorBase +using Accessors: @set using MapBroadcast: Mapped using NamedDimsArrays: NamedDimsArrays, @@ -14,16 +15,29 @@ using NamedDimsArrays: name, named, nameddimsindices, + setname, unname +const Tag = String +const TagSet = Set{Tag} + +tagset(tags::String) = Set(filter(!isempty, String.(strip.(split(tags, ","))))) + @kwdef struct IndexName <: AbstractName id::UInt64 = rand(UInt64) plev::Int = 0 - tags::Set{String} = Set{String}() - namedtags::Dict{Symbol,String} = Dict{Symbol,String}() + tags::TagSet = TagSet() end NamedDimsArrays.randname(n::IndexName) = IndexName() +tags(n::IndexName) = n.tags +settags(n::IndexName, tags) = @set n.tags = tags +addtags(n::IndexName, ts) = settags(n, tags(n) ∪ tagset(ts)) + +plev(n::IndexName) = n.plev +setprime(n::IndexName, plev) = @set n.plev = plev +prime(n::IndexName) = setprime(n, plev(n) + 1) + struct IndexVal{Value<:Integer} <: AbstractNamedInteger{Value,IndexName} value::Value name::IndexName @@ -41,7 +55,15 @@ struct Index{T,Value<:AbstractUnitRange{T}} <: AbstractNamedUnitRange{T,Value,In name::IndexName end -Index(length::Int) = Index(Base.OneTo(length), IndexName()) +Index(length::Int; kwargs...) = Index(Base.OneTo(length), IndexName(; kwargs...)) +function Index(length::Int, tags::String; kwargs...) + return Index(Base.OneTo(length), IndexName(; kwargs..., tags=tagset(tags))) +end + +tags(i::Index) = tags(name(i)) +addtags(i::Index, tags) = setname(i, addtags(name(i), tags)) +prime(i::Index) = setname(i, prime(name(i))) +Base.adjoint(i::Index) = prime(i) # Interface # TODO: Overload `Base.parent` instead. @@ -127,9 +149,21 @@ using Accessors: @set setdenamed(a::ITensor, denamed) = (@set a.parent = denamed) setdenamed!(a::ITensor, denamed) = (a.parent = denamed) +function ITensor(elt::Type, I1::Index, I_rest::Index...) + I = (I1, I_rest...) + # TODO: Use `FillArrays.Zeros`. + return ITensor(zeros(elt, length.(dename.(I))...), I) +end + function ITensor(I1::Index, I_rest::Index...) I = (I1, I_rest...) return ITensor(Zeros{UnspecifiedZero}(length.(dename.(I))...), I) end +function ITensor() + return ITensor(Zeros{UnspecifiedZero}(), ()) +end + +include("quirks.jl") + end diff --git a/src/quirks.jl b/src/quirks.jl new file mode 100644 index 0000000..1fad08f --- /dev/null +++ b/src/quirks.jl @@ -0,0 +1,4 @@ +# TODO: Define this properly. +dag(i::Index) = i +hasqns(i::Index) = false +dim(i::Index) = length(i) From bb400c713ebc8c4dd1a3333d338bb35f82e48cb2 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Sun, 12 Jan 2025 09:40:51 -0500 Subject: [PATCH 2/9] Printing --- src/ITensorBase.jl | 54 ++++++++++++++++++++++++++++++++++++++++++++-- src/quirks.jl | 10 ++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/ITensorBase.jl b/src/ITensorBase.jl index 62695ee..379769b 100644 --- a/src/ITensorBase.jl +++ b/src/ITensorBase.jl @@ -23,21 +23,43 @@ const TagSet = Set{Tag} tagset(tags::String) = Set(filter(!isempty, String.(strip.(split(tags, ","))))) +function tagsstring(tags::TagSet) + str = "" + length(tags) == 0 && return str + tags_vec = collect(tags) + for n in 1:(length(tags_vec) - 1) + str *= "$(tags_vec[n])," + end + str *= "$(tags_vec[end])" + return str +end + @kwdef struct IndexName <: AbstractName id::UInt64 = rand(UInt64) - plev::Int = 0 tags::TagSet = TagSet() + plev::Int = 0 end NamedDimsArrays.randname(n::IndexName) = IndexName() +id(n::IndexName) = n.id tags(n::IndexName) = n.tags +plev(n::IndexName) = n.plev + settags(n::IndexName, tags) = @set n.tags = tags addtags(n::IndexName, ts) = settags(n, tags(n) ∪ tagset(ts)) -plev(n::IndexName) = n.plev setprime(n::IndexName, plev) = @set n.plev = plev prime(n::IndexName) = setprime(n, plev(n) + 1) +function Base.show(io::IO, i::IndexName) + idstr = "id=$(id(i) % 1000)" + tagsstr = !isempty(tags(i)) ? "|\"$(tagsstring(tags(i)))\"" : "" + primestr = primestring(plev(i)) + str = "IndexName($(idstr)$(tagsstr))$(primestr)" + print(io, str) + return nothing +end + struct IndexVal{Value<:Integer} <: AbstractNamedInteger{Value,IndexName} value::Value name::IndexName @@ -60,7 +82,12 @@ function Index(length::Int, tags::String; kwargs...) return Index(Base.OneTo(length), IndexName(; kwargs..., tags=tagset(tags))) end +# TODO: Define for `NamedDimsArrays.NamedViewIndex`. +id(i::Index) = id(name(i)) tags(i::Index) = tags(name(i)) +plev(i::Index) = plev(name(i)) + +# TODO: Define for `NamedDimsArrays.NamedViewIndex`. addtags(i::Index, tags) = setname(i, addtags(name(i), tags)) prime(i::Index) = setname(i, prime(name(i))) Base.adjoint(i::Index) = prime(i) @@ -73,6 +100,29 @@ NamedDimsArrays.name(i::Index) = i.name # Constructor NamedDimsArrays.named(i::AbstractUnitRange, name::IndexName) = Index(i, name) +function primestring(plev) + if plev < 0 + return " (warning: prime level $plev is less than 0)" + end + if plev == 0 + return "" + elseif plev > 3 + return "'$plev" + else + return "'"^plev + end +end + +function Base.show(io::IO, i::Index) + lenstr = "length=$(dename(length(i)))" + idstr = "|id=$(id(i) % 1000)" + tagsstr = !isempty(tags(i)) ? "|\"$(tagsstring(tags(i)))\"" : "" + primestr = primestring(plev(i)) + str = "Index($(lenstr)$(idstr)$(tagsstr))$(primestr)" + print(io, str) + return nothing +end + struct NoncontiguousIndex{T,Value<:AbstractVector{T}} <: AbstractNamedVector{T,Value,IndexName} value::Value diff --git a/src/quirks.jl b/src/quirks.jl index 1fad08f..c7b0c2e 100644 --- a/src/quirks.jl +++ b/src/quirks.jl @@ -1,4 +1,12 @@ # TODO: Define this properly. dag(i::Index) = i +# TODO: Deprecate. +dim(i::Index) = dename(length(i)) +# TODO: Define this properly. hasqns(i::Index) = false -dim(i::Index) = length(i) +inds(a::ITensor) = nameddimsindices(a) +# TODO: Deprecate. +itensor(parent::AbstractArray, nameddimsindices) = ITensor(parent, nameddimsindices) +function itensor(parent::AbstractArray, i1::Index, i_rest::Index...) + return ITensor(parent, (i1, i_rest...)) +end From 850039095defaf4a2fbfb3ada3c5d3dbf20bb95c Mon Sep 17 00:00:00 2001 From: mtfishman Date: Wed, 15 Jan 2025 20:42:56 -0500 Subject: [PATCH 3/9] Exports, Broadcast.extrude --- src/ITensorBase.jl | 2 ++ src/quirks.jl | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/ITensorBase.jl b/src/ITensorBase.jl index 379769b..bf4f8ea 100644 --- a/src/ITensorBase.jl +++ b/src/ITensorBase.jl @@ -1,5 +1,7 @@ module ITensorBase +export ITensor, Index + using Accessors: @set using MapBroadcast: Mapped using NamedDimsArrays: diff --git a/src/quirks.jl b/src/quirks.jl index c7b0c2e..0227d72 100644 --- a/src/quirks.jl +++ b/src/quirks.jl @@ -10,3 +10,5 @@ itensor(parent::AbstractArray, nameddimsindices) = ITensor(parent, nameddimsindi function itensor(parent::AbstractArray, i1::Index, i_rest::Index...) return ITensor(parent, (i1, i_rest...)) end + +Base.Broadcast.extrude(a::AbstractITensor) = a From e6df7a7798005690b6bf3a8a5a97cf90b88b1c0a Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 16 Jan 2025 18:35:47 -0500 Subject: [PATCH 4/9] More missing functionality --- Project.toml | 2 ++ src/ITensorBase.jl | 43 +++++++++++++++++++++++++++++++++++++++---- src/quirks.jl | 19 ++++++++++++++++++- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index f6be3a0..e4a6e25 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ version = "0.1.2" Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" DerivableInterfaces = "6c5e35bf-e59e-4898-b73c-732dcc4ba65f" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MapBroadcast = "ebd9b9da-f48d-417c-9660-449667d60261" NamedDimsArrays = "60cbd0c0-df58-4cb7-918c-6f5607b73fde" UnallocatedArrays = "43c9e47c-e622-40fb-bf18-a09fc8c466b6" @@ -16,6 +17,7 @@ UnspecifiedTypes = "42b3faec-625b-4613-8ddc-352bf9672b8d" Accessors = "0.1.39" DerivableInterfaces = "0.3.7" FillArrays = "1.13.0" +LinearAlgebra = "1.11.0" MapBroadcast = "0.1.5" NamedDimsArrays = "0.3.0" UnallocatedArrays = "0.1.1" diff --git a/src/ITensorBase.jl b/src/ITensorBase.jl index bf4f8ea..4ce20aa 100644 --- a/src/ITensorBase.jl +++ b/src/ITensorBase.jl @@ -18,6 +18,7 @@ using NamedDimsArrays: named, nameddimsindices, setname, + setnameddimsindices, unname const Tag = String @@ -79,7 +80,9 @@ struct Index{T,Value<:AbstractUnitRange{T}} <: AbstractNamedUnitRange{T,Value,In name::IndexName end -Index(length::Int; kwargs...) = Index(Base.OneTo(length), IndexName(; kwargs...)) +function Index(length::Int; tags, kwargs...) + return Index(Base.OneTo(length), IndexName(; tags=tagset(tags), kwargs...)) +end function Index(length::Int, tags::String; kwargs...) return Index(Base.OneTo(length), IndexName(; kwargs..., tags=tagset(tags))) end @@ -177,17 +180,30 @@ struct AllocatableArrayInterface <: AbstractAllocatableArrayInterface end unallocatable(a::AbstractITensor) = NamedDimsArray(a) -@interface ::AbstractAllocatableArrayInterface function Base.setindex!( - a::AbstractArray, value, I::Int... -) +function setindex_allocatable!(a::AbstractArray, value, I...) allocate!(specify_eltype!(a, typeof(value))) # TODO: Maybe use `@interface interface(a) a[I...] = value`? unallocatable(a)[I...] = value return a end +# TODO: Combine these by using `Base.to_indices`. +@interface ::AbstractAllocatableArrayInterface function Base.setindex!( + a::AbstractArray, value, I::Int... +) + setindex_allocatable!(a, value, I...) + return a +end +@interface ::AbstractAllocatableArrayInterface function Base.setindex!( + a::AbstractArray, value, I::AbstractNamedInteger... +) + setindex_allocatable!(a, value, I...) + return a +end + @derive AllocatableArrayInterface() (T=AbstractITensor,) begin Base.setindex!(::T, ::Any, ::Int...) + Base.setindex!(::T, ::Any, ::AbstractNamedInteger...) end mutable struct ITensor <: AbstractITensor @@ -216,6 +232,25 @@ function ITensor() return ITensor(Zeros{UnspecifiedZero}(), ()) end +inds(a::AbstractITensor) = nameddimsindices(a) +setinds(a::AbstractITensor, inds) = setnameddimsindices(a, inds) + +function uniqueinds(a1::AbstractITensor, a_rest::AbstractITensor...) + return setdiff(inds(a1), inds.(a_rest)...) +end +function uniqueind(a1::AbstractITensor, a_rest::AbstractITensor...) + return only(uniqueinds(a1, a_rest...)) +end + +function commoninds(a1::AbstractITensor, a_rest::AbstractITensor...) + return intersect(inds(a1), inds.(a_rest)...) +end +function commonind(a1::AbstractITensor, a_rest::AbstractITensor...) + return only(commoninds(a1, a_rest...)) +end + +prime(a::AbstractITensor) = setinds(a, prime.(inds(a))) + include("quirks.jl") end diff --git a/src/quirks.jl b/src/quirks.jl index 0227d72..f9d4e5c 100644 --- a/src/quirks.jl +++ b/src/quirks.jl @@ -4,11 +4,28 @@ dag(i::Index) = i dim(i::Index) = dename(length(i)) # TODO: Define this properly. hasqns(i::Index) = false -inds(a::ITensor) = nameddimsindices(a) # TODO: Deprecate. itensor(parent::AbstractArray, nameddimsindices) = ITensor(parent, nameddimsindices) function itensor(parent::AbstractArray, i1::Index, i_rest::Index...) return ITensor(parent, (i1, i_rest...)) end +# This seems to be needed to get broadcasting working. +# TODO: Investigate this and see if we can get rid of it. Base.Broadcast.extrude(a::AbstractITensor) = a + +# TODO: Generalize this. +# Maybe define it as `oneelement`, and base it on +# `FillArrays.OneElement` (https://juliaarrays.github.io/FillArrays.jl/stable/#FillArrays.OneElement). +function onehot(iv::Pair{<:Index,<:Int}) + a = ITensor(first(iv)) + a[last(iv)] = one(Bool) + return a +end + +using LinearAlgebra: svd +# TODO: Define this in `MatrixAlgebra.jl`/`TensorAlgebra.jl`. +function factorize(a::AbstractITensor, args...; kwargs...) + U, S, V = svd(a, args...; kwargs...) + return U, S * V +end From 2655456f2ff268e0e45c181c6ed443ebc020ad8c Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 16 Jan 2025 18:37:03 -0500 Subject: [PATCH 5/9] Add comment --- src/ITensorBase.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ITensorBase.jl b/src/ITensorBase.jl index 4ce20aa..fd61bc7 100644 --- a/src/ITensorBase.jl +++ b/src/ITensorBase.jl @@ -249,6 +249,8 @@ function commonind(a1::AbstractITensor, a_rest::AbstractITensor...) return only(commoninds(a1, a_rest...)) end +# TODO: Use `replaceinds`/`mapinds`, based on +# `replacenameddimsindices`/`mapnameddimsindices`. prime(a::AbstractITensor) = setinds(a, prime.(inds(a))) include("quirks.jl") From 24b815a09072bb96f93052916b709516ee090962 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 16 Jan 2025 18:38:53 -0500 Subject: [PATCH 6/9] Loosen compat --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e4a6e25..c34c6e1 100644 --- a/Project.toml +++ b/Project.toml @@ -17,7 +17,7 @@ UnspecifiedTypes = "42b3faec-625b-4613-8ddc-352bf9672b8d" Accessors = "0.1.39" DerivableInterfaces = "0.3.7" FillArrays = "1.13.0" -LinearAlgebra = "1.11.0" +LinearAlgebra = "1.10" MapBroadcast = "0.1.5" NamedDimsArrays = "0.3.0" UnallocatedArrays = "0.1.1" From 6c7b1c7282e04782ee018ebcd6a3fdcff58d68b8 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 16 Jan 2025 18:39:25 -0500 Subject: [PATCH 7/9] Bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c34c6e1..09603fd 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ITensorBase" uuid = "4795dd04-0d67-49bb-8f44-b89c448a1dc7" authors = ["ITensor developers and contributors"] -version = "0.1.2" +version = "0.1.3" [deps] Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" From a4b41c5c6664e820dc843ccc49172a98b70ca4d1 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 16 Jan 2025 18:42:27 -0500 Subject: [PATCH 8/9] Fix example --- examples/README.jl | 3 +-- src/ITensorBase.jl | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/README.jl b/examples/README.jl index 48de04f..70c1717 100644 --- a/examples/README.jl +++ b/examples/README.jl @@ -20,9 +20,8 @@ julia> Pkg.add("ITensorBase") # ## Examples using ITensorBase: ITensorBase, ITensor, Index -# TODO: This should be `TensorAlgebra.qr`. using LinearAlgebra: qr -using NamedDimsArrays: NamedDimsArray, aligndims, dimnames, name, unname +using NamedDimsArrays: aligndims, unname using Test: @test i = Index(2) j = Index(2) diff --git a/src/ITensorBase.jl b/src/ITensorBase.jl index fd61bc7..ccecd09 100644 --- a/src/ITensorBase.jl +++ b/src/ITensorBase.jl @@ -25,6 +25,7 @@ const Tag = String const TagSet = Set{Tag} tagset(tags::String) = Set(filter(!isempty, String.(strip.(split(tags, ","))))) +tagset(tags::TagSet) = tags function tagsstring(tags::TagSet) str = "" @@ -80,7 +81,7 @@ struct Index{T,Value<:AbstractUnitRange{T}} <: AbstractNamedUnitRange{T,Value,In name::IndexName end -function Index(length::Int; tags, kwargs...) +function Index(length::Int; tags=TagSet(), kwargs...) return Index(Base.OneTo(length), IndexName(; tags=tagset(tags), kwargs...)) end function Index(length::Int, tags::String; kwargs...) From ac1dbfef220b8849ff8f24a535d63e9399388a20 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 16 Jan 2025 18:43:27 -0500 Subject: [PATCH 9/9] Update README --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index a25436a..5216bc7 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,8 @@ julia> Pkg.add("ITensorBase") ````julia using ITensorBase: ITensorBase, ITensor, Index -```` - -TODO: This should be `TensorAlgebra.qr`. - -````julia using LinearAlgebra: qr -using NamedDimsArrays: NamedDimsArray, aligndims, dimnames, name, unname +using NamedDimsArrays: aligndims, unname using Test: @test i = Index(2) j = Index(2)