@@ -787,13 +787,34 @@ def step_function(x: Tensor) -> Tensor:
787
787
self .any (index , unitary = g ) # type: ignore
788
788
return 0.0
789
789
790
+ def select_gate (self , which : Tensor , kraus : Sequence [Gate ], * index : int ) -> None :
791
+ """
792
+ Apply ``which``-th gate from ``kraus`` list, i.e. apply kraus[which]
793
+
794
+ :param which: Tensor of shape [] and dtype int
795
+ :type which: Tensor
796
+ :param kraus: A list of gate in the form of ``tc.gate`` or Tensor
797
+ :type kraus: Sequence[Gate]
798
+ :param index: the qubit lines the gate applied on
799
+ :type index: int
800
+ """
801
+ kraus = [k .tensor if isinstance (k , tn .Node ) else k for k in kraus ]
802
+ kraus = [gates .array_to_tensor (k ) for k in kraus ]
803
+ l = len (kraus )
804
+ r = backend .onehot (which , l )
805
+ r = backend .cast (r , dtype = dtypestr )
806
+ tensor = reduce (add , [r [i ] * kraus [i ] for i in range (l )])
807
+ self .any (* index , unitary = tensor ) # type: ignore
808
+
809
+ conditional_gate = select_gate
810
+
790
811
def unitary_kraus2 (
791
812
self ,
792
813
kraus : Sequence [Gate ],
793
814
* index : int ,
794
815
prob : Optional [Sequence [float ]] = None ,
795
816
status : Optional [float ] = None ,
796
- ) -> float :
817
+ ) -> Tensor :
797
818
# general impl from Monte Carlo trajectory depolarizing above
798
819
# still jittable
799
820
# speed is similar to ``unitary_kraus``
@@ -811,7 +832,19 @@ def unitary_kraus(
811
832
* index : int ,
812
833
prob : Optional [Sequence [float ]] = None ,
813
834
status : Optional [float ] = None ,
814
- ) -> float :
835
+ ) -> Tensor :
836
+ """
837
+ Apply unitary gates in ``kraus`` randomly based on corresponding ``prob``.
838
+
839
+ :param kraus: List of ``tc.gates.Gate`` or just Tensors
840
+ :type kraus: Sequence[Gate]
841
+ :param prob: prob list with the same size as ``kraus``, defaults to None
842
+ :type prob: Optional[Sequence[float]], optional
843
+ :param status: random seed between 0 to 1, defaults to None
844
+ :type status: Optional[float], optional
845
+ :return: shape [] int dtype tensor indicates which kraus gate is applied
846
+ :rtype: Tensor
847
+ """
815
848
# general impl from Monte Carlo trajectory depolarizing above
816
849
# still jittable
817
850
@@ -835,9 +868,10 @@ def _unitary_kraus_template(
835
868
get_gate_from_index : Optional [
836
869
Callable [[Tensor , Sequence [Tensor ]], Tensor ]
837
870
] = None ,
838
- ) -> float : # DRY
871
+ ) -> Tensor : # DRY
839
872
sites = len (index )
840
873
kraus = [k .tensor if isinstance (k , tn .Node ) else k for k in kraus ]
874
+ kraus = [gates .array_to_tensor (k ) for k in kraus ]
841
875
if prob is None :
842
876
prob = [
843
877
backend .real (backend .trace (backend .adjoint (k ) @ k ) / k .shape [0 ])
@@ -867,7 +901,7 @@ def step_function(x: Tensor) -> Tensor:
867
901
g = get_gate_from_index (r , kraus )
868
902
g = backend .reshape (g , [2 for _ in range (sites * 2 )])
869
903
self .any (* index , unitary = g ) # type: ignore
870
- return 0.0
904
+ return r
871
905
872
906
def _general_kraus_tf (
873
907
self ,
@@ -942,7 +976,7 @@ def _general_kraus_2(
942
976
kraus : Sequence [Gate ],
943
977
* index : int ,
944
978
status : Optional [float ] = None ,
945
- ) -> float :
979
+ ) -> Tensor :
946
980
# the graph building time is frustratingly slow, several minutes
947
981
# though running time is in terms of ms
948
982
# raw running time in terms of s
@@ -954,7 +988,7 @@ def _general_kraus_2(
954
988
# layerwise jit technique can greatly boost the staging time, see in /examples/mcnoise_boost.py
955
989
sites = len (index )
956
990
kraus_tensor = [k .tensor if isinstance (k , tn .Node ) else k for k in kraus ]
957
- # kraus_tensor = [k.tensor for k in kraus ]
991
+ kraus_tensor = [gates . array_to_tensor ( k ) for k in kraus_tensor ]
958
992
959
993
# tn with hole
960
994
newnodes , newfront = self ._copy ()
@@ -988,15 +1022,14 @@ def calculate_kraus_p(i: int) -> Tensor:
988
1022
for w , k in zip (prob , kraus_tensor )
989
1023
]
990
1024
991
- self .unitary_kraus2 (new_kraus , * index , prob = prob , status = status )
992
- return 0.0
1025
+ return self .unitary_kraus2 (new_kraus , * index , prob = prob , status = status )
993
1026
994
1027
def general_kraus (
995
1028
self ,
996
1029
kraus : Sequence [Gate ],
997
1030
* index : int ,
998
1031
status : Optional [float ] = None ,
999
- ) -> float :
1032
+ ) -> Tensor :
1000
1033
"""
1001
1034
Monte Carlo trajectory simulation of general Kraus channel whose Kraus operators cannot be
1002
1035
amplified to unitary operators. For unitary operators composed Kraus channel, :py:meth:`unitary_kraus`
0 commit comments