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
6 changes: 4 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FusionTensors"
uuid = "e16ca583-1f51-4df0-8e12-57d32947d33e"
authors = ["ITensor developers <support@itensor.org> and contributors"]
version = "0.5.13"
version = "0.5.14"

[deps]
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
Expand All @@ -14,6 +14,7 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Strided = "5e0ebb24-38b0-5f93-81fe-25c709ecae67"
TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a"
TensorKitSectors = "13a9c161-d5da-41f0-bcbd-e1a08ae0647f"
TensorProducts = "decf83d6-1968-43f4-96dc-fdb3fe15fc6d"
TypeParameterAccessors = "7e5a90cf-f82e-492e-a09b-e3e26432c138"
WignerSymbols = "9f57e263-0b3d-5e2e-b1be-24f2bb48858b"
Expand All @@ -22,13 +23,14 @@ WignerSymbols = "9f57e263-0b3d-5e2e-b1be-24f2bb48858b"
Accessors = "0.1.42"
BlockArrays = "1.7"
BlockSparseArrays = "0.10"
GradedArrays = "0.4"
GradedArrays = "0.5.2"
HalfIntegers = "1.6"
LRUCache = "1.6"
LinearAlgebra = "1.10"
Random = "1.10"
Strided = "2.3"
TensorAlgebra = "0.4"
TensorKitSectors = "0.1, 0.2"
TensorProducts = "0.1.7"
TypeParameterAccessors = "0.4"
WignerSymbols = "2.0.0"
Expand Down
110 changes: 20 additions & 90 deletions src/fusion_trees/clebsch_gordan_tensors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ using WignerSymbols: clebschgordan

using GradedArrays:
AbelianStyle,
AbstractSector,
NotAbelianStyle,
O2,
SU,
SU2,
SectorRange,
SymmetryStyle,
TrivialSector,
dual,
istrivial,
quantum_dimension,
Expand All @@ -21,16 +22,17 @@ using GradedArrays:
zero_odd
using TensorAlgebra: contract
using TensorProducts: ⊗
import TensorKitSectors as TKS

function symbol_1j(s::AbstractSector)
function symbol_1j(s::SectorRange)
cgt = clebsch_gordan_tensor(s, dual(s), trivial(s), 1)
return sqrt(quantum_dimension(s)) * cgt[:, :, 1]
end

