|
| 1 | +const tk_tensor = Union{TensorMap, BraidingTensor} |
| 2 | + |
| 3 | +function ITensors.ITensor(t::tk_tensor; |
| 4 | + tags::AbstractVector{<:AbstractString}=itensor_standard_tags(numind(t)), |
| 5 | + ids=itensor_standard_ids(numind(t)), |
| 6 | + plevs=itensor_standard_plevs(numind(t)), |
| 7 | + qn_names::Union{<:AbstractVector{<:AbstractString},Missing}=missing, |
| 8 | +)::ITensor |
| 9 | + T = eltype(t) |
| 10 | + ## First we take t to be a tensor from a 0-dimensional codomain to a rank N-domain |
| 11 | + t = repartition(t, numind(t), 0) |
| 12 | + sp = TensorKit.space(t) |
| 13 | + indices = [[(isdual(V) ? dual(c) : c) => TensorKit.dim(V, c) for c in sectors(V)] for V in sp.codomain] |
| 14 | + direction = [isdual(V) ? ITensors.In : ITensors.Out for V in sp.codomain] |
| 15 | + direction_sign = [isdual(V) ? -1 : 1 for V in sp.codomain] |
| 16 | + if sectortype(sp) <: Trivial |
| 17 | + sizes = last.(last.(indices)) |
| 18 | + index = map(eachindex(indices)) do i |
| 19 | + id = ids[i] |
| 20 | + dir = direction[i] |
| 21 | + tag = tags[i] |
| 22 | + plev = plevs[i] |
| 23 | + return Index(id, sizes[i], dir, tag, plev) |
| 24 | + end |
| 25 | + iten = ITensors.DenseTensor(T, undef, index) |
| 26 | + copyto!(iten.storage.data, t.data) |
| 27 | + return ITensors.itensor(iten) |
| 28 | + end |
| 29 | + isa_product = sectortype(sp) <: ProductSector |
| 30 | + if isa_product |
| 31 | + moduli = convert_to_modulus.(fieldtypes(sectortype(sp).parameters[1])) |
| 32 | + else |
| 33 | + moduli = convert_to_modulus.([sectortype(sp)]) |
| 34 | + end |
| 35 | + |
| 36 | + ismissing(qn_names) && (qn_names=itensor_standard_qn_names(length(moduli))) |
| 37 | + |
| 38 | + all_u1s = findall(x -> x == 1, moduli) |
| 39 | + multiply_by_two=false |
| 40 | + for i in eachindex(indices) |
| 41 | + space = indices[i] |
| 42 | + for (c, _) in space |
| 43 | + for i in all_u1s |
| 44 | + charge = get_charge(isa_product ? c[i] : c; rescale=true) |
| 45 | + if mod(charge,2)!=0 |
| 46 | + multiply_by_two=true |
| 47 | + break |
| 48 | + end |
| 49 | + end |
| 50 | + if multiply_by_two |
| 51 | + break |
| 52 | + end |
| 53 | + end |
| 54 | + if multiply_by_two |
| 55 | + break |
| 56 | + end |
| 57 | + end |
| 58 | + |
| 59 | + index_dict=[Dict{Sector, Int}() for _ in eachindex(indices)] |
| 60 | + |
| 61 | + indices = map(eachindex(indices)) do i |
| 62 | + space_tensorkit = indices[i] |
| 63 | + space = map(x->construct_QN(x[1],direction_sign[i],qn_names,moduli, multiply_by_two, isa_product)=>x[2], space_tensorkit) |
| 64 | + index_dict[i] = Dict(zip(first.(space_tensorkit),eachindex(space))) |
| 65 | + |
| 66 | + id = ids[i] |
| 67 | + dir = direction[i] |
| 68 | + tag = tags[i] |
| 69 | + plev = plevs[i] |
| 70 | + return Index(id, space, dir, tag, plev) |
| 71 | + end |
| 72 | + |
| 73 | + N=numind(t) |
| 74 | + |
| 75 | + all_blocks = ITensors.Block{N}[] |
| 76 | + for (f1,f2) in fusiontrees(t) |
| 77 | + push!(all_blocks, get_block(f1,f2,index_dict, Val(N))) |
| 78 | + end |
| 79 | + ITens = ITensors.BlockSparseTensor(T, undef, all_blocks, indices) |
| 80 | + for (f1, f2) in fusiontrees(t) |
| 81 | + b = get_block(f1,f2,index_dict, Val(N)) |
| 82 | + ITensors.blockview(ITens, b) .= t[f1, f2] |
| 83 | + end |
| 84 | + ITens = ITensors.itensor(ITens) |
| 85 | + check_flux(ITens) |
| 86 | + return combineblocks_itensor(ITens) |
| 87 | +end |
| 88 | + |
| 89 | +function construct_QN(x::Sector, sign::Int, qn_names, moduli, multiply_by_two::Bool=false, isa_product::Bool=false) |
| 90 | + charges = map(eachindex(moduli)) do i |
| 91 | + #charg = sign* |
| 92 | + |
| 93 | + charg = get_charge(isa_product ? x[i] : x; rescale=multiply_by_two) |
| 94 | + if !isone(moduli[i]) |
| 95 | + charg = mod(charg, moduli[i]) |
| 96 | + end |
| 97 | + return charg |
| 98 | + end |
| 99 | + return QN(map(i->(qn_names[i],charges[i],moduli[i]),eachindex(moduli))...) |
| 100 | +end |
| 101 | + |
| 102 | +function get_block(f1::FusionTree, f2::FusionTree, index_dict::Vector{Dict{Sector,Int}},::Val{N}) where {N} |
| 103 | + charges= ( |
| 104 | + (flag ? dual(c) : c for (flag, c) in zip(f1.isdual, f1.uncoupled))..., |
| 105 | + (flag ? dual(c) : c for (flag, c) in zip(f2.isdual, f2.uncoupled))..., |
| 106 | + ) |
| 107 | + blockinds=ntuple(i-> index_dict[i][charges[i]], N) |
| 108 | + return ITensors.Block{N}(blockinds) |
| 109 | +end |
| 110 | + |
| 111 | +function convert_to_modulus(::Type{U1Irrep}) |
| 112 | + return 1 |
| 113 | +end |
| 114 | +function convert_to_modulus(::Type{ZNIrrep{N}}) where {N} |
| 115 | + return N |
| 116 | +end |
| 117 | +function get_charge(x::ZNIrrep{N}; rescale::Bool=false) where {N} |
| 118 | + return Int(x.n) |
| 119 | +end |
| 120 | +function get_charge(x::U1Irrep; rescale::Bool=false) |
| 121 | + if !rescale |
| 122 | + return Int(x.charge*1) |
| 123 | + else |
| 124 | + return Int(x.charge*2) |
| 125 | + end |
| 126 | +end |
| 127 | + |
| 128 | +function itensor_standard_ids(N::Int) |
| 129 | + return [rand(index_id_rng(), ITensors.IDType) for _ in 1:N] |
| 130 | +end |
| 131 | +function itensor_standard_plevs(N::Int) |
| 132 | + return fill(0, N) |
| 133 | +end |
| 134 | +function itensor_standard_tags(N::Int) |
| 135 | + return ["" for _ in 1:N] |
| 136 | +end |
| 137 | +function itensor_standard_qn_names(N::Int) |
| 138 | + return [string(Char('A' + i - 1)) for i in 1:N] |
| 139 | +end |
| 140 | +function check_flux(T::ITensor) |
| 141 | + if !iszero(T) |
| 142 | + @assert iszero(flux(T)) |
| 143 | + end |
| 144 | +end |
0 commit comments