@@ -4854,13 +4854,14 @@ void multiControlledMultiQubitUnitary(Qureg qureg, int* ctrls, int numCtrls, int
4854
4854
* \f[
4855
4855
\sum \limits_i^{\text{numOps}} K_i^\dagger K_i = I
4856
4856
* \f]
4857
- * where \f$ I \f$ is the identity matrix.
4857
+ * where \f$ I \f$ is the identity matrix. Use mixNonTPKrausMap() to relax this condition.
4858
4858
*
4859
4859
* Note that in distributed mode, this routine requires that each node contains at least 4 amplitudes.
4860
4860
* This means an q-qubit register can be distributed by at most 2^(q-2) numTargs nodes.
4861
4861
*
4862
4862
* @see
4863
4863
* - ::ComplexMatrix2
4864
+ * - mixNonTPKrausMap()
4864
4865
* - mixTwoQubitKrausMap()
4865
4866
* - mixMultiQubitKrausMap()
4866
4867
* - mixDephasing()
@@ -4894,7 +4895,8 @@ void mixKrausMap(Qureg qureg, int target, ComplexMatrix2 *ops, int numOps);
4894
4895
* \f[
4895
4896
\sum \limits_i^{\text{numOps}} K_i^\dagger K_i = I
4896
4897
* \f]
4897
- * where \f$ I \f$ is the identity matrix.
4898
+ * where \f$ I \f$ is the identity matrix. Use mixNonTPTwoQubitKrausMap() to relax this
4899
+ * this condition.
4898
4900
*
4899
4901
* \p targetQubit1 is treated as the \p least significant qubit in each op in \p ops.
4900
4902
*
@@ -4903,6 +4905,7 @@ void mixKrausMap(Qureg qureg, int target, ComplexMatrix2 *ops, int numOps);
4903
4905
*
4904
4906
* @see
4905
4907
* - ::ComplexMatrix4
4908
+ * - mixNonTPTwoQubitKrausMap()
4906
4909
* - mixMultiQubitKrausMap()
4907
4910
* - mixKrausMap()
4908
4911
*
@@ -4932,7 +4935,8 @@ void mixTwoQubitKrausMap(Qureg qureg, int target1, int target2, ComplexMatrix4 *
4932
4935
* \f[
4933
4936
\sum \limits_i^{\text{numOps}} K_i^\dagger K_i = I
4934
4937
* \f]
4935
- * where \f$ I \f$ is the identity matrix.
4938
+ * where \f$ I \f$ is the identity matrix. Use mixNonTPMultiQubitKrausMap() to relax
4939
+ * this condition.
4936
4940
*
4937
4941
* The first qubit in \p targets is treated as the \p least significant qubit in each op in \p ops.
4938
4942
*
@@ -4952,6 +4956,7 @@ void mixTwoQubitKrausMap(Qureg qureg, int target1, int target2, ComplexMatrix4 *
4952
4956
* @see
4953
4957
* - createComplexMatrixN()
4954
4958
* - initComplexMatrixN()
4959
+ * - mixNonTPMultiQubitKrausMap()
4955
4960
* - mixKrausMap()
4956
4961
* - mixTwoQubitKrausMap()
4957
4962
*
@@ -4974,6 +4979,131 @@ void mixTwoQubitKrausMap(Qureg qureg, int target1, int target2, ComplexMatrix4 *
4974
4979
*/
4975
4980
void mixMultiQubitKrausMap (Qureg qureg , int * targets , int numTargets , ComplexMatrixN * ops , int numOps );
4976
4981
4982
+ /** Apply a general non-trace-preserving single-qubit Kraus map to a density matrix,
4983
+ * as specified by at most four operators, \f$K_i\f$ (\p ops).
4984
+ * This effects
4985
+ * \f[
4986
+ \rho \to \sum\limits_i^{\text{numOps}} K_i \rho K_i^\dagger
4987
+ * \f]
4988
+ * where \f$K_i\f$ are permitted to be any matrix. This means the density matrix
4989
+ * can enter a non-physical state.
4990
+ *
4991
+ * Use mixKrausMap() to enforce that the channel is trace preserving and completely positive.
4992
+ *
4993
+ * Note that in distributed mode, this routine requires that each node contains at least 4 amplitudes.
4994
+ * This means an q-qubit register can be distributed by at most 2^(q-2) numTargs nodes.
4995
+ *
4996
+ * @see
4997
+ * - ::ComplexMatrix2
4998
+ * - mixKrausMap()
4999
+ * - mixNonTPTwoQubitKrausMap()
5000
+ * - mixNonTPMultiQubitKrausMap()
5001
+ *
5002
+ * @ingroup decoherence
5003
+ * @param[in,out] qureg the density matrix to which to apply the map
5004
+ * @param[in] target the target qubit of the map
5005
+ * @param[in] ops an array of at most 4 Kraus operators
5006
+ * @param[in] numOps the number of operators in \p ops which must be >0 and <= 4.
5007
+ * @throws invalidQuESTInputError()
5008
+ * - if \p qureg is not a density matrix
5009
+ * - if \p target is outside of [0, \p qureg.numQubitsRepresented)
5010
+ * - if \p numOps is outside [1, 4]
5011
+ * - if a node cannot fit 4 amplitudes in distributed mode
5012
+ * @author Tyson Jones
5013
+ * @author Balint Koczor (backend code)
5014
+ */
5015
+ void mixNonTPKrausMap (Qureg qureg , int target , ComplexMatrix2 * ops , int numOps );
5016
+
5017
+ /** Apply a general non-trace-preserving two-qubit Kraus map to a density matrix,
5018
+ * as specified by at most sixteen operators, \f$K_i\f$ (\p ops).
5019
+ *
5020
+ * This effects
5021
+ * \f[
5022
+ \rho \to \sum\limits_i^{\text{numOps}} K_i \rho K_i^\dagger
5023
+ * \f]
5024
+ * where the matrices \f$K_i\f$ are unconstrained, and hence the effective map is permitted
5025
+ * to be non-completely-positive and non-trace-preserving.
5026
+ * Use mixTwoQubitKrausMap() to enforce that the map be completely positive.
5027
+ *
5028
+ * \p targetQubit1 is treated as the \p least significant qubit in each op in \p ops.
5029
+ *
5030
+ * Note that in distributed mode, this routine requires that each node contains at least 16 amplitudes.
5031
+ * This means an q-qubit register can be distributed by at most 2^(q-4) numTargs nodes.
5032
+ *
5033
+ * @see
5034
+ * - ::ComplexMatrix4
5035
+ * - mixTwoQubitKrausMap()
5036
+ * - mixNonTPKrausMap()
5037
+ * - mixNonTPMultiQubitKrausMap()
5038
+ *
5039
+ * @ingroup decoherence
5040
+ * @param[in,out] qureg the density matrix to which to apply the map
5041
+ * @param[in] target1 the least significant target qubit in \p ops
5042
+ * @param[in] target2 the most significant target qubit in \p ops
5043
+ * @param[in] ops an array of at most 16 Kraus operators
5044
+ * @param[in] numOps the number of operators in \p ops which must be >0 and <= 16.
5045
+ * @throws invalidQuESTInputError()
5046
+ * - if \p qureg is not a density matrix
5047
+ * - if either \p target1 or \p target2 is outside of [0, \p qureg.numQubitsRepresented)
5048
+ * - if \p target1 = \p target2
5049
+ * - if \p numOps is outside [1, 16]
5050
+ * - if a node cannot fit 16 amplitudes in distributed mode
5051
+ * @author Tyson Jones
5052
+ * @author Balint Koczor (backend code)
5053
+ */
5054
+ void mixNonTPTwoQubitKrausMap (Qureg qureg , int target1 , int target2 , ComplexMatrix4 * ops , int numOps );
5055
+
5056
+ /** Apply a general N-qubit non-trace-preserving Kraus map to a density matrix,
5057
+ * as specified by at most (2N)^2 operators.
5058
+ *
5059
+ * This effects
5060
+ * \f[
5061
+ \rho \to \sum\limits_i^{\text{numOps}} K_i \rho K_i^\dagger
5062
+ * \f]
5063
+ * where the matrices \f$ K_i \f$ are unconstrained, and hence the effective map is permitted
5064
+ * to be non-completely-positive and non-trace-preserving.
5065
+ * Use mixMultiQubitKrausMap() to enforce that the map be completely positive.
5066
+ *
5067
+ * The first qubit in \p targets is treated as the \p least significant qubit in each op in \p ops.
5068
+ *
5069
+ * Note that in distributed mode, this routine requires that each node contains at least (2N)^2 amplitudes.
5070
+ * This means an q-qubit register can be distributed by at most 2^(q-2)/N^2 nodes.
5071
+ *
5072
+ * Note too that this routine internally creates a 'superoperator'; a complex matrix of dimensions
5073
+ * 2^(2*numTargets) by 2^(2*numTargets). Therefore, invoking this function incurs,
5074
+ * for numTargs={1,2,3,4,5, ...}, an additional memory overhead of (at double-precision)
5075
+ * {0.25 KiB, 4 KiB, 64 KiB, 1 MiB, 16 MiB, ...} (respectively).
5076
+ * At quad precision (usually 10 B per number, but possibly 16 B due to alignment),
5077
+ * this costs at most double the amount of memory.
5078
+ * For numTargets < 4, this superoperator will be created in the runtime
5079
+ * stack. For numTargs >= 4, the superoperator will be allocated in the heap and
5080
+ * therefore this routine may suffer an anomalous slowdown.
5081
+ *
5082
+ * @see
5083
+ * - createComplexMatrixN()
5084
+ * - initComplexMatrixN()
5085
+ * - mixMultiQubitKrausMap()
5086
+ * - mixNonTPKrausMap()
5087
+ * - mixNonTPTwoQubitKrausMap()
5088
+ *
5089
+ * @ingroup decoherence
5090
+ * @param[in,out] qureg the density matrix to which to apply the map
5091
+ * @param[in] targets a list of target qubit indices, the first of which is treated as least significant in each op in \p ops
5092
+ * @param[in] numTargets the length of \p targets
5093
+ * @param[in] ops an array of at most (2N)^2 Kraus operators
5094
+ * @param[in] numOps the number of operators in \p ops which must be >0 and <= (2N)^2.
5095
+ * @throws invalidQuESTInputError()
5096
+ * - if \p qureg is not a density matrix
5097
+ * - if any target in \p targets is outside of [0, \p qureg.numQubitsRepresented)
5098
+ * - if any qubit in \p targets is repeated
5099
+ * - if \p numOps is outside [1, (2 \p numTargets)^2]
5100
+ * - if any ComplexMatrixN in \p ops does not have op.numQubits == \p numTargets
5101
+ * - if a node cannot fit (2N)^2 amplitudes in distributed mode
5102
+ * @author Tyson Jones
5103
+ * @author Balint Koczor (backend code)
5104
+ */
5105
+ void mixNonTPMultiQubitKrausMap (Qureg qureg , int * targets , int numTargets , ComplexMatrixN * ops , int numOps );
5106
+
4977
5107
/** Computes the Hilbert Schmidt distance between two density matrices \p a and \p b,
4978
5108
* defined as the Frobenius norm of the difference between them.
4979
5109
* That is, we define the Hilbert Schmidt distance
0 commit comments