Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ITensorBase"
uuid = "4795dd04-0d67-49bb-8f44-b89c448a1dc7"
authors = ["ITensor developers <support@itensor.org> and contributors"]
version = "0.1.8"
version = "0.1.9"

[deps]
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
Expand Down
281 changes: 2 additions & 279 deletions src/ITensorBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,285 +2,8 @@ module ITensorBase

export ITensor, Index

using Accessors: @set
using MapBroadcast: Mapped
using NamedDimsArrays:
NamedDimsArrays,
AbstractName,
AbstractNamedDimsArray,
AbstractNamedInteger,
AbstractNamedUnitRange,
AbstractNamedVector,
NamedDimsArray,
dename,
dimnames,
mapnameddimsindices,
name,
named,
nameddimsindices,
randname,
replacenameddimsindices,
setname,
setnameddimsindices,
unname

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 = ""
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)
tags::TagSet = TagSet()
plev::Int = 0
end
NamedDimsArrays.randname(n::IndexName) = IndexName(; tags=tags(n), plev=plev(n))

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))

setprime(n::IndexName, plev) = @set n.plev = plev
prime(n::IndexName) = setprime(n, plev(n) + 1)
noprime(n::IndexName) = setprime(n, 0)
sim(n::IndexName) = randname(n)

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
end

# Interface
NamedDimsArrays.dename(i::IndexVal) = i.value
NamedDimsArrays.name(i::IndexVal) = i.name

# Constructor
NamedDimsArrays.named(i::Integer, name::IndexName) = IndexVal(i, name)

struct Index{T,Value<:AbstractUnitRange{T}} <: AbstractNamedUnitRange{T,Value,IndexName}
value::Value
name::IndexName
end

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...)
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)
noprime(i::Index) = setname(i, noprime(name(i)))
sim(i::Index) = setname(i, sim(name(i)))

# Interface
# TODO: Overload `Base.parent` instead.
NamedDimsArrays.dename(i::Index) = i.value
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
name::IndexName
end

# Interface
# TODO: Overload `Base.parent` instead.
NamedDimsArrays.dename(i::NoncontiguousIndex) = i.value
NamedDimsArrays.name(i::NoncontiguousIndex) = i.name

# Constructor
NamedDimsArrays.named(i::AbstractVector, name::IndexName) = NoncontiguousIndex(i, name)

abstract type AbstractITensor <: AbstractNamedDimsArray{Any,Any} end

NamedDimsArrays.nameddimsarraytype(::Type{<:IndexName}) = ITensor

Base.ndims(::Type{<:AbstractITensor}) = Any

using FillArrays: Zeros
using UnallocatedArrays: UnallocatedZeros, allocate
using UnspecifiedTypes: UnspecifiedZero

# TODO: Make this more general, maybe with traits `is_unallocated`
# and `is_eltype_unspecified`.
function specify_eltype(a::Zeros{UnspecifiedZero}, elt::Type)
return Zeros{elt}(axes(a))
end
function specify_eltype(a::AbstractArray, elt::Type)
return a
end

# TODO: Use `adapt` to reach down into the storage.
function specify_eltype!(a::AbstractITensor, elt::Type)
setdenamed!(a, specify_eltype(dename(a), elt))
return a
end

# Assume it is allocated.
allocate!(a::AbstractArray) = a

# TODO: Use `adapt` to reach down into the storage.
function allocate!(a::AbstractITensor)
setdenamed!(a, allocate(dename(a)))
return a
end

using DerivableInterfaces: @derive, @interface, AbstractArrayInterface

abstract type AbstractAllocatableArrayInterface <: AbstractArrayInterface end
struct AllocatableArrayInterface <: AbstractAllocatableArrayInterface end

unallocatable(a::AbstractITensor) = NamedDimsArray(a)

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
parent::AbstractArray
nameddimsindices
end
Base.parent(a::ITensor) = a.parent
NamedDimsArrays.nameddimsindices(a::ITensor) = a.nameddimsindices

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

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

# TODO: Use `replaceinds`/`mapinds`, based on
# `replacenameddimsindices`/`mapnameddimsindices`.
prime(a::AbstractITensor) = setinds(a, prime.(inds(a)))
noprime(a::AbstractITensor) = setinds(a, noprime.(inds(a)))
sim(a::AbstractITensor) = setinds(a, sim.(inds(a)))

function replaceinds(a::AbstractITensor, replacements::Pair...)
return replacenameddimsindices(a, replacements...)
end

function replaceinds(f, a::AbstractITensor)
return replacenameddimsindices(f, a)
end

function mapinds(f, a::AbstractITensor)
return mapnameddimsindices(f, a)
end

using VectorInterface: VectorInterface, scalartype
VectorInterface.scalartype(a::AbstractITensor) = scalartype(unallocatable(a))

include("index.jl")
include("abstractitensor.jl")
include("quirks.jl")

end
Loading
Loading