@@ -471,7 +471,7 @@ proj(ψ::QuantumObject{<:AbstractArray{T},KetQuantumObject}) where {T} = ψ * ψ
471471proj (ψ:: QuantumObject{<:AbstractArray{T},BraQuantumObject} ) where {T} = ψ' * ψ
472472
473473@doc raw """
474- ptrace(QO::QuantumObject, sel::Vector{Int} )
474+ ptrace(QO::QuantumObject, sel)
475475
476476[Partial trace](https://en.wikipedia.org/wiki/Partial_trace) of a quantum state `QO` leaving only the dimensions
477477with the indices present in the `sel` vector.
@@ -487,7 +487,7 @@ Quantum Object: type=Ket dims=[2, 2] size=(4,)
487487 0.0 + 0.0im
488488 0.0 + 0.0im
489489
490- julia> ptrace(ψ, [2] )
490+ julia> ptrace(ψ, 2 )
491491Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true
4924922×2 Matrix{ComplexF64}:
493493 0.0+0.0im 0.0+0.0im
@@ -504,63 +504,79 @@ Quantum Object: type=Ket dims=[2, 2] size=(4,)
504504 0.0 + 0.0im
505505 0.7071067811865475 + 0.0im
506506
507- julia> ptrace(ψ, [1] )
507+ julia> ptrace(ψ, 1 )
508508Quantum Object: type=Operator dims=[2] size=(2, 2) ishermitian=true
5095092×2 Matrix{ComplexF64}:
510510 0.5+0.0im 0.0+0.0im
511511 0.0+0.0im 0.5+0.0im
512512```
513513"""
514- function ptrace (QO:: QuantumObject{<:AbstractArray{T1} ,KetQuantumObject} , sel:: Vector{T2} ) where {T1,T2 <: Integer }
514+ function ptrace (QO:: QuantumObject{<:AbstractArray,KetQuantumObject} , sel:: Union{AbstractVector{Int},Tuple} )
515515 length (QO. dims) == 1 && return QO
516516
517- ρtr, dkeep = _ptrace_ket (QO. data, QO. dims, sel)
517+ ρtr, dkeep = _ptrace_ket (QO. data, QO. dims, SVector ( sel) )
518518 return QuantumObject (ρtr, dims = dkeep)
519519end
520520
521- ptrace (QO:: QuantumObject{<:AbstractArray{T1},BraQuantumObject} , sel:: Vector{T2} ) where {T1,T2<: Integer } =
522- ptrace (QO' , sel)
521+ ptrace (QO:: QuantumObject{<:AbstractArray,BraQuantumObject} , sel:: Union{AbstractVector{Int},Tuple} ) = ptrace (QO' , sel)
523522
524- function ptrace (QO:: QuantumObject{<:AbstractArray{T1} ,OperatorQuantumObject} , sel:: Vector{T2} ) where {T1,T2 <: Integer }
523+ function ptrace (QO:: QuantumObject{<:AbstractArray,OperatorQuantumObject} , sel:: Union{AbstractVector{Int},Tuple} )
525524 length (QO. dims) == 1 && return QO
526525
527- ρtr, dkeep = _ptrace_oper (QO. data, QO. dims, sel)
526+ ρtr, dkeep = _ptrace_oper (QO. data, QO. dims, SVector ( sel) )
528527 return QuantumObject (ρtr, dims = dkeep)
529528end
530- ptrace (QO:: QuantumObject , sel:: Int ) = ptrace (QO, [sel])
531-
532- function _ptrace_ket (QO:: AbstractArray{T1} , dims:: Vector{<:Integer} , sel:: Vector{T2} ) where {T1,T2<: Integer }
533- rd = dims
534- nd = length (rd)
535-
536- nd == 1 && return QO, rd
537-
538- dkeep = rd[sel]
539- qtrace = filter! (e -> e ∉ sel, Vector (1 : nd))
540- dtrace = @view (rd[qtrace])
529+ ptrace (QO:: QuantumObject , sel:: Int ) = ptrace (QO, SVector (sel))
530+
531+ function _ptrace_ket (QO:: AbstractArray , dims:: Union{SVector,MVector} , sel)
532+ nd = length (dims)
533+
534+ nd == 1 && return QO, dims
535+
536+ qtrace = filter (i -> i ∉ sel, 1 : nd)
537+ dkeep = dims[sel]
538+ dtrace = dims[qtrace]
539+ # Concatenate sel and qtrace without loosing the length information
540+ sel_qtrace = ntuple (Val (nd)) do i
541+ if i <= length (sel)
542+ @inbounds sel[i]
543+ else
544+ @inbounds qtrace[i- length (sel)]
545+ end
546+ end
541547
542- vmat = reshape (QO, reverse (rd )... )
543- topermute = nd + 1 .- vcat (sel, qtrace)
548+ vmat = reshape (QO, reverse (dims )... )
549+ topermute = nd + 1 .- sel_qtrace
544550 vmat = PermutedDimsArray (vmat, topermute)
545551 vmat = reshape (vmat, prod (dkeep), prod (dtrace))
546552
547553 return vmat * vmat' , dkeep
548554end
549555
550- function _ptrace_oper (QO:: AbstractArray{T1} , dims:: Vector{<:Integer} , sel:: Vector{T2} ) where {T1,T2<: Integer }
551- rd = dims
552- nd = length (rd)
553-
554- nd == 1 && return QO, rd
555-
556- dkeep = rd[sel]
557- qtrace = filter! (e -> e ∉ sel, Vector (1 : nd))
558- dtrace = @view (rd[qtrace])
556+ function _ptrace_oper (QO:: AbstractArray , dims:: Union{SVector,MVector} , sel)
557+ nd = length (dims)
558+
559+ nd == 1 && return QO, dims
560+
561+ qtrace = filter (i -> i ∉ sel, 1 : nd)
562+ dkeep = dims[sel]
563+ dtrace = dims[qtrace]
564+ # Concatenate sel and qtrace without loosing the length information
565+ qtrace_sel = ntuple (Val (2 * nd)) do i
566+ if i <= length (qtrace)
567+ @inbounds qtrace[i]
568+ elseif i <= 2 * length (qtrace)
569+ @inbounds qtrace[i- length (qtrace)] + nd
570+ elseif i <= 2 * length (qtrace) + length (sel)
571+ @inbounds sel[i- length (qtrace)- length (sel)]
572+ else
573+ @inbounds sel[i- length (qtrace)- 2 * length (sel)] + nd
574+ end
575+ end
559576
560- ρmat = reshape (QO, reverse! (repeat (rd, 2 ))... )
561- topermute = 2 * nd + 1 .- vcat (qtrace, qtrace .+ nd, sel, sel .+ nd)
562- reverse! (topermute)
563- ρmat = PermutedDimsArray (ρmat, topermute)
577+ ρmat = reshape (QO, reverse (vcat (dims, dims))... )
578+ topermute = 2 * nd + 1 .- qtrace_sel
579+ ρmat = PermutedDimsArray (ρmat, reverse (topermute))
564580
565581 # # TODO : Check if it works always
566582
@@ -639,7 +655,7 @@ function get_coherence(ρ::QuantumObject{<:AbstractArray,OperatorQuantumObject})
639655end
640656
641657@doc raw """
642- permute(A::QuantumObject, order::Vector{ Int})
658+ permute(A::QuantumObject, order::Union{AbstractVector{ Int},Tuple })
643659
644660Permute the tensor structure of a [`QuantumObject`](@ref) `A` according to the specified `order` list
645661
@@ -660,28 +676,36 @@ true
660676"""
661677function permute (
662678 A:: QuantumObject{<:AbstractArray{T},ObjType} ,
663- order:: AbstractVector{Int} ,
679+ order:: Union{ AbstractVector{Int},Tuple } ,
664680) where {T,ObjType<: Union{KetQuantumObject,BraQuantumObject,OperatorQuantumObject} }
665681 (length (order) != length (A. dims)) &&
666682 throw (ArgumentError (" The order list must have the same length as the number of subsystems (A.dims)" ))
667683
668684 ! isperm (order) && throw (ArgumentError (" $(order) is not a valid permutation of the subsystems (A.dims)" ))
669685
686+ _non_static_array_warning (" order" , order)
687+
688+ order_svector = SVector {length(order),Int} (order) # convert it to SVector for performance
689+
670690 # obtain the arguments: dims for reshape; perm for PermutedDimsArray
671- dims, perm = _dims_and_perm (A. type, A. dims, order , length (order ))
691+ dims, perm = _dims_and_perm (A. type, A. dims, order_svector , length (order_svector ))
672692
673- return QuantumObject (reshape (PermutedDimsArray (reshape (A. data, dims... ), perm), size (A)), A. type, A. dims[order])
693+ return QuantumObject (
694+ reshape (PermutedDimsArray (reshape (A. data, dims... ), Tuple (perm)), size (A)),
695+ A. type,
696+ A. dims[order_svector],
697+ )
674698end
675699
676700function _dims_and_perm (
677701 :: ObjType ,
678- dims:: AbstractVector{ Int} ,
702+ dims:: SVector{N, Int} ,
679703 order:: AbstractVector{Int} ,
680704 L:: Int ,
681- ) where {ObjType<: Union{KetQuantumObject,BraQuantumObject} }
682- return reverse (dims), reverse! ((L + 1 ) .- order)
705+ ) where {ObjType<: Union{KetQuantumObject,BraQuantumObject} ,N }
706+ return reverse (dims), reverse ((L + 1 ) .- order)
683707end
684708
685- function _dims_and_perm (:: OperatorQuantumObject , dims:: AbstractVector{ Int} , order:: AbstractVector{Int} , L:: Int )
686- return reverse! ([ dims; dims]) , reverse! ((2 * L + 1 ) .- [ order; order .+ L] )
709+ function _dims_and_perm (:: OperatorQuantumObject , dims:: SVector{N, Int} , order:: AbstractVector{Int} , L:: Int ) where {N}
710+ return reverse ( vcat ( dims, dims)) , reverse ((2 * L + 1 ) .- vcat ( order, order .+ L) )
687711end
0 commit comments