function clebsch_gordan_tensor(
s1::AbstractSector,
s2::AbstractSector,
s3::AbstractSector,
s1::SectorRange,
s2::SectorRange,
s3::SectorRange,
arrow1::Bool,
arrow2::Bool,
inner_mult_index::Int,
Expand All @@ -47,91 +49,19 @@ function clebsch_gordan_tensor(
return cgt
end

function clebsch_gordan_tensor(s1::S, s2::S, s3::S, outer_mult_index::Int) where {S}
return clebsch_gordan_tensor(SymmetryStyle(S), s1, s2, s3, outer_mult_index)
end

function clebsch_gordan_tensor(
::AbelianStyle, s1::S, s2::S, s3::S, outer_mult_index::Int
) where {S}
@assert outer_mult_index == 1
return s1 ⊗ s2 == s3 ? ones((1, 1, 1)) : zeros((1, 1, 1))
end

function clebsch_gordan_tensor(::NotAbelianStyle, s1::O2, s2::O2, s3::O2, ::Int)
return clebsch_gordan_tensor(s1, s2, s3) # no outer multiplicity
end

function clebsch_gordan_tensor(s1::O2, s2::O2, s3::O2)
d1 = quantum_dimension(s1)
d2 = quantum_dimension(s2)
d3 = quantum_dimension(s3)
cgt = zeros((d1, d2, d3))
s3 ∉ sectors(s1 ⊗ s2) && return cgt

# adapted from TensorKit
l1 = sector_label(s1)
l2 = sector_label(s2)
l3 = sector_label(s3)
if l3 <= 0 # 0even or 0odd
if l1 <= 0 && l2 <= 0
cgt[1, 1, 1, 1] = 1.0
else
if istrivial(s3)
cgt[1, 2, 1, 1] = 1.0 / sqrt(2)
cgt[2, 1, 1, 1] = 1.0 / sqrt(2)
else
cgt[1, 2, 1, 1] = 1.0 / sqrt(2)
cgt[2, 1, 1, 1] = -1.0 / sqrt(2)
end
end
elseif l1 <= 0 # 0even or 0odd
cgt[1, 1, 1, 1] = 1.0
cgt[1, 2, 2, 1] = s1 == zero_odd(O2) ? -1.0 : 1.0
elseif l2 == 0
cgt[1, 1, 1, 1] = 1.0
cgt[2, 1, 2, 1] = s2 == zero_odd(O2) ? -1.0 : 1.0
elseif l3 == l1 + l2
cgt[1, 1, 1, 1] = 1.0
cgt[2, 2, 2, 1] = 1.0
elseif l3 == l1 - l2
cgt[1, 2, 1, 1] = 1.0
cgt[2, 1, 2, 1] = 1.0
elseif l3 == l2 - l1
cgt[2, 1, 1, 1] = 1.0
cgt[1, 2, 2, 1] = 1.0
function clebsch_gordan_tensor(s1::S, s2::S, s3::S, outer_mult_index::Int = 1) where {S}
CGC = TKS.fusiontensor(GradedArrays.label.((s1, s2, s3))...)
outer_mult_index ∈ axes(CGC, 4) || throw(ArgumentError("invalid outer multiplicity index"))
if TKS.FusionStyle(S) === TKS.GenericFusion()
# TODO: do we want a view here?
return CGC[:, :, :, outer_mult_index]
else
return dropdims(CGC; dims = 4)
end
return cgt
end

function clebsch_gordan_tensor(::NotAbelianStyle, s1::SU{2}, s2::SU{2}, s3::SU{2}, ::Int)
return clebsch_gordan_tensor(s1, s2, s3) # no outer multiplicity
end

function clebsch_gordan_tensor(s1::SU{2}, s2::SU{2}, s3::SU{2})
d1 = quantum_dimension(s1)
d2 = quantum_dimension(s2)
d3 = quantum_dimension(s3)
j1 = half(d1 - 1)
j2 = half(d2 - 1)
j3 = half(d3 - 1)
cgtensor = Array{Float64, 3}(undef, (d1, d2, d3))
for (i, j, k) in Iterators.product(1:d1, 1:d2, 1:d3)
m1 = j1 - i + 1
m2 = j2 - j + 1
m3 = j3 - k + 1
cgtensor[i, j, k] = clebschgordan(j1, m1, j2, m2, j3, m3)
end
return cgtensor
end

function clebsch_gordan_tensor(
::NotAbelianStyle, s1::SU{3}, s2::SU{3}, s3::SU{3}, outer_mult_index::Int
)
d1 = quantum_dimension(s1)
d2 = quantum_dimension(s2)
d3 = quantum_dimension(s3)
cgtensor = zeros(d1, d2, d3)
# dummy
return cgtensor
# TODO: remove once TensorKitSectors fixes this
function clebsch_gordan_tensor(s1::TrivialSector, s2::TrivialSector, s3::TrivialSector, outer_mult_index::Int = 1)
outer_mult_index == 1 || throw(ArgumentError("invalid outer multiplicity index"))
return fill(1, (1, 1, 1))
end
39 changes: 20 additions & 19 deletions src/fusion_trees/fusiontree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@

using GradedArrays:
GradedArrays,
×,
AbstractGradedUnitRange,
AbstractSector,
SectorProduct,
SectorProductRange,
SectorRange,
×,
arguments,
flip,
flip_dual,
isdual,
nsymbol,
sector_multiplicities,
sector_type,
sectorproduct,
sectors,
to_gradedrange,
trivial
Expand Down Expand Up @@ -125,7 +126,7 @@ function GradedArrays.:×(f1::SectorFusionTree, f2::SectorFusionTree)
)
end

function GradedArrays.arguments(f::SectorFusionTree{<:SectorProduct})
function GradedArrays.arguments(f::SectorFusionTree{<:SectorProductRange})
transposed_indices = outer_multiplicity_split.(
Base.tail(leaves(f)),
branch_sectors(f),
Expand All @@ -136,7 +137,7 @@ function GradedArrays.arguments(f::SectorFusionTree{<:SectorProduct})
arguments_leaves = arguments.(leaves(f))
arguments_branch_sectors = arguments.(branch_sectors(f))
# TODO way to avoid explicit ntuple?
# works fine for Tuple and NamedTuple SectorProduct
# works fine for Tuple and NamedTuple SectorProductRange
return ntuple(
i -> SectorFusionTree(
getindex.(arguments_leaves, i),
Expand All @@ -149,21 +150,21 @@ function GradedArrays.arguments(f::SectorFusionTree{<:SectorProduct})
)
end

function GradedArrays.arguments(f::SectorFusionTree{<:SectorProduct, 0})
function GradedArrays.arguments(f::SectorFusionTree{<:SectorProductRange, 0})
return map(arg -> SectorFusionTree((), (), arg, (), ()), arguments(root_sector(f)))
end

function GradedArrays.arguments(f::SectorFusionTree{<:SectorProduct, 1})
function GradedArrays.arguments(f::SectorFusionTree{<:SectorProductRange, 1})
arguments_root = arguments(root_sector(f))
arguments_leave = arguments(only(leaves(f)))
# use map(keys) to stay agnostic with respect to SectorProduct implementation
# use map(keys) to stay agnostic with respect to SectorProductRange implementation
return map(keys(arguments_root)) do k
return SectorFusionTree((arguments_leave[k],), arrows(f), arguments_root[k], (), ())
end
end

# TBD change type depending on AbelianStyle?
fusiontree_eltype(::Type{<:AbstractSector}) = Float64
fusiontree_eltype(::Type{<:SectorRange}) = Float64

# constructors
function build_trees(legs::Vararg{AbstractGradedUnitRange})
Expand All @@ -175,7 +176,7 @@ function build_trees(legs::Vararg{AbstractGradedUnitRange})
end

function build_trees(
sectors_to_fuse::NTuple{N, <:AbstractSector}, arrows_to_fuse::NTuple{N, Bool}
sectors_to_fuse::NTuple{N, <:SectorRange}, arrows_to_fuse::NTuple{N, Bool}
) where {N}
# construct all authorized trees with fixed outer sectors
trees = [SectorFusionTree(first(sectors_to_fuse), first(arrows_to_fuse))]
Expand All @@ -186,18 +187,18 @@ end
# ===================================== Internals ========================================
#

# --------------- SectorProduct helper functions ---------------
# --------------- SectorProductRange helper functions ---------------
function outer_multiplicity_kron(
sec1, sec2, fused, outer_multiplicity1, outer_multiplicity2
)
n = nsymbol(sec1, sec2, fused)
n = Int(nsymbol(sec1, sec2, fused))
linear_inds = LinearIndices((n, outer_multiplicity2))
return linear_inds[outer_multiplicity1, outer_multiplicity2]
end

function outer_multiplicity_split(
sec1::S, sec2::S, fused::S, outer_mult_index::Integer
) where {S <: SectorProduct}
) where {S <: SectorProductRange}
args1 = arguments(sec1)
args2 = arguments(sec2)
args12 = arguments(fused)
Expand All @@ -207,15 +208,15 @@ end

# --------------- Build trees ---------------
# zero leg: need S to get sector type information
function SectorFusionTree{S}() where {S <: AbstractSector}
function SectorFusionTree{S}() where {S <: SectorRange}
return SectorFusionTree((), (), trivial(S), (), ())
end
function SectorFusionTree{S}(::Tuple{}, ::Tuple{}) where {S <: AbstractSector}
function SectorFusionTree{S}(::Tuple{}, ::Tuple{}) where {S <: SectorRange}
return SectorFusionTree((), (), trivial(S), (), ())
end

# one leg
function SectorFusionTree(sect::AbstractSector, arrow::Bool)
function SectorFusionTree(sect::SectorRange, arrow::Bool)
return SectorFusionTree((sect,), (arrow,), sect, (), ())
end

Expand All @@ -227,7 +228,7 @@ end

function append_tree_leave(
parent_tree::SectorFusionTree,
branch_sector::AbstractSector,
branch_sector::SectorRange,
level_arrow::Bool,
child_root_sector,
outer_mult,
Expand All @@ -242,7 +243,7 @@ function append_tree_leave(
end

function fuse_next_sector(
parent_tree::SectorFusionTree, branch_sector::AbstractSector, level_arrow::Bool
parent_tree::SectorFusionTree, branch_sector::SectorRange, level_arrow::Bool
)
new_space = to_gradedrange(root_sector(parent_tree) ⊗ branch_sector)
return mapreduce(
Expand Down Expand Up @@ -282,7 +283,7 @@ function to_array(f::SectorFusionTree)
return grow_tensor_tree(tree_tensor, f)
end

function to_array(f::SectorFusionTree{<:SectorProduct})
function to_array(f::SectorFusionTree{<:SectorProductRange})
args = convert.(Array, arguments(f))
return reduce(_tensor_kron, args)
end
Expand Down
8 changes: 5 additions & 3 deletions src/fusiontensor/fusiontensor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ using BlockSparseArrays:
AbstractBlockSparseMatrix, BlockSparseArray, eachblockstoredindex, to_block_indices
using GradedArrays:
AbstractGradedUnitRange,
SectorProduct,
SymmetryStyle,
TrivialSector,
dual,
findfirstblock,
Expand Down Expand Up @@ -35,7 +35,7 @@ function flip_domain(nonflipped_col_axis, nonflipped_trees_to_ranges)
return col_axis, domain_trees_to_ranges_mapping
end

function fuse_axes(::Type{S}, ::Tuple{}) where {S <: AbstractSector}
function fuse_axes(::Type{S}, ::Tuple{}) where {S <: SectorRange}
fused_axis = trivial_axis(S)
trees_to_ranges_mapping = Dict([SectorFusionTree{S}() => Block(1)[1:1]])
return fused_axis, trees_to_ranges_mapping
Expand Down Expand Up @@ -253,7 +253,9 @@ function GradedArrays.sector_type(::Type{FT}) where {FT <: FusionTensor}
return sector_type(type_parameters(FT, 3))
end

SymmetryStyle(::Type{FT}) where {FT <: FusionTensor} = SymmetryStyle(sector_type(FT))
function GradedArrays.SymmetryStyle(::Type{FT}) where {FT <: FusionTensor}
return SymmetryStyle(sector_type(FT))
end

# ============================== FusionTensor interface ==================================

Expand Down
1 change: 0 additions & 1 deletion src/fusiontensor/fusiontensoraxes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ using BlockArrays: BlockArrays
using GradedArrays:
GradedArrays,
AbstractGradedUnitRange,
AbstractSector,
SymmetryStyle,
TrivialSector,
dual,
Expand Down
4 changes: 3 additions & 1 deletion test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ FusionTensors = "e16ca583-1f51-4df0-8e12-57d32947d33e"
GradedArrays = "bc96ca6e-b7c8-4bb6-888e-c93f838762c2"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SUNRepresentations = "1a50b95c-7aac-476d-a9ce-2bfc675fc617"
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a"
Expand All @@ -17,9 +18,10 @@ Aqua = "0.8.11"
BlockArrays = "1.6"
BlockSparseArrays = "0.10"
FusionTensors = "0.5"
GradedArrays = "0.4"
GradedArrays = "0.5"
LinearAlgebra = "1.10.0"
Random = "1.10"
SUNRepresentations = "0.3.1"
SafeTestsets = "0.1.0"
Suppressor = "0.2.8"
TensorAlgebra = "0.4"
Expand Down
Loading
Loading