Skip to content
Merged
15 changes: 13 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
name = "QuantumOperatorDefinitions"
uuid = "826dd319-6fd5-459a-a990-3a4f214664bf"
authors = ["ITensor developers <[email protected]> and contributors"]
version = "0.1.4"
version = "0.1.5"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[weakdeps]
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
GradedUnitRanges = "e2de450a-8a67-46c7-b59c-01d5a3d041c5"
LabelledNumbers = "f856a3a6-4152-4ec4-b2a7-02c1a55d7993"
ITensorBase = "4795dd04-0d67-49bb-8f44-b89c448a1dc7"
NamedDimsArrays = "60cbd0c0-df58-4cb7-918c-6f5607b73fde"
SymmetrySectors = "f8a8ad64-adbc-4fce-92f7-ffe2bb36a86e"

[extensions]
QuantumOperatorDefinitionsITensorBaseExt = "ITensorBase"
QuantumOperatorDefinitionsITensorBaseExt = ["ITensorBase", "NamedDimsArrays"]
QuantumOperatorDefinitionsSymmetrySectorsExt = ["BlockArrays", "GradedUnitRanges", "LabelledNumbers", "SymmetrySectors"]

[compat]
BlockArrays = "1.3.0"
GradedUnitRanges = "0.1.2"
ITensorBase = "0.1.10"
LabelledNumbers = "0.1.0"
LinearAlgebra = "1.10"
NamedDimsArrays = "0.4.0"
Random = "1.10"
SymmetrySectors = "0.1.3"
julia = "1.10"
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ julia> Pkg.add("QuantumOperatorDefinitions")

````julia
using QuantumOperatorDefinitions: OpName, SiteType, StateName, ⊗, controlled, op, state
using LinearAlgebra: Diagonal
using SparseArrays: SparseMatrixCSC, SparseVector
using Test: @test

Expand Down Expand Up @@ -64,8 +63,6 @@ using Test: @test
@test op("Y") == [0 -im; im 0]
@test op("Z") == [1 0; 0 -1]

@test op("Z") isa Diagonal

@test op(Float32, "X") == [0 1; 1 0]
@test eltype(op(Float32, "X")) === Float32
@test op(SparseMatrixCSC, "X") == [0 1; 1 0]
Expand Down
3 changes: 0 additions & 3 deletions examples/README.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ julia> Pkg.add("QuantumOperatorDefinitions")
# ## Examples

using QuantumOperatorDefinitions: OpName, SiteType, StateName, ⊗, controlled, op, state
using LinearAlgebra: Diagonal
using SparseArrays: SparseMatrixCSC, SparseVector
using Test: @test

Expand Down Expand Up @@ -69,8 +68,6 @@ using Test: @test
@test op("Y") == [0 -im; im 0]
@test op("Z") == [1 0; 0 -1]

@test op("Z") isa Diagonal

@test op(Float32, "X") == [0 1; 1 0]
@test eltype(op(Float32, "X")) === Float32
@test op(SparseMatrixCSC, "X") == [0 1; 1 0]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,58 @@
module QuantumOperatorDefinitionsITensorBaseExt

using ITensorBase: ITensor, Index, dag, gettag, prime
using ITensorBase: ITensorBase, ITensor, Index, dag, gettag, prime, settag
using NamedDimsArrays: dename
using QuantumOperatorDefinitions:
QuantumOperatorDefinitions, OpName, SiteType, StateName, has_fermion_string
QuantumOperatorDefinitions,
@OpName_str,
OpName,
SiteType,
StateName,
has_fermion_string,
name

function QuantumOperatorDefinitions.SiteType(r::Index)
return SiteType(gettag(r, "sitetype", "Qudit"); dim=Int(length(r)))
# We pass the axis of the (unnamed) Index because
# the Index may have originated from a slice, in which
# case the start may not be 1 (for NonContiguousIndex,
# which we need to add support for, it may not even
# be a unit range).
return SiteType(
gettag(r, "sitetype", "Qudit"); dim=Int.(length(r)), range=only(axes(dename(r)))
)
end

function (rangetype::Type{<:Index})(t::SiteType)
return settag(rangetype(AbstractUnitRange(t)), "sitetype", String(name(t)))
end

# TODO: Define in terms of `OpName` directly, and define a generic
# forwarding method `has_fermion_string(n::String, t) = has_fermion_string(OpName(n), t)`.
function QuantumOperatorDefinitions.has_fermion_string(n::String, r::Index)
return has_fermion_string(OpName(n), SiteType(r))
end

