QuEST_validation.c
Go to the documentation of this file.
1 // Distributed under MIT licence. See https://github.com/QuEST-Kit/QuEST/blob/master/LICENCE.txt for details
2 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 # include "QuEST.h"
18 # include "QuEST_precision.h"
19 # include "QuEST_internal.h"
20 # include "QuEST_validation.h"
21 
22 # include <stdio.h>
23 # include <stdlib.h>
24 # include <stdint.h>
25 
26 typedef enum {
78 } ErrorCode;
79 
80 static const char* errorMessages[] = {
81  [E_INVALID_NUM_RANKS] = "Invalid number of nodes. Distributed simulation can only make use of a power-of-2 number of node.",
82  [E_INVALID_NUM_CREATE_QUBITS] = "Invalid number of qubits. Must create >0.",
83  [E_INVALID_QUBIT_INDEX] = "Invalid qubit index. Must be >=0 and <numQubits.",
84  [E_INVALID_TARGET_QUBIT] = "Invalid target qubit. Must be >=0 and <numQubits.",
85  [E_INVALID_CONTROL_QUBIT] = "Invalid control qubit. Must be >=0 and <numQubits.",
86  [E_INVALID_STATE_INDEX] = "Invalid state index. Must be >=0 and <2^numQubits.",
87  [E_INVALID_AMP_INDEX] = "Invalid amplitude index. Must be >=0 and <2^numQubits.",
88  [E_INVALID_NUM_AMPS] = "Invalid number of amplitudes. Must be >=0 and <=2^numQubits.",
89  [E_INVALID_OFFSET_NUM_AMPS] = "More amplitudes given than exist in the statevector from the given starting index.",
90  [E_TARGET_IS_CONTROL] = "Control qubit cannot equal target qubit.",
91  [E_TARGET_IN_CONTROLS] = "Control qubits cannot include target qubit.",
92  [E_CONTROL_TARGET_COLLISION] = "Control and target qubits must be disjoint.",
93  [E_QUBITS_NOT_UNIQUE] = "The qubits must be unique.",
94  [E_TARGETS_NOT_UNIQUE] = "The target qubits must be unique.",
95  [E_CONTROLS_NOT_UNIQUE] = "The control qubits should be unique.",
96  [E_INVALID_NUM_QUBITS] = "Invalid number of qubits. Must be >0 and <=numQubits.",
97  [E_INVALID_NUM_TARGETS] = "Invalid number of target qubits. Must be >0 and <=numQubits.",
98  [E_INVALID_NUM_CONTROLS] = "Invalid number of control qubits. Must be >0 and <numQubits.",
99  [E_NON_UNITARY_MATRIX] = "Matrix is not unitary.",
100  [E_NON_UNITARY_COMPLEX_PAIR] = "Compact matrix formed by given complex numbers is not unitary.",
101  [E_ZERO_VECTOR] = "Invalid axis vector. Must be non-zero.",
102  [E_SYS_TOO_BIG_TO_PRINT] = "Invalid system size. Cannot print output for systems greater than 5 qubits.",
103  [E_COLLAPSE_STATE_ZERO_PROB] = "Can't collapse to state with zero probability.",
104  [E_INVALID_QUBIT_OUTCOME] = "Invalid measurement outcome -- must be either 0 or 1.",
105  [E_CANNOT_OPEN_FILE] = "Could not open file.",
106  [E_SECOND_ARG_MUST_BE_STATEVEC] = "Second argument must be a state-vector.",
107  [E_MISMATCHING_QUREG_DIMENSIONS] = "Dimensions of the qubit registers don't match.",
108  [E_MISMATCHING_QUREG_TYPES] = "Registers must both be state-vectors or both be density matrices.",
109  [E_DEFINED_ONLY_FOR_STATEVECS] = "Operation valid only for state-vectors.",
110  [E_DEFINED_ONLY_FOR_DENSMATRS] = "Operation valid only for density matrices.",
111  [E_INVALID_PROB] = "Probabilities must be in [0, 1].",
112  [E_UNNORM_PROBS] = "Probabilities must sum to ~1.",
113  [E_INVALID_ONE_QUBIT_DEPHASE_PROB] = "The probability of a single qubit dephase error cannot exceed 1/2, which maximally mixes.",
114  [E_INVALID_TWO_QUBIT_DEPHASE_PROB] = "The probability of a two-qubit qubit dephase error cannot exceed 3/4, which maximally mixes.",
115  [E_INVALID_ONE_QUBIT_DEPOL_PROB] = "The probability of a single qubit depolarising error cannot exceed 3/4, which maximally mixes.",
116  [E_INVALID_TWO_QUBIT_DEPOL_PROB] = "The probability of a two-qubit depolarising error cannot exceed 15/16, which maximally mixes.",
117  [E_INVALID_ONE_QUBIT_PAULI_PROBS] = "The probability of any X, Y or Z error cannot exceed the probability of no error.",
118  [E_INVALID_CONTROLS_BIT_STATE] = "The state of the control qubits must be a bit sequence (0s and 1s).",
119  [E_INVALID_PAULI_CODE] = "Invalid Pauli code. Codes must be 0 (or PAULI_I), 1 (PAULI_X), 2 (PAULI_Y) or 3 (PAULI_Z) to indicate the identity, X, Y and Z gates respectively.",
120  [E_INVALID_NUM_SUM_TERMS] = "Invalid number of terms in the Pauli sum. The number of terms must be >0.",
121  [E_CANNOT_FIT_MULTI_QUBIT_MATRIX] = "The specified matrix targets too many qubits; the batches of amplitudes to modify cannot all fit in a single distributed node's memory allocation.",
122  [E_INVALID_UNITARY_SIZE] = "The matrix size does not match the number of target qubits.",
123  [E_COMPLEX_MATRIX_NOT_INIT] = "The ComplexMatrixN was not successfully created (possibly insufficient memory available).",
124  [E_INVALID_NUM_ONE_QUBIT_KRAUS_OPS] = "At least 1 and at most 4 single qubit Kraus operators may be specified.",
125  [E_INVALID_NUM_TWO_QUBIT_KRAUS_OPS] = "At least 1 and at most 16 two-qubit Kraus operators may be specified.",
126  [E_INVALID_NUM_N_QUBIT_KRAUS_OPS] = "At least 1 and at most 4*N^2 of N-qubit Kraus operators may be specified.",
127  [E_INVALID_KRAUS_OPS] = "The specified Kraus map is not a completely positive, trace preserving map.",
128  [E_MISMATCHING_NUM_TARGS_KRAUS_SIZE] = "Every Kraus operator must be of the same number of qubits as the number of targets.",
129  [E_DISTRIB_QUREG_TOO_SMALL] = "Too few qubits. The created qureg must have at least one amplitude per node used in distributed simulation.",
130  [E_NUM_AMPS_EXCEED_TYPE] = "Too many qubits (max of log2(SIZE_MAX)). Cannot store the number of amplitudes per-node in the size_t type."
131 };
132 
133 void exitWithError(const char* msg, const char* func) {
134  printf("!!!\n");
135  printf("QuEST Error in function %s: %s\n", func, msg);
136  printf("!!!\n");
137  printf("exiting..\n");
138  exit(1);
139 }
140 
141 #pragma weak invalidQuESTInputError
142 void invalidQuESTInputError(const char* errMsg, const char* errFunc) {
143  exitWithError(errMsg, errFunc);
144 }
145 
146 void QuESTAssert(int isValid, ErrorCode code, const char* func){
147  if (!isValid) invalidQuESTInputError(errorMessages[code], func);
148 }
149 
150 int isComplexUnit(Complex alpha) {
151  return (absReal(1 - sqrt(alpha.real*alpha.real + alpha.imag*alpha.imag)) < REAL_EPS);
152 }
153 
154 int isVectorUnit(qreal ux, qreal uy, qreal uz) {
155  return (absReal(1 - sqrt(ux*ux + uy*uy + uz*uz)) < REAL_EPS );
156 }
157 
159  return ( absReal( -1
160  + alpha.real*alpha.real
161  + alpha.imag*alpha.imag
162  + beta.real*beta.real
163  + beta.imag*beta.imag) < REAL_EPS );
164 }
165 
166 #define macro_isMatrixUnitary(m, dim, retVal) { \
167  /* elemRe_ and elemIm_ must not exist in caller scope */ \
168  qreal elemRe_, elemIm_; \
169  retVal = 1; \
170  /* check m * ConjugateTranspose(m) == Identity */ \
171  for (int r=0; r < (dim); r++) { \
172  for (int c=0; c < (dim); c++) { \
173  /* m[r][...] * ConjugateTranspose(m)[...][c] */ \
174  elemRe_ = 0; \
175  elemIm_ = 0; \
176  for (int i=0; i < (dim); i++) { \
177  /* m[r][i] * conj(m[c][i]) */ \
178  elemRe_ += m.real[r][i]*m.real[c][i] + m.imag[r][i]*m.imag[c][i]; \
179  elemIm_ += m.imag[r][i]*m.real[c][i] - m.real[r][i]*m.imag[c][i]; \
180  } \
181  /* check distance from identity */ \
182  if ((absReal(elemIm_) > REAL_EPS) || \
183  (r == c && absReal(elemRe_ - 1) > REAL_EPS) || \
184  (r != c && absReal(elemRe_ ) > REAL_EPS)) { \
185  retVal = 0; \
186  break; \
187  } \
188  } \
189  if (retVal == 0) \
190  break; \
191  } \
192 }
194  int dim = 2;
195  int retVal;
196  macro_isMatrixUnitary(u, dim, retVal);
197  return retVal;
198 }
200  int dim = 4;
201  int retVal;
202  macro_isMatrixUnitary(u, dim, retVal);
203  return retVal;
204 }
206  int dim = 1 << u.numQubits;
207  int retVal;
208  macro_isMatrixUnitary(u, dim, retVal);
209  return retVal;
210 }
211 
212 #define macro_isCompletelyPositiveMap(ops, numOps, opDim) { \
213  for (int r=0; r<(opDim); r++) { \
214  for (int c=0; c<(opDim); c++) { \
215  qreal elemRe_ = 0; \
216  qreal elemIm_ = 0; \
217  for (int n=0; n<(numOps); n++) { \
218  for (int k=0; k<(opDim); k++) { \
219  elemRe_ += ops[n].real[k][r]*ops[n].real[k][c] + ops[n].imag[k][r]*ops[n].imag[k][c]; \
220  elemIm_ += ops[n].real[k][r]*ops[n].imag[k][c] - ops[n].imag[k][r]*ops[n].real[k][c]; \
221  } \
222  } \
223  qreal dist_ = absReal(elemIm_) + absReal(elemRe_ - ((r==c)? 1:0)); \
224  if (dist_ > REAL_EPS) \
225  return 0; \
226  } \
227  } \
228  return 1; \
229 }
231  macro_isCompletelyPositiveMap(ops, numOps, 2);
232 }
234  macro_isCompletelyPositiveMap(ops, numOps, 4);
235 }
237  int opDim = 1 << ops[0].numQubits;
238  macro_isCompletelyPositiveMap(ops, numOps, opDim);
239 }
240 
241 int areUniqueQubits(int* qubits, int numQubits) {
242  long long int mask = 0;
243  long long int bit;
244  for (int q=0; q < numQubits; q++) {
245  bit = 1LL << qubits[q];
246  if (mask & bit)
247  return 0;
248  mask |= bit;
249  }
250  return 1;
251 }
252 
254 unsigned int calcLog2(long unsigned int num) {
255  unsigned int l = 0;
256  while (num >>= 1)
257  l++;
258  return l;
259 }
260 
261 void validateNumRanks(int numRanks, const char* caller) {
262 
263  /* silly but robust way to determine if numRanks is a power of 2,
264  * in lieu of bit-twiddling (e.g. AND with all-ones) which may be
265  * system / precsision dependent
266  */
267  int isValid = 0;
268  for (int exp2 = 1; exp2 <= numRanks; exp2 *= 2)
269  if (exp2 == numRanks)
270  isValid = 1;
271 
272  QuESTAssert(isValid, E_INVALID_NUM_RANKS, caller);
273 }
274 
275 void validateNumQubitsInQureg(int numQubits, int numRanks, const char* caller) {
276  QuESTAssert(numQubits>0, E_INVALID_NUM_CREATE_QUBITS, caller);
277 
278  // mustn't be more amplitudes than can fit in the type
279  unsigned int maxQubits = calcLog2(SIZE_MAX);
280  QuESTAssert( numQubits <= maxQubits, E_NUM_AMPS_EXCEED_TYPE, caller);
281 
282  // must be at least one amplitude per node
283  long unsigned int numAmps = (1<<numQubits);
284  QuESTAssert(numAmps >= numRanks, E_DISTRIB_QUREG_TOO_SMALL, caller);
285 }
286 
287 void validateNumQubitsInMatrix(int numQubits, const char* caller) {
288  QuESTAssert(numQubits>0, E_INVALID_NUM_QUBITS, caller);
289 }
290 
291 void validateStateIndex(Qureg qureg, long long int stateInd, const char* caller) {
292  long long int stateMax = 1LL << qureg.numQubitsRepresented;
293  QuESTAssert(stateInd>=0 && stateInd<stateMax, E_INVALID_STATE_INDEX, caller);
294 }
295 
296 void validateAmpIndex(Qureg qureg, long long int ampInd, const char* caller) {
297  long long int indMax = 1LL << qureg.numQubitsRepresented;
298  QuESTAssert(ampInd>=0 && ampInd<indMax, E_INVALID_AMP_INDEX, caller);
299 }
300 
301 void validateNumAmps(Qureg qureg, long long int startInd, long long int numAmps, const char* caller) {
302  validateAmpIndex(qureg, startInd, caller);
303  QuESTAssert(numAmps >= 0 && numAmps <= qureg.numAmpsTotal, E_INVALID_NUM_AMPS, caller);
304  QuESTAssert(numAmps + startInd <= qureg.numAmpsTotal, E_INVALID_OFFSET_NUM_AMPS, caller);
305 }
306 
307 void validateTarget(Qureg qureg, int targetQubit, const char* caller) {
308  QuESTAssert(targetQubit>=0 && targetQubit<qureg.numQubitsRepresented, E_INVALID_TARGET_QUBIT, caller);
309 }
310 
311 void validateControl(Qureg qureg, int controlQubit, const char* caller) {
312  QuESTAssert(controlQubit>=0 && controlQubit<qureg.numQubitsRepresented, E_INVALID_CONTROL_QUBIT, caller);
313 }
314 
315 void validateControlTarget(Qureg qureg, int controlQubit, int targetQubit, const char* caller) {
316  validateTarget(qureg, targetQubit, caller);
317  validateControl(qureg, controlQubit, caller);
318  QuESTAssert(controlQubit != targetQubit, E_TARGET_IS_CONTROL, caller);
319 }
320 
321 void validateUniqueTargets(Qureg qureg, int qubit1, int qubit2, const char* caller) {
322  validateTarget(qureg, qubit1, caller);
323  validateTarget(qureg, qubit2, caller);
324  QuESTAssert(qubit1 != qubit2, E_TARGETS_NOT_UNIQUE, caller);
325 }
326 
327 void validateNumTargets(Qureg qureg, const int numTargetQubits, const char* caller) {
328  QuESTAssert(numTargetQubits>0 && numTargetQubits<=qureg.numQubitsRepresented, E_INVALID_NUM_TARGETS, caller);
329 }
330 
331 void validateNumControls(Qureg qureg, const int numControlQubits, const char* caller) {
332  QuESTAssert(numControlQubits>0 && numControlQubits<qureg.numQubitsRepresented, E_INVALID_NUM_CONTROLS, caller);
333 }
334 
335 void validateMultiTargets(Qureg qureg, int* targetQubits, const int numTargetQubits, const char* caller) {
336  validateNumTargets(qureg, numTargetQubits, caller);
337  for (int i=0; i < numTargetQubits; i++)
338  validateTarget(qureg, targetQubits[i], caller);
339 
340  QuESTAssert(areUniqueQubits(targetQubits, numTargetQubits), E_TARGETS_NOT_UNIQUE, caller);
341 }
342 
343 void validateMultiControls(Qureg qureg, int* controlQubits, const int numControlQubits, const char* caller) {
344  validateNumControls(qureg, numControlQubits, caller);
345  for (int i=0; i < numControlQubits; i++)
346  validateControl(qureg, controlQubits[i], caller);
347 
348  QuESTAssert(areUniqueQubits(controlQubits, numControlQubits), E_CONTROLS_NOT_UNIQUE, caller);
349 }
350 
351 void validateMultiQubits(Qureg qureg, int* qubits, const int numQubits, const char* caller) {
352  QuESTAssert(numQubits>0 && numQubits<=qureg.numQubitsRepresented, E_INVALID_NUM_QUBITS, caller);
353  for (int i=0; i < numQubits; i++)
354  QuESTAssert(qubits[i]>=0 && qubits[i]<qureg.numQubitsRepresented, E_INVALID_QUBIT_INDEX, caller);
355 
356  QuESTAssert(areUniqueQubits(qubits, numQubits), E_QUBITS_NOT_UNIQUE, caller);
357 }
358 
359 void validateMultiControlsTarget(Qureg qureg, int* controlQubits, const int numControlQubits, const int targetQubit, const char* caller) {
360  validateTarget(qureg, targetQubit, caller);
361  validateMultiControls(qureg, controlQubits, numControlQubits, caller);
362  for (int i=0; i < numControlQubits; i++)
363  QuESTAssert(controlQubits[i] != targetQubit, E_TARGET_IN_CONTROLS, caller);
364 }
365 
366 void validateMultiControlsMultiTargets(Qureg qureg, int* controlQubits, const int numControlQubits, int* targetQubits, const int numTargetQubits, const char* caller) {
367  validateMultiControls(qureg, controlQubits, numControlQubits, caller);
368  validateMultiTargets(qureg, targetQubits, numTargetQubits, caller);
369  long long int ctrlMask = getQubitBitMask(controlQubits, numControlQubits);
370  long long int targMask = getQubitBitMask(targetQubits, numTargetQubits);
371  int overlap = ctrlMask & targMask;
372  QuESTAssert(!overlap, E_CONTROL_TARGET_COLLISION, caller);
373 }
374 
375 void validateControlState(int* controlState, const int numControlQubits, const char* caller) {
376  for (int i=0; i < numControlQubits; i++)
377  QuESTAssert(controlState[i] == 0 || controlState[i] == 1, E_INVALID_CONTROLS_BIT_STATE, caller);
378 }
379 
380 void validateMultiQubitMatrixFitsInNode(Qureg qureg, int numTargets, const char* caller) {
381  QuESTAssert(qureg.numAmpsPerChunk >= (1LL << numTargets), E_CANNOT_FIT_MULTI_QUBIT_MATRIX, caller);
382 }
383 
384 void validateOneQubitUnitaryMatrix(ComplexMatrix2 u, const char* caller) {
386 }
387 
388 void validateTwoQubitUnitaryMatrix(Qureg qureg, ComplexMatrix4 u, const char* caller) {
389  validateMultiQubitMatrixFitsInNode(qureg, 2, caller);
391 }
392 
393 void validateMatrixInit(ComplexMatrixN matr, const char* caller) {
394 
395  /* note that for (most) compilers which don't automatically initialise
396  * pointers to NULL, this can only be used to check the mallocs in createComplexMatrixN
397  * succeeded. It can not be used to differentiate whether a user actually attempted
398  * to initialise or create their ComplexMatrixN instance.
399  */
400  QuESTAssert(matr.real != NULL && matr.imag != NULL, E_COMPLEX_MATRIX_NOT_INIT, caller);
401 }
402 
403 void validateMultiQubitUnitaryMatrix(Qureg qureg, ComplexMatrixN u, int numTargs, const char* caller) {
404  validateMatrixInit(u, caller);
405  validateMultiQubitMatrixFitsInNode(qureg, numTargs, caller);
406  QuESTAssert(numTargs == u.numQubits, E_INVALID_UNITARY_SIZE, caller);
408 }
409 
410 void validateUnitaryComplexPair(Complex alpha, Complex beta, const char* caller) {
412 }
413 
414 void validateVector(Vector vec, const char* caller) {
415  QuESTAssert(getVectorMagnitude(vec) > REAL_EPS, E_ZERO_VECTOR, caller);
416 }
417 
418 void validateStateVecQureg(Qureg qureg, const char* caller) {
420 }
421 
422 void validateDensityMatrQureg(Qureg qureg, const char* caller) {
424 }
425 
426 void validateOutcome(int outcome, const char* caller) {
427  QuESTAssert(outcome==0 || outcome==1, E_INVALID_QUBIT_OUTCOME, caller);
428 }
429 
430 void validateMeasurementProb(qreal prob, const char* caller) {
431  QuESTAssert(prob>REAL_EPS, E_COLLAPSE_STATE_ZERO_PROB, caller);
432 }
433 
434 void validateMatchingQuregDims(Qureg qureg1, Qureg qureg2, const char *caller) {
436 }
437 
438 void validateMatchingQuregTypes(Qureg qureg1, Qureg qureg2, const char *caller) {
440 }
441 
442 void validateSecondQuregStateVec(Qureg qureg2, const char *caller) {
444 }
445 
446 void validateFileOpened(int found, const char* caller) {
447  QuESTAssert(found, E_CANNOT_OPEN_FILE, caller);
448 }
449 
450 void validateProb(qreal prob, const char* caller) {
451  QuESTAssert(prob >= 0 && prob <= 1, E_INVALID_PROB, caller);
452 }
453 
454 void validateNormProbs(qreal prob1, qreal prob2, const char* caller) {
455  validateProb(prob1, caller);
456  validateProb(prob2, caller);
457 
458  qreal sum = prob1 + prob2;
459  QuESTAssert(absReal(1 - sum) < REAL_EPS, E_UNNORM_PROBS, caller);
460 }
461 
462 void validateOneQubitDephaseProb(qreal prob, const char* caller) {
463  validateProb(prob, caller);
464  QuESTAssert(prob <= 1/2.0, E_INVALID_ONE_QUBIT_DEPHASE_PROB, caller);
465 }
466 
467 void validateTwoQubitDephaseProb(qreal prob, const char* caller) {
468  validateProb(prob, caller);
469  QuESTAssert(prob <= 3/4.0, E_INVALID_TWO_QUBIT_DEPHASE_PROB, caller);
470 }
471 
472 void validateOneQubitDepolProb(qreal prob, const char* caller) {
473  validateProb(prob, caller);
474  QuESTAssert(prob <= 3/4.0, E_INVALID_ONE_QUBIT_DEPOL_PROB, caller);
475 }
476 
477 void validateOneQubitDampingProb(qreal prob, const char* caller) {
478  validateProb(prob, caller);
479  QuESTAssert(prob <= 1.0, E_INVALID_ONE_QUBIT_DEPOL_PROB, caller);
480 }
481 
482 void validateTwoQubitDepolProb(qreal prob, const char* caller) {
483  validateProb(prob, caller);
484  QuESTAssert(prob <= 15/16.0, E_INVALID_TWO_QUBIT_DEPOL_PROB, caller);
485 }
486 
487 void validateOneQubitPauliProbs(qreal probX, qreal probY, qreal probZ, const char* caller) {
488  validateProb(probX, caller);
489  validateProb(probY, caller);
490  validateProb(probZ, caller);
491 
492  qreal probNoError = 1 - probX - probY - probZ;
493  QuESTAssert(probX <= probNoError, E_INVALID_ONE_QUBIT_PAULI_PROBS, caller);
494  QuESTAssert(probY <= probNoError, E_INVALID_ONE_QUBIT_PAULI_PROBS, caller);
495  QuESTAssert(probZ <= probNoError, E_INVALID_ONE_QUBIT_PAULI_PROBS, caller);
496 }
497 
498 void validatePauliCodes(enum pauliOpType* pauliCodes, int numPauliCodes, const char* caller) {
499  for (int i=0; i < numPauliCodes; i++) {
500  int code = pauliCodes[i];
501  QuESTAssert(
502  code==PAULI_I || code==PAULI_X || code==PAULI_Y || code==PAULI_Z,
503  E_INVALID_PAULI_CODE, caller);
504  }
505 }
506 
507 void validateNumPauliSumTerms(int numTerms, const char* caller) {
508  QuESTAssert(numTerms > 0, E_INVALID_NUM_SUM_TERMS, caller);
509 }
510 
511 void validateOneQubitKrausMap(Qureg qureg, ComplexMatrix2* ops, int numOps, const char* caller) {
512  int opNumQubits = 1;
513  int superOpNumQubits = 2*opNumQubits;
514  int maxNumOps = superOpNumQubits*superOpNumQubits;
515  QuESTAssert(numOps > 0 && numOps <= maxNumOps, E_INVALID_NUM_ONE_QUBIT_KRAUS_OPS, caller);
516 
517  validateMultiQubitMatrixFitsInNode(qureg, superOpNumQubits, caller);
518 
519  int isPos = isCompletelyPositiveMap2(ops, numOps);
520  QuESTAssert(isPos, E_INVALID_KRAUS_OPS, caller);
521 }
522 
523 void validateTwoQubitKrausMap(Qureg qureg, ComplexMatrix4* ops, int numOps, const char* caller) {
524  int opNumQubits = 2;
525  int superOpNumQubits = 2*opNumQubits;
526  int maxNumOps = superOpNumQubits*superOpNumQubits;
527  QuESTAssert(numOps > 0 && numOps <= maxNumOps, E_INVALID_NUM_TWO_QUBIT_KRAUS_OPS, caller);
528 
529  validateMultiQubitMatrixFitsInNode(qureg, superOpNumQubits, caller);
530 
531  int isPos = isCompletelyPositiveMap4(ops, numOps);
532  QuESTAssert(isPos, E_INVALID_KRAUS_OPS, caller);
533 }
534 
535 void validateMultiQubitKrausMap(Qureg qureg, int numTargs, ComplexMatrixN* ops, int numOps, const char* caller) {
536  int opNumQubits = numTargs;
537  int superOpNumQubits = 2*opNumQubits;
538  int maxNumOps = superOpNumQubits*superOpNumQubits;
539  QuESTAssert(numOps>0 && numOps <= maxNumOps, E_INVALID_NUM_N_QUBIT_KRAUS_OPS, caller);
540 
541  for (int n=0; n<numOps; n++) {
542  validateMatrixInit(ops[n], __func__);
543  QuESTAssert(ops[n].numQubits == numTargs, E_MISMATCHING_NUM_TARGS_KRAUS_SIZE, caller);
544  }
545 
546  validateMultiQubitMatrixFitsInNode(qureg, superOpNumQubits, caller);
547 
548  int isPos = isCompletelyPositiveMapN(ops, numOps);
549  QuESTAssert(isPos, E_INVALID_KRAUS_OPS, caller);
550 }
551 
552 #ifdef __cplusplus
553 }
554 #endif
void validateDensityMatrQureg(Qureg qureg, const char *caller)
Represents a 3-vector of real numbers.
Definition: QuEST.h:148
pauliOpType
Codes for specifying Pauli operators.
Definition: QuEST.h:96
@ E_INVALID_TWO_QUBIT_DEPOL_PROB
void validateMeasurementProb(qreal prob, const char *caller)
@ E_NUM_AMPS_EXCEED_TYPE
void validateTarget(Qureg qureg, int targetQubit, const char *caller)
@ E_INVALID_QUBIT_OUTCOME
void validateOutcome(int outcome, const char *caller)
int isMatrix2Unitary(ComplexMatrix2 u)
@ PAULI_Z
Definition: QuEST.h:96
@ E_INVALID_PAULI_CODE
void validateStateIndex(Qureg qureg, long long int stateInd, const char *caller)
@ E_NON_UNITARY_MATRIX
@ PAULI_I
Definition: QuEST.h:96
@ E_INVALID_ONE_QUBIT_DEPHASE_PROB
void validateStateVecQureg(Qureg qureg, const char *caller)
void validateMultiQubitMatrixFitsInNode(Qureg qureg, int numTargets, const char *caller)
void validateNumAmps(Qureg qureg, long long int startInd, long long int numAmps, const char *caller)
@ E_CANNOT_FIT_MULTI_QUBIT_MATRIX
@ E_INVALID_NUM_N_QUBIT_KRAUS_OPS
int isMatrix4Unitary(ComplexMatrix4 u)
void validateNumQubitsInQureg(int numQubits, int numRanks, const char *caller)
void validateMultiQubitUnitaryMatrix(Qureg qureg, ComplexMatrixN u, int numTargs, const char *caller)
@ E_MISMATCHING_QUREG_TYPES
int isCompletelyPositiveMap4(ComplexMatrix4 *ops, int numOps)
#define macro_isCompletelyPositiveMap(ops, numOps, opDim)
@ E_INVALID_QUBIT_INDEX
void validateProb(qreal prob, const char *caller)
@ E_NON_UNITARY_COMPLEX_PAIR
int isVectorUnit(qreal ux, qreal uy, qreal uz)
Represents a 4x4 matrix of complex numbers.
Definition: QuEST.h:125
void validateMultiTargets(Qureg qureg, int *targetQubits, const int numTargetQubits, const char *caller)
@ E_INVALID_CONTROLS_BIT_STATE
@ E_INVALID_NUM_TWO_QUBIT_KRAUS_OPS
Represents a general 2^N by 2^N matrix of complex numbers.
Definition: QuEST.h:136
void validateTwoQubitDepolProb(qreal prob, const char *caller)
@ E_SECOND_ARG_MUST_BE_STATEVEC
@ E_INVALID_CONTROL_QUBIT
void validateNumPauliSumTerms(int numTerms, const char *caller)
@ E_INVALID_NUM_SUM_TERMS
@ E_DEFINED_ONLY_FOR_STATEVECS
#define qreal
void validateMatrixInit(ComplexMatrixN matr, const char *caller)
int isCompletelyPositiveMap2(ComplexMatrix2 *ops, int numOps)
unsigned int calcLog2(long unsigned int num)
returns log2 of numbers which must be gauranteed to be 2^n
void validateControl(Qureg qureg, int controlQubit, const char *caller)
#define macro_isMatrixUnitary(m, dim, retVal)
@ PAULI_X
Definition: QuEST.h:96
int isComplexUnit(Complex alpha)
@ E_INVALID_PROB
int isMatrixNUnitary(ComplexMatrixN u)
@ E_QUBITS_NOT_UNIQUE
void validateVector(Vector vec, const char *caller)
void validateMultiControls(Qureg qureg, int *controlQubits, const int numControlQubits, const char *caller)
@ E_CONTROL_TARGET_COLLISION
long long int getQubitBitMask(int *qubits, const int numQubits)
Definition: QuEST_common.c:43
void invalidQuESTInputError(const char *errMsg, const char *errFunc)
An internal function called when invalid arguments are passed to a QuEST API call,...
@ E_DEFINED_ONLY_FOR_DENSMATRS
@ E_INVALID_KRAUS_OPS
@ E_INVALID_STATE_INDEX
void validateControlTarget(Qureg qureg, int controlQubit, int targetQubit, const char *caller)
void exitWithError(const char *msg, const char *func)
int areUniqueQubits(int *qubits, int numQubits)
@ E_TARGET_IN_CONTROLS
@ E_INVALID_NUM_QUBITS
long long int numAmpsPerChunk
Number of probability amplitudes held in stateVec by this process In the non-MPI version,...
Definition: QuEST.h:170
@ E_TARGET_IS_CONTROL
@ E_INVALID_UNITARY_SIZE
@ E_INVALID_ONE_QUBIT_PAULI_PROBS
void validateOneQubitDephaseProb(qreal prob, const char *caller)
@ E_MISMATCHING_NUM_TARGS_KRAUS_SIZE
@ E_INVALID_TARGET_QUBIT
@ E_COMPLEX_MATRIX_NOT_INIT
void validateMatchingQuregDims(Qureg qureg1, Qureg qureg2, const char *caller)
@ E_CANNOT_OPEN_FILE
@ E_DISTRIB_QUREG_TOO_SMALL
@ E_INVALID_NUM_ONE_QUBIT_KRAUS_OPS
@ PAULI_Y
Definition: QuEST.h:96
@ E_INVALID_AMP_INDEX
void validateOneQubitKrausMap(Qureg qureg, ComplexMatrix2 *ops, int numOps, const char *caller)
qreal ** real
Definition: QuEST.h:139
@ E_INVALID_NUM_RANKS
@ E_INVALID_TWO_QUBIT_DEPHASE_PROB
static const char * errorMessages[]
void QuESTAssert(int isValid, ErrorCode code, const char *func)
@ E_INVALID_NUM_AMPS
void validateOneQubitDepolProb(qreal prob, const char *caller)
@ E_COLLAPSE_STATE_ZERO_PROB
void validateMultiQubits(Qureg qureg, int *qubits, const int numQubits, const char *caller)
void validateNumControls(Qureg qureg, const int numControlQubits, const char *caller)
void validateTwoQubitKrausMap(Qureg qureg, ComplexMatrix4 *ops, int numOps, const char *caller)
@ E_TARGETS_NOT_UNIQUE
Represents a system of qubits.
Definition: QuEST.h:160
void validateNumQubitsInMatrix(int numQubits, const char *caller)
qreal ** imag
Definition: QuEST.h:140
@ E_MISMATCHING_QUREG_DIMENSIONS
ErrorCode
@ E_INVALID_NUM_CONTROLS
void validateNumTargets(Qureg qureg, const int numTargetQubits, const char *caller)
void validateTwoQubitUnitaryMatrix(Qureg qureg, ComplexMatrix4 u, const char *caller)
@ E_INVALID_NUM_CREATE_QUBITS
int isDensityMatrix
Whether this instance is a density-state representation.
Definition: QuEST.h:163
void validateMatchingQuregTypes(Qureg qureg1, Qureg qureg2, const char *caller)
int numQubits
Definition: QuEST.h:138
void validateAmpIndex(Qureg qureg, long long int ampInd, const char *caller)
qreal getVectorMagnitude(Vector vec)
Definition: QuEST_common.c:72
void validateOneQubitUnitaryMatrix(ComplexMatrix2 u, const char *caller)
void validateSecondQuregStateVec(Qureg qureg2, const char *caller)
@ E_UNNORM_PROBS
int numQubitsRepresented
The number of qubits represented in either the state-vector or density matrix.
Definition: QuEST.h:165
long long int numAmpsTotal
Total number of amplitudes, which are possibly distributed among machines.
Definition: QuEST.h:172
qreal real
Definition: QuEST.h:105
void validateControlState(int *controlState, const int numControlQubits, const char *caller)
int isCompletelyPositiveMapN(ComplexMatrixN *ops, int numOps)
qreal imag
Definition: QuEST.h:106
void validateFileOpened(int found, const char *caller)
void validateMultiQubitKrausMap(Qureg qureg, int numTargs, ComplexMatrixN *ops, int numOps, const char *caller)
@ E_INVALID_NUM_TARGETS
@ E_SYS_TOO_BIG_TO_PRINT
void validateNumRanks(int numRanks, const char *caller)
@ E_INVALID_OFFSET_NUM_AMPS
Represents one complex number.
Definition: QuEST.h:103
int isComplexPairUnitary(Complex alpha, Complex beta)
void validatePauliCodes(enum pauliOpType *pauliCodes, int numPauliCodes, const char *caller)
void validateUnitaryComplexPair(Complex alpha, Complex beta, const char *caller)
void validateMultiControlsMultiTargets(Qureg qureg, int *controlQubits, const int numControlQubits, int *targetQubits, const int numTargetQubits, const char *caller)
@ E_INVALID_ONE_QUBIT_DEPOL_PROB
void validateNormProbs(qreal prob1, qreal prob2, const char *caller)
@ E_SUCCESS
void validateOneQubitDampingProb(qreal prob, const char *caller)
@ E_ZERO_VECTOR
@ E_CONTROLS_NOT_UNIQUE
void validateUniqueTargets(Qureg qureg, int qubit1, int qubit2, const char *caller)
void validateTwoQubitDephaseProb(qreal prob, const char *caller)
Represents a 2x2 matrix of complex numbers.
Definition: QuEST.h:114
void validateOneQubitPauliProbs(qreal probX, qreal probY, qreal probZ, const char *caller)
void validateMultiControlsTarget(Qureg qureg, int *controlQubits, const int numControlQubits, const int targetQubit, const char *caller)