@@ -50,26 +50,63 @@ for op in (:(+), :(-), :(*))
5050 end
5151end
5252
53+ function check_mul_dims (from:: SVector{NA,AbstractSpace} , to:: SVector{NB,AbstractSpace} ) where {NA,NB}
54+ (from != to) && throw (
55+ DimensionMismatch (
56+ " The quantum object with dims = $from can not multiply a quantum object with dims = $to on the right-hand side." ,
57+ ),
58+ )
59+ return nothing
60+ end
61+
62+ for ADimType in (:Dimensions , :CompoundDimensions )
63+ for BDimType in (:Dimensions , :CompoundDimensions )
64+ if ADimType == BDimType == :Dimensions
65+ @eval begin
66+ function LinearAlgebra.:(* )(
67+ A:: AbstractQuantumObject{DT1,OperatorQuantumObject,$ADimType{NA}} ,
68+ B:: AbstractQuantumObject{DT2,OperatorQuantumObject,$BDimType{NB}} ,
69+ ) where {DT1,DT2,NA,NB}
70+ check_dims (A, B)
71+ QType = promote_op_type (A, B)
72+ return QType (A. data * B. data, Operator, A. dims)
73+ end
74+ end
75+ else
76+ @eval begin
77+ function LinearAlgebra.:(* )(
78+ A:: AbstractQuantumObject{DT1,OperatorQuantumObject,$ADimType{NA}} ,
79+ B:: AbstractQuantumObject{DT2,OperatorQuantumObject,$BDimType{NB}} ,
80+ ) where {DT1,DT2,NA,NB}
81+ check_mul_dims (A. from, B. to)
82+ QType = promote_op_type (A, B)
83+ return QType (A. data * B. data, Operator, CompoundDimensions (A. to, B. from))
84+ end
85+ end
86+ end
87+ end
88+ end
89+
5390function LinearAlgebra.:(* )(
5491 A:: AbstractQuantumObject{DT1,OperatorQuantumObject} ,
5592 B:: QuantumObject{DT2,KetQuantumObject} ,
5693) where {DT1,DT2}
57- check_dims (A , B)
58- return QuantumObject (A. data * B. data, Ket, A . dims )
94+ check_mul_dims (A . from , B. to )
95+ return QuantumObject (A. data * B. data, Ket, Dimensions (A . to) )
5996end
6097function LinearAlgebra.:(* )(
6198 A:: QuantumObject{DT1,BraQuantumObject} ,
6299 B:: AbstractQuantumObject{DT2,OperatorQuantumObject} ,
63100) where {DT1,DT2}
64- check_dims (A , B)
65- return QuantumObject (A. data * B. data, Bra, A . dims )
101+ check_mul_dims (A . from , B. to )
102+ return QuantumObject (A. data * B. data, Bra, Dimensions (B . from) )
66103end
67104function LinearAlgebra.:(* )(
68105 A:: QuantumObject{DT1,KetQuantumObject} ,
69106 B:: QuantumObject{DT2,BraQuantumObject} ,
70107) where {DT1,DT2}
71108 check_dims (A, B)
72- return QuantumObject (A. data * B. data, Operator, A. dims)
109+ return QuantumObject (A. data * B. data, Operator, A. dims) # to align with QuTiP, don't use kron(A, B) to do it.
73110end
74111function LinearAlgebra.:(* )(
75112 A:: QuantumObject{DT1,BraQuantumObject} ,
@@ -196,7 +233,7 @@ Lazy matrix transpose of the [`AbstractQuantumObject`](@ref).
196233LinearAlgebra. transpose (
197234 A:: AbstractQuantumObject{DT,OpType} ,
198235) where {DT,OpType<: Union{OperatorQuantumObject,SuperOperatorQuantumObject} } =
199- get_typename_wrapper (A)(transpose (A. data), A. type, A. dims)
236+ get_typename_wrapper (A)(transpose (A. data), A. type, transpose ( A. dims) )
200237
201238@doc raw """
202239 A'
@@ -211,13 +248,15 @@ Lazy adjoint (conjugate transposition) of the [`AbstractQuantumObject`](@ref)
211248LinearAlgebra. adjoint (
212249 A:: AbstractQuantumObject{DT,OpType} ,
213250) where {DT,OpType<: Union{OperatorQuantumObject,SuperOperatorQuantumObject} } =
214- get_typename_wrapper (A)(adjoint (A. data), A. type, A. dims)
215- LinearAlgebra. adjoint (A:: QuantumObject{DT,KetQuantumObject} ) where {DT} = QuantumObject (adjoint (A. data), Bra, A. dims)
216- LinearAlgebra. adjoint (A:: QuantumObject{DT,BraQuantumObject} ) where {DT} = QuantumObject (adjoint (A. data), Ket, A. dims)
251+ get_typename_wrapper (A)(adjoint (A. data), A. type, transpose (A. dims))
252+ LinearAlgebra. adjoint (A:: QuantumObject{DT,KetQuantumObject} ) where {DT} =
253+ QuantumObject (adjoint (A. data), Bra, transpose (A. dims))
254+ LinearAlgebra. adjoint (A:: QuantumObject{DT,BraQuantumObject} ) where {DT} =
255+ QuantumObject (adjoint (A. data), Ket, transpose (A. dims))
217256LinearAlgebra. adjoint (A:: QuantumObject{DT,OperatorKetQuantumObject} ) where {DT} =
218- QuantumObject (adjoint (A. data), OperatorBra, A. dims)
257+ QuantumObject (adjoint (A. data), OperatorBra, transpose ( A. dims) )
219258LinearAlgebra. adjoint (A:: QuantumObject{DT,OperatorBraQuantumObject} ) where {DT} =
220- QuantumObject (adjoint (A. data), OperatorKet, A. dims)
259+ QuantumObject (adjoint (A. data), OperatorKet, transpose ( A. dims) )
221260
222261@doc raw """
223262 inv(A::AbstractQuantumObject)
@@ -557,14 +596,19 @@ function ptrace(QO::QuantumObject{<:AbstractArray,KetQuantumObject}, sel::Union{
557596 (n_d == 1 ) && return ket2dm (QO) # ptrace should always return Operator
558597 end
559598
599+ dimslist = dims_to_list (QO. dims)
560600 _sort_sel = sort (SVector {length(sel),Int} (sel))
561- ρtr, dkeep = _ptrace_ket (QO. data, QO . dims , _sort_sel)
562- return QuantumObject (ρtr, type = Operator, dims = dkeep)
601+ ρtr, dkeep = _ptrace_ket (QO. data, dimslist , _sort_sel)
602+ return QuantumObject (ρtr, type = Operator, dims = Dimensions ( dkeep) )
563603end
564604
565605ptrace (QO:: QuantumObject{<:AbstractArray,BraQuantumObject} , sel:: Union{AbstractVector{Int},Tuple} ) = ptrace (QO' , sel)
566606
567607function ptrace (QO:: QuantumObject{<:AbstractArray,OperatorQuantumObject} , sel:: Union{AbstractVector{Int},Tuple} )
608+ isa (QO. dims, CompoundDimensions) &&
609+ (QO. to != QO. from) &&
610+ throw (ArgumentError (" Invalid partial trace for dims = $(QO. dims) " ))
611+
568612 _non_static_array_warning (" sel" , sel)
569613
570614 n_s = length (sel)
@@ -580,9 +624,10 @@ function ptrace(QO::QuantumObject{<:AbstractArray,OperatorQuantumObject}, sel::U
580624 (n_d == 1 ) && return QO
581625 end
582626
627+ dimslist = dims_to_list (QO. to)
583628 _sort_sel = sort (SVector {length(sel),Int} (sel))
584- ρtr, dkeep = _ptrace_oper (QO. data, QO . dims , _sort_sel)
585- return QuantumObject (ρtr, type = Operator, dims = dkeep)
629+ ρtr, dkeep = _ptrace_oper (QO. data, dimslist , _sort_sel)
630+ return QuantumObject (ρtr, type = Operator, dims = Dimensions ( dkeep) )
586631end
587632ptrace (QO:: QuantumObject , sel:: Int ) = ptrace (QO, SVector (sel))
588633
@@ -758,24 +803,31 @@ function permute(
758803 order_svector = SVector {length(order),Int} (order) # convert it to SVector for performance
759804
760805 # obtain the arguments: dims for reshape; perm for PermutedDimsArray
761- dims, perm = _dims_and_perm (A. type, A. dims, order_svector, length (order_svector))
806+ dimslist = dims_to_list (A. dims)
807+ dims, perm = _dims_and_perm (A. type, dimslist, order_svector, length (order_svector))
762808
763809 return QuantumObject (
764810 reshape (permutedims (reshape (A. data, dims... ), Tuple (perm)), size (A)),
765811 A. type,
766- A. dims[order_svector],
812+ Dimensions ( A. dims. to [order_svector]) ,
767813 )
768814end
769815
770- function _dims_and_perm (
816+ _dims_and_perm (
771817 :: ObjType ,
772- dims :: SVector{N,Int} ,
818+ dimslist :: SVector{N,Int} ,
773819 order:: AbstractVector{Int} ,
774820 L:: Int ,
775- ) where {ObjType<: Union{KetQuantumObject,BraQuantumObject} ,N}
776- return reverse (dims), reverse ((L + 1 ) .- order)
777- end
821+ ) where {ObjType<: Union{KetQuantumObject,BraQuantumObject} ,N} = reverse (dimslist), reverse ((L + 1 ) .- order)
778822
779- function _dims_and_perm (:: OperatorQuantumObject , dims:: SVector{N,Int} , order:: AbstractVector{Int} , L:: Int ) where {N}
780- return reverse (vcat (dims, dims)), reverse ((2 * L + 1 ) .- vcat (order, order .+ L))
781- end
823+ # if dims originates from Dimensions
824+ _dims_and_perm (:: OperatorQuantumObject , dimslist:: SVector{N,Int} , order:: AbstractVector{Int} , L:: Int ) where {N} =
825+ reverse (vcat (dimslist, dimslist)), reverse ((2 * L + 1 ) .- vcat (order, order .+ L))
826+
827+ # if dims originates from CompoundDimensions
828+ _dims_and_perm (
829+ :: OperatorQuantumObject ,
830+ dimslist:: SVector{2,SVector{N,Int}} ,
831+ order:: AbstractVector{Int} ,
832+ L:: Int ,
833+ ) where {N} = reverse (vcat (dimslist[1 ], dimslist[2 ])), reverse ((2 * L + 1 ) .- vcat (order, order .+ L))
0 commit comments