function Base.AbstractArray(n::OpName, r::Index)
# TODO: Define this with mapped dimnames.
return ITensor(AbstractArray(n, SiteType(r)), (prime(r), dag(r)))
function Base.axes(::OpName, domain::Tuple{Vararg{Index}})
return (prime.(domain)..., dag.(domain)...)
end
## function Base.axes(::OpName"SWAP", domain::Tuple{Vararg{Index}})
## return (prime.(reverse(domain))..., dag.(domain)...)
## end

function Base.AbstractArray(n::StateName, r::Index)
return ITensor(AbstractArray(n, SiteType(r)), (r,))
# Fix ambiguity error with generic `AbstractArray` version.
function ITensorBase.ITensor(n::Union{OpName,StateName}, domain::Index...)
return ITensor(n, domain)
end
# Fix ambiguity error with generic `AbstractArray` version.
function ITensorBase.ITensor(n::Union{OpName,StateName}, domain::Tuple{Vararg{Index}})
return ITensor(AbstractArray(n, domain), axes(n, domain))
end
function (arrtype::Type{<:AbstractArray})(
n::Union{OpName,StateName}, domain::Tuple{Vararg{Index}}
)
# Convert to `SiteType` in case the Index specifies a `"sitetype"` tag.
# TODO: Try to build this into the generic codepath.
return ITensor(arrtype(n, SiteType.(domain)), axes(n, domain))
end

end
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
module QuantumOperatorDefinitionsSymmetrySectorsExt

using BlockArrays: blocklasts, blocklengths
using GradedUnitRanges: AbstractGradedUnitRange, GradedOneTo, gradedrange
using LabelledNumbers: label, labelled, unlabel
using QuantumOperatorDefinitions:
QuantumOperatorDefinitions,
@SiteType_str,
@GradingType_str,
SiteType,
GradingType,
OpName,
name
using SymmetrySectors: ×, dual, SectorProduct, U1, Z

function Base.axes(::OpName, domain::Tuple{Vararg{AbstractGradedUnitRange}})
return (domain..., dual.(domain)...)
end

sortedunion(a, b) = sort(union(a, b))

Check warning on line 20 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L20

Added line #L20 was not covered by tests
function QuantumOperatorDefinitions.combine_axes(a1::GradedOneTo, a2::GradedOneTo)
return gradedrange(
map(blocklengths(a1), blocklengths(a2)) do s1, s2
l1 = unlabel(s1)
l2 = unlabel(s2)
@assert l1 == l2
labelled(l1, label(s1) × label(s2))
end,
)
end
QuantumOperatorDefinitions.combine_axes(a::GradedOneTo, b::Base.OneTo) = a

Check warning on line 31 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L31

Added line #L31 was not covered by tests
QuantumOperatorDefinitions.combine_axes(a::Base.OneTo, b::GradedOneTo) = b

function Base.AbstractUnitRange(::GradingType"N", t::SiteType)
return gradedrange(map(i -> SectorProduct((; N=U1(i - 1))) => 1, 1:length(t)))

Check warning on line 35 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L34-L35

Added lines #L34 - L35 were not covered by tests
end
function Base.AbstractUnitRange(::GradingType"Sz", t::SiteType)
return gradedrange(map(i -> SectorProduct((; Sz=U1(i - 1))) => 1, 1:length(t)))
end
function Base.AbstractUnitRange(::GradingType"Sz↑", t::SiteType)
return AbstractUnitRange(GradingType"Sz"(), t)

Check warning on line 41 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L40-L41

Added lines #L40 - L41 were not covered by tests
end
function Base.AbstractUnitRange(::GradingType"Sz↓", t::SiteType)
return gradedrange(map(i -> SectorProduct((; Sz=U1(-(i - 1)))) => 1, 1:length(t)))

Check warning on line 44 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L43-L44

Added lines #L43 - L44 were not covered by tests
end

function sector(gradingtype::GradingType, sec)
sectorname = Symbol(get(gradingtype, :name, name(gradingtype)))
return SectorProduct(NamedTuple{(sectorname,)}((sec,)))
end

function Base.AbstractUnitRange(s::GradingType"Nf", t::SiteType"Fermion")
return gradedrange([sector(s, U1(0)) => 1, sector(s, U1(1)) => 1])

Check warning on line 53 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L52-L53

Added lines #L52 - L53 were not covered by tests
end
# TODO: Write in terms of `GradingType"Nf"` definition.
function Base.AbstractUnitRange(s::GradingType"NfParity", t::SiteType"Fermion")
return gradedrange([sector(s, Z{2}(0)) => 1, sector(s, Z{2}(1)) => 1])

Check warning on line 57 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L56-L57

Added lines #L56 - L57 were not covered by tests
end
function Base.AbstractUnitRange(s::GradingType"Sz", t::SiteType"Fermion")
return gradedrange([sector(s, U1(0)) => 1, sector(s, U1(1)) => 1])

Check warning on line 60 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L59-L60

Added lines #L59 - L60 were not covered by tests
end
function Base.AbstractUnitRange(s::GradingType"Sz↑", t::SiteType"Fermion")
return gradedrange([sector(s, U1(0)) => 1, sector(s, U1(1)) => 1])

Check warning on line 63 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L62-L63

Added lines #L62 - L63 were not covered by tests
end
function Base.AbstractUnitRange(s::GradingType"Sz↓", t::SiteType"Fermion")
return gradedrange([sector(s, U1(0)) => 1, sector(s, U1(-1)) => 1])

Check warning on line 66 in ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/QuantumOperatorDefinitionsSymmetrySectorsExt/QuantumOperatorDefinitionsSymmetrySectorsExt.jl#L65-L66

Added lines #L65 - L66 were not covered by tests
end

# TODO: Write in terms of `SiteType"Fermion"` definitions.
function Base.AbstractUnitRange(s::GradingType"Nf", t::SiteType"Electron")
return gradedrange([
sector(s, U1(0)) => 1,
sector(s, U1(1)) => 1,
sector(s, U1(1)) => 1,
sector(s, U1(2)) => 1,
])
end
# TODO: Write in terms of `GradingType"Nf"` definition.
function Base.AbstractUnitRange(s::GradingType"NfParity", t::SiteType"Electron")
return gradedrange([
sector(s, Z{2}(0)) => 1,
sector(s, Z{2}(1)) => 1,
sector(s, Z{2}(1)) => 1,
sector(s, Z{2}(0)) => 1,
])
end
function Base.AbstractUnitRange(s::GradingType"Sz", t::SiteType"Electron")
return gradedrange([
sector(s, U1(0)) => 1,
sector(s, U1(1)) => 1,
sector(s, U1(-1)) => 1,
sector(s, U1(0)) => 1,
])
end

end
95 changes: 63 additions & 32 deletions src/op.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
end
name(::OpName{Name}) where {Name} = Name
params(n::OpName) = getfield(n, :params)

Base.getproperty(n::OpName, name::Symbol) = getfield(params(n), name)
Base.get(t::OpName, name::Symbol, default) = get(params(t), name, default)

Check warning on line 12 in src/op.jl

View check run for this annotation

Codecov / codecov/patch

src/op.jl#L12

Added line #L12 was not covered by tests

OpName{N}(; kwargs...) where {N} = OpName{N}((; kwargs...))

Expand Down Expand Up @@ -54,9 +54,14 @@
# Generic to `StateName` or `OpName`.
const StateOrOpName = Union{StateName,OpName}
alias(n::StateOrOpName) = n
function (arrtype::Type{<:AbstractArray})(n::StateOrOpName, domain::Integer...)
function (arrtype::Type{<:AbstractArray})(
n::StateOrOpName, domain::Union{Integer,AbstractUnitRange}...
)
return arrtype(n, domain)
end
function (arrtype::Type{<:AbstractArray})(n::StateOrOpName, domain::Tuple{Vararg{Integer}})
return arrtype(n, Base.oneto.(domain))
end
(arrtype::Type{<:AbstractArray})(n::StateOrOpName, ts::SiteType...) = arrtype(n, ts)
function (n::StateOrOpName)(domain...)
# TODO: Try one alias at a time?
Expand Down Expand Up @@ -87,32 +92,58 @@
return nsites(n′)
end

function op_convert(
arrtype::Type{<:AbstractArray{<:Any,N}},
domain::Tuple{Vararg{Integer}},
a::AbstractArray{<:Any,N},
) where {N}
# TODO: Check the dimensions.
return convert(arrtype, a)
# TODO: This does some unwanted conversions, like turning
# `Diagonal` dense.
function array(a::AbstractArray, ax::Tuple{Vararg{AbstractUnitRange}})
return a[ax...]
end
function op_convert(
arrtype::Type{<:AbstractArray}, domain::Tuple{Vararg{Integer}}, a::AbstractArray
)
# TODO: Check the dimensions.
return convert(arrtype, a)

function Base.axes(::OpName, domain::Tuple{Vararg{AbstractUnitRange}})
return (domain..., domain...)
end
function Base.axes(n::StateOrOpName, domain::Tuple{Vararg{Integer}})
return axes(n, Base.OneTo.(domain))
end
function Base.axes(n::StateOrOpName, domain::Tuple{Vararg{SiteType}})
return axes(n, AbstractUnitRange.(domain))
end

## function Base.axes(::OpName"SWAP", domain::Tuple{Vararg{AbstractUnitRange}})
## return (reverse(domain)..., domain...)
## end

function reversed_sites(n::StateOrOpName, domain)
return reverse_sites(n, reshape(n(domain...), length.(axes(n, reverse(domain)))))
end
function reverse_sites(n::OpName, a::AbstractArray)
ndomain = Int(ndims(a)//2)
perm1 = reverse(ntuple(identity, ndomain))
perm2 = perm1 .+ ndomain
perm = (perm1..., perm2...)
return permutedims(a, perm)
end
function op_convert(
arrtype::Type{<:AbstractArray{<:Any,N}}, domain::Tuple{Vararg{Integer}}, a::AbstractArray
) where {N}
size = (domain..., domain...)
@assert length(size) == N
return convert(arrtype, reshape(a, size))

function state_or_op_convert(
n::StateOrOpName,
arrtype::Type{<:AbstractArray},
domain::Tuple{Vararg{AbstractUnitRange}},
a::AbstractArray,
)
ax = axes(n, domain)
a′ = reshape(a, length.(ax))
a′′ = array(a′, ax)
return convert(arrtype, a′′)
end
function (arrtype::Type{<:AbstractArray})(n::OpName, domain::Tuple{Vararg{SiteType}})
return op_convert(arrtype, length.(domain), n(domain...))

function (arrtype::Type{<:AbstractArray})(n::StateOrOpName, domain::Tuple{Vararg{SiteType}})
domain′ = AbstractUnitRange.(domain)
return state_or_op_convert(n, arrtype, domain′, reversed_sites(n, domain))
end
function (arrtype::Type{<:AbstractArray})(n::OpName, domain::Tuple{Vararg{Integer}})
return op_convert(arrtype, domain, n(Int.(domain)...))
function (arrtype::Type{<:AbstractArray})(
n::StateOrOpName, domain::Tuple{Vararg{AbstractUnitRange}}
)
# TODO: Make `(::OpName)(domain...)` constructor process more general inputs.
return state_or_op_convert(n, arrtype, domain, reversed_sites(n, Int.(length.(domain))))
end

function op(arrtype::Type{<:AbstractArray}, n::String, domain...; kwargs...)
Expand Down Expand Up @@ -475,13 +506,13 @@
# Number of control sites.
nc = get(params(n), :ncontrol, length(domain) - nt)
@assert length(domain) == nc + nt
d_control = prod(to_dim.(domain[1:nc]))
d_control = prod(to_dim.(domain)) - prod(to_dim.(domain[(nc + 1):end]))
return cat(I(d_control), n.arg(domain[(nc + 1):end]...); dims=(1, 2))
end
@op_alias "CNOT" "Controlled" op = OpName"X"()
@op_alias "CX" "Controlled" op = OpName"X"()
@op_alias "CY" "Controlled" op = OpName"Y"()
@op_alias "CZ" "Controlled" op = OpName"Z"()
@op_alias "CNOT" "Controlled" arg = OpName"X"()
@op_alias "CX" "Controlled" arg = OpName"X"()
@op_alias "CY" "Controlled" arg = OpName"Y"()
@op_alias "CZ" "Controlled" arg = OpName"Z"()
function alias(n::OpName"CPhase")
return controlled(OpName"Phase"(; params(n)...))
end
Expand All @@ -504,17 +535,17 @@
end
@op_alias "CRn̂" "CRn"

@op_alias "CCNOT" "Controlled" ncontrol = 2 op = OpName"X"()
@op_alias "CCNOT" "Controlled" ncontrol = 2 arg = OpName"X"()
@op_alias "Toffoli" "CCNOT"
@op_alias "CCX" "CCNOT"
@op_alias "TOFF" "CCNOT"

@op_alias "CSWAP" "Controlled" ncontrol = 2 op = OpName"SWAP"()
@op_alias "CSWAP" "Controlled" ncontrol = 2 arg = OpName"SWAP"()
@op_alias "Fredkin" "CSWAP"
@op_alias "CSwap" "CSWAP"
@op_alias "CS" "CSWAP"

@op_alias "CCCNOT" "Controlled" ncontrol = 3 op = OpName"X"()
@op_alias "CCCNOT" "Controlled" ncontrol = 3 arg = OpName"X"()

## # 1-qudit rotation around generic axis n̂.
## # exp(-im * α / 2 * n̂ ⋅ σ⃗)
Expand Down
Loading