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 /* buffer for an error message which contains formatters. This must be global,
27  * since if a function writes to a local buffer then throws an error, the
28  * local buffer may be cleared and dangle before the error catcher can process it.
29  */
30 char errMsgBuffer[1024];
31 
32 typedef enum {
98 } ErrorCode;
99 
100 static const char* errorMessages[] = {
101  [E_INVALID_NUM_RANKS] = "Invalid number of nodes. Distributed simulation can only make use of a power-of-2 number of node.",
102  [E_INVALID_NUM_CREATE_QUBITS] = "Invalid number of qubits. Must create >0.",
103  [E_INVALID_QUBIT_INDEX] = "Invalid qubit index. Must be >=0 and <numQubits.",
104  [E_INVALID_TARGET_QUBIT] = "Invalid target qubit. Must be >=0 and <numQubits.",
105  [E_INVALID_CONTROL_QUBIT] = "Invalid control qubit. Must be >=0 and <numQubits.",
106  [E_INVALID_STATE_INDEX] = "Invalid state index. Must be >=0 and <2^numQubits.",
107  [E_INVALID_AMP_INDEX] = "Invalid amplitude index. Must be >=0 and <2^numQubits.",
108  [E_INVALID_ELEM_INDEX] = "Invalid element index. Must be >=0 and <2^numQubits.",
109  [E_INVALID_NUM_AMPS] = "Invalid number of amplitudes. Must be >=0 and <=2^numQubits.",
110  [E_INVALID_NUM_ELEMS] = "Invalid number of elements. Must be >=0 and <=2^numQubits.",
111  [E_INVALID_OFFSET_NUM_AMPS_QUREG] = "More amplitudes given than exist in the statevector from the given starting index.",
112  [E_INVALID_OFFSET_NUM_ELEMS_DIAG] = "More elements given than exist in the diagonal operator from the given starting index.",
113  [E_TARGET_IS_CONTROL] = "Control qubit cannot equal target qubit.",
114  [E_TARGET_IN_CONTROLS] = "Control qubits cannot include target qubit.",
115  [E_CONTROL_TARGET_COLLISION] = "Control and target qubits must be disjoint.",
116  [E_QUBITS_NOT_UNIQUE] = "The qubits must be unique.",
117  [E_TARGETS_NOT_UNIQUE] = "The target qubits must be unique.",
118  [E_CONTROLS_NOT_UNIQUE] = "The control qubits should be unique.",
119  [E_INVALID_NUM_QUBITS] = "Invalid number of qubits. Must be >0 and <=numQubits.",
120  [E_INVALID_NUM_TARGETS] = "Invalid number of target qubits. Must be >0 and <=numQubits.",
121  [E_INVALID_NUM_CONTROLS] = "Invalid number of control qubits. Must be >0 and <numQubits.",
122  [E_NON_UNITARY_MATRIX] = "Matrix is not unitary.",
123  [E_NON_UNITARY_COMPLEX_PAIR] = "Compact matrix formed by given complex numbers is not unitary.",
124  [E_ZERO_VECTOR] = "Invalid axis vector. Must be non-zero.",
125  [E_SYS_TOO_BIG_TO_PRINT] = "Invalid system size. Cannot print output for systems greater than 5 qubits.",
126  [E_COLLAPSE_STATE_ZERO_PROB] = "Can't collapse to state with zero probability.",
127  [E_INVALID_QUBIT_OUTCOME] = "Invalid measurement outcome -- must be either 0 or 1.",
128  [E_CANNOT_OPEN_FILE] = "Could not open file (%s).",
129  [E_SECOND_ARG_MUST_BE_STATEVEC] = "Second argument must be a state-vector.",
130  [E_MISMATCHING_QUREG_DIMENSIONS] = "Dimensions of the qubit registers don't match.",
131  [E_MISMATCHING_QUREG_TYPES] = "Registers must both be state-vectors or both be density matrices.",
132  [E_DEFINED_ONLY_FOR_STATEVECS] = "Operation valid only for state-vectors.",
133  [E_DEFINED_ONLY_FOR_DENSMATRS] = "Operation valid only for density matrices.",
134  [E_INVALID_PROB] = "Probabilities must be in [0, 1].",
135  [E_UNNORM_PROBS] = "Probabilities must sum to ~1.",
136  [E_INVALID_ONE_QUBIT_DEPHASE_PROB] = "The probability of a single qubit dephase error cannot exceed 1/2, which maximally mixes.",
137  [E_INVALID_TWO_QUBIT_DEPHASE_PROB] = "The probability of a two-qubit qubit dephase error cannot exceed 3/4, which maximally mixes.",
138  [E_INVALID_ONE_QUBIT_DEPOL_PROB] = "The probability of a single qubit depolarising error cannot exceed 3/4, which maximally mixes.",
139  [E_INVALID_TWO_QUBIT_DEPOL_PROB] = "The probability of a two-qubit depolarising error cannot exceed 15/16, which maximally mixes.",
140  [E_INVALID_ONE_QUBIT_PAULI_PROBS] = "The probability of any X, Y or Z error cannot exceed the probability of no error.",
141  [E_INVALID_CONTROLS_BIT_STATE] = "The state of the control qubits must be a bit sequence (0s and 1s).",
142  [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 operators respectively.",
143  [E_INVALID_NUM_SUM_TERMS] = "Invalid number of terms in the Pauli sum. The number of terms must be >0.",
144  [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.",
145  [E_INVALID_UNITARY_SIZE] = "The matrix size does not match the number of target qubits.",
146  [E_COMPLEX_MATRIX_NOT_INIT] = "The ComplexMatrixN was not successfully created (possibly insufficient memory available).",
147  [E_INVALID_NUM_ONE_QUBIT_KRAUS_OPS] = "At least 1 and at most 4 single qubit Kraus operators may be specified.",
148  [E_INVALID_NUM_TWO_QUBIT_KRAUS_OPS] = "At least 1 and at most 16 two-qubit Kraus operators may be specified.",
149  [E_INVALID_NUM_N_QUBIT_KRAUS_OPS] = "At least 1 and at most 4*N^2 of N-qubit Kraus operators may be specified.",
150  [E_INVALID_KRAUS_OPS] = "The specified Kraus map is not a completely positive, trace preserving map.",
151  [E_MISMATCHING_NUM_TARGS_KRAUS_SIZE] = "Every Kraus operator must be of the same number of qubits as the number of targets.",
152  [E_DISTRIB_QUREG_TOO_SMALL] = "Too few qubits. The created qureg must have at least one amplitude per node used in distributed simulation.",
153  [E_DISTRIB_DIAG_OP_TOO_SMALL] = "Too few qubits. The created DiagonalOp must contain at least one element per node used in distributed simulation.",
154  [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.",
155  [E_INVALID_PAULI_HAMIL_PARAMS] = "The number of qubits and terms in the PauliHamil must be strictly positive.",
156  [E_INVALID_PAULI_HAMIL_FILE_PARAMS] = "The number of qubits and terms in the PauliHamil file (%s) must be strictly positive.",
157  [E_CANNOT_PARSE_PAULI_HAMIL_FILE_COEFF] = "Failed to parse the next expected term coefficient in PauliHamil file (%s).",
158  [E_CANNOT_PARSE_PAULI_HAMIL_FILE_PAULI] = "Failed to parse the next expected Pauli code in PauliHamil file (%s).",
159  [E_INVALID_PAULI_HAMIL_FILE_PAULI_CODE] = "The PauliHamil file (%s) contained an invalid pauli code (%d). 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 operators respectively.",
160  [E_MISMATCHING_PAULI_HAMIL_QUREG_NUM_QUBITS] = "The PauliHamil must act on the same number of qubits as exist in the Qureg.",
161  [E_INVALID_TROTTER_ORDER] = "The Trotterisation order must be 1, or an even number (for higher-order Suzuki symmetrized expansions).",
162  [E_INVALID_TROTTER_REPS] = "The number of Trotter repetitions must be >=1.",
163  [E_MISMATCHING_QUREG_DIAGONAL_OP_SIZE] = "The qureg must represent an equal number of qubits as that in the applied diagonal operator.",
164  [E_DIAGONAL_OP_NOT_INITIALISED] = "The diagonal operator has not been initialised through createDiagonalOperator()."
165 };
166 
167 void exitWithError(const char* msg, const char* func) {
168  printf("!!!\n");
169  printf("QuEST Error in function %s: %s\n", func, msg);
170  printf("!!!\n");
171  printf("exiting..\n");
172  exit(1);
173 }
174 
175 #pragma weak invalidQuESTInputError
176 void invalidQuESTInputError(const char* errMsg, const char* errFunc) {
177  exitWithError(errMsg, errFunc);
178 }
179 
180 void QuESTAssert(int isValid, ErrorCode code, const char* func){
181  if (!isValid) invalidQuESTInputError(errorMessages[code], func);
182 }
183 
184 int isComplexUnit(Complex alpha) {
185  return (absReal(1 - sqrt(alpha.real*alpha.real + alpha.imag*alpha.imag)) < REAL_EPS);
186 }
187 
188 int isVectorUnit(qreal ux, qreal uy, qreal uz) {
189  return (absReal(1 - sqrt(ux*ux + uy*uy + uz*uz)) < REAL_EPS );
190 }
191 
193  return ( absReal( -1
194  + alpha.real*alpha.real
195  + alpha.imag*alpha.imag
196  + beta.real*beta.real
197  + beta.imag*beta.imag) < REAL_EPS );
198 }
199 
200 #define macro_isMatrixUnitary(m, dim, retVal) { \
201  /* elemRe_ and elemIm_ must not exist in caller scope */ \
202  qreal elemRe_, elemIm_; \
203  retVal = 1; \
204  /* check m * ConjugateTranspose(m) == Identity */ \
205  for (int r=0; r < (dim); r++) { \
206  for (int c=0; c < (dim); c++) { \
207  /* m[r][...] * ConjugateTranspose(m)[...][c] */ \
208  elemRe_ = 0; \
209  elemIm_ = 0; \
210  for (int i=0; i < (dim); i++) { \
211  /* m[r][i] * conj(m[c][i]) */ \
212  elemRe_ += m.real[r][i]*m.real[c][i] + m.imag[r][i]*m.imag[c][i]; \
213  elemIm_ += m.imag[r][i]*m.real[c][i] - m.real[r][i]*m.imag[c][i]; \
214  } \
215  /* check distance from identity */ \
216  if ((absReal(elemIm_) > REAL_EPS) || \
217  (r == c && absReal(elemRe_ - 1) > REAL_EPS) || \
218  (r != c && absReal(elemRe_ ) > REAL_EPS)) { \
219  retVal = 0; \
220  break; \
221  } \
222  } \
223  if (retVal == 0) \
224  break; \
225  } \
226 }
228  int dim = 2;
229  int retVal;
230  macro_isMatrixUnitary(u, dim, retVal);
231  return retVal;
232 }
234  int dim = 4;
235  int retVal;
236  macro_isMatrixUnitary(u, dim, retVal);
237  return retVal;
238 }
240  int dim = 1 << u.numQubits;
241  int retVal;
242  macro_isMatrixUnitary(u, dim, retVal);
243  return retVal;
244 }
245 
246 #define macro_isCompletelyPositiveMap(ops, numOps, opDim) { \
247  for (int r=0; r<(opDim); r++) { \
248  for (int c=0; c<(opDim); c++) { \
249  qreal elemRe_ = 0; \
250  qreal elemIm_ = 0; \
251  for (int n=0; n<(numOps); n++) { \
252  for (int k=0; k<(opDim); k++) { \
253  elemRe_ += ops[n].real[k][r]*ops[n].real[k][c] + ops[n].imag[k][r]*ops[n].imag[k][c]; \
254  elemIm_ += ops[n].real[k][r]*ops[n].imag[k][c] - ops[n].imag[k][r]*ops[n].real[k][c]; \
255  } \
256  } \
257  qreal dist_ = absReal(elemIm_) + absReal(elemRe_ - ((r==c)? 1:0)); \
258  if (dist_ > REAL_EPS) \
259  return 0; \
260  } \
261  } \
262  return 1; \
263 }
265  macro_isCompletelyPositiveMap(ops, numOps, 2);
266 }
268  macro_isCompletelyPositiveMap(ops, numOps, 4);
269 }
271  int opDim = 1 << ops[0].numQubits;
272  macro_isCompletelyPositiveMap(ops, numOps, opDim);
273 }
274 
276  return (code==PAULI_I || code==PAULI_X || code==PAULI_Y || code==PAULI_Z);
277 }
278 
279 int areUniqueQubits(int* qubits, int numQubits) {
280  long long int mask = 0;
281  long long int bit;
282  for (int q=0; q < numQubits; q++) {
283  bit = 1LL << qubits[q];
284  if (mask & bit)
285  return 0;
286  mask |= bit;
287  }
288  return 1;
289 }
290 
292 unsigned int calcLog2(long unsigned int num) {
293  unsigned int l = 0;
294  while (num >>= 1)
295  l++;
296  return l;
297 }
298 
299 void validateNumRanks(int numRanks, const char* caller) {
300 
301  /* silly but robust way to determine if numRanks is a power of 2,
302  * in lieu of bit-twiddling (e.g. AND with all-ones) which may be
303  * system / precsision dependent
304  */
305  int isValid = 0;
306  for (int exp2 = 1; exp2 <= numRanks; exp2 *= 2)
307  if (exp2 == numRanks)
308  isValid = 1;
309 
310  QuESTAssert(isValid, E_INVALID_NUM_RANKS, caller);
311 }
312 
313 void validateNumQubitsInQureg(int numQubits, int numRanks, const char* caller) {
314  QuESTAssert(numQubits>0, E_INVALID_NUM_CREATE_QUBITS, caller);
315 
316  // mustn't be more amplitudes than can fit in the type
317  unsigned int maxQubits = calcLog2(SIZE_MAX);
318  QuESTAssert( numQubits <= maxQubits, E_NUM_AMPS_EXCEED_TYPE, caller);
319 
320  // must be at least one amplitude per node
321  long unsigned int numAmps = (1UL<<numQubits);
322  QuESTAssert(numAmps >= numRanks, E_DISTRIB_QUREG_TOO_SMALL, caller);
323 }
324 
325 void validateNumQubitsInMatrix(int numQubits, const char* caller) {
326  QuESTAssert(numQubits>0, E_INVALID_NUM_QUBITS, caller);
327 }
328 
329 void validateNumQubitsInDiagOp(int numQubits, int numRanks, const char* caller) {
330  QuESTAssert(numQubits>0, E_INVALID_NUM_CREATE_QUBITS, caller);
331 
332  // mustn't be more amplitudes than can fit in the type
333  unsigned int maxQubits = calcLog2(SIZE_MAX);
334  QuESTAssert( numQubits <= maxQubits, E_NUM_AMPS_EXCEED_TYPE, caller);
335 
336  // must be at least one amplitude per node
337  long unsigned int numAmps = (1UL<<numQubits);
338  QuESTAssert(numAmps >= numRanks, E_DISTRIB_DIAG_OP_TOO_SMALL, caller);
339 }
340 
341 void validateStateIndex(Qureg qureg, long long int stateInd, const char* caller) {
342  long long int stateMax = 1LL << qureg.numQubitsRepresented;
343  QuESTAssert(stateInd>=0 && stateInd<stateMax, E_INVALID_STATE_INDEX, caller);
344 }
345 
346 void validateAmpIndex(Qureg qureg, long long int ampInd, const char* caller) {
347  long long int indMax = 1LL << qureg.numQubitsRepresented;
348  QuESTAssert(ampInd>=0 && ampInd<indMax, E_INVALID_AMP_INDEX, caller);
349 }
350 
351 void validateNumAmps(Qureg qureg, long long int startInd, long long int numAmps, const char* caller) {
352  validateAmpIndex(qureg, startInd, caller);
353  QuESTAssert(numAmps >= 0 && numAmps <= qureg.numAmpsTotal, E_INVALID_NUM_AMPS, caller);
354  QuESTAssert(numAmps + startInd <= qureg.numAmpsTotal, E_INVALID_OFFSET_NUM_AMPS_QUREG, caller);
355 }
356 
357 void validateNumElems(DiagonalOp op, long long int startInd, long long int numElems, const char* caller) {
358  long long int indMax = 1LL << op.numQubits;
359  QuESTAssert(startInd >= 0 && startInd < indMax, E_INVALID_ELEM_INDEX, caller);
360  QuESTAssert(numElems >= 0 && numElems <= indMax, E_INVALID_NUM_ELEMS, caller);
361  QuESTAssert(numElems + startInd <= indMax, E_INVALID_OFFSET_NUM_ELEMS_DIAG, caller);
362 }
363 
364 void validateTarget(Qureg qureg, int targetQubit, const char* caller) {
365  QuESTAssert(targetQubit>=0 && targetQubit<qureg.numQubitsRepresented, E_INVALID_TARGET_QUBIT, caller);
366 }
367 
368 void validateControl(Qureg qureg, int controlQubit, const char* caller) {
369  QuESTAssert(controlQubit>=0 && controlQubit<qureg.numQubitsRepresented, E_INVALID_CONTROL_QUBIT, caller);
370 }
371 
372 void validateControlTarget(Qureg qureg, int controlQubit, int targetQubit, const char* caller) {
373  validateTarget(qureg, targetQubit, caller);
374  validateControl(qureg, controlQubit, caller);
375  QuESTAssert(controlQubit != targetQubit, E_TARGET_IS_CONTROL, caller);
376 }
377 
378 void validateUniqueTargets(Qureg qureg, int qubit1, int qubit2, const char* caller) {
379  validateTarget(qureg, qubit1, caller);
380  validateTarget(qureg, qubit2, caller);
381  QuESTAssert(qubit1 != qubit2, E_TARGETS_NOT_UNIQUE, caller);
382 }
383 
384 void validateNumTargets(Qureg qureg, int numTargetQubits, const char* caller) {
385  QuESTAssert(numTargetQubits>0 && numTargetQubits<=qureg.numQubitsRepresented, E_INVALID_NUM_TARGETS, caller);
386 }
387 
388 void validateNumControls(Qureg qureg, int numControlQubits, const char* caller) {
389  QuESTAssert(numControlQubits>0 && numControlQubits<qureg.numQubitsRepresented, E_INVALID_NUM_CONTROLS, caller);
390 }
391 
392 void validateMultiTargets(Qureg qureg, int* targetQubits, int numTargetQubits, const char* caller) {
393  validateNumTargets(qureg, numTargetQubits, caller);
394  for (int i=0; i < numTargetQubits; i++)
395  validateTarget(qureg, targetQubits[i], caller);
396 
397  QuESTAssert(areUniqueQubits(targetQubits, numTargetQubits), E_TARGETS_NOT_UNIQUE, caller);
398 }
399 
400 void validateMultiControls(Qureg qureg, int* controlQubits, int numControlQubits, const char* caller) {
401  validateNumControls(qureg, numControlQubits, caller);
402  for (int i=0; i < numControlQubits; i++)
403  validateControl(qureg, controlQubits[i], caller);
404 
405  QuESTAssert(areUniqueQubits(controlQubits, numControlQubits), E_CONTROLS_NOT_UNIQUE, caller);
406 }
407 
408 void validateMultiQubits(Qureg qureg, int* qubits, int numQubits, const char* caller) {
409  QuESTAssert(numQubits>0 && numQubits<=qureg.numQubitsRepresented, E_INVALID_NUM_QUBITS, caller);
410  for (int i=0; i < numQubits; i++)
411  QuESTAssert(qubits[i]>=0 && qubits[i]<qureg.numQubitsRepresented, E_INVALID_QUBIT_INDEX, caller);
412 
413  QuESTAssert(areUniqueQubits(qubits, numQubits), E_QUBITS_NOT_UNIQUE, caller);
414 }
415 
416 void validateMultiControlsTarget(Qureg qureg, int* controlQubits, int numControlQubits, int targetQubit, const char* caller) {
417  validateTarget(qureg, targetQubit, caller);
418  validateMultiControls(qureg, controlQubits, numControlQubits, caller);
419  for (int i=0; i < numControlQubits; i++)
420  QuESTAssert(controlQubits[i] != targetQubit, E_TARGET_IN_CONTROLS, caller);
421 }
422 
423 void validateMultiControlsMultiTargets(Qureg qureg, int* controlQubits, int numControlQubits, int* targetQubits, int numTargetQubits, const char* caller) {
424  validateMultiControls(qureg, controlQubits, numControlQubits, caller);
425  validateMultiTargets(qureg, targetQubits, numTargetQubits, caller);
426  long long int ctrlMask = getQubitBitMask(controlQubits, numControlQubits);
427  long long int targMask = getQubitBitMask(targetQubits, numTargetQubits);
428  int overlap = ctrlMask & targMask;
429  QuESTAssert(!overlap, E_CONTROL_TARGET_COLLISION, caller);
430 }
431 
432 void validateControlState(int* controlState, int numControlQubits, const char* caller) {
433  for (int i=0; i < numControlQubits; i++)
434  QuESTAssert(controlState[i] == 0 || controlState[i] == 1, E_INVALID_CONTROLS_BIT_STATE, caller);
435 }
436 
437 void validateMultiQubitMatrixFitsInNode(Qureg qureg, int numTargets, const char* caller) {
438  QuESTAssert(qureg.numAmpsPerChunk >= (1LL << numTargets), E_CANNOT_FIT_MULTI_QUBIT_MATRIX, caller);
439 }
440 
441 void validateOneQubitUnitaryMatrix(ComplexMatrix2 u, const char* caller) {
443 }
444 
445 void validateTwoQubitUnitaryMatrix(Qureg qureg, ComplexMatrix4 u, const char* caller) {
446  validateMultiQubitMatrixFitsInNode(qureg, 2, caller);
448 }
449 
450 void validateMatrixInit(ComplexMatrixN matr, const char* caller) {
451 
452  /* note that for (most) compilers which don't automatically initialise
453  * pointers to NULL, this can only be used to check the mallocs in createComplexMatrixN
454  * succeeded. It can not be used to differentiate whether a user actually attempted
455  * to initialise or create their ComplexMatrixN instance.
456  */
457  QuESTAssert(matr.real != NULL && matr.imag != NULL, E_COMPLEX_MATRIX_NOT_INIT, caller);
458 }
459 
460 void validateMultiQubitMatrix(Qureg qureg, ComplexMatrixN u, int numTargs, const char* caller) {
461  validateMatrixInit(u, caller);
462  validateMultiQubitMatrixFitsInNode(qureg, numTargs, caller);
463  QuESTAssert(numTargs == u.numQubits, E_INVALID_UNITARY_SIZE, caller);
464 }
465 
466 void validateMultiQubitUnitaryMatrix(Qureg qureg, ComplexMatrixN u, int numTargs, const char* caller) {
467  validateMultiQubitMatrix(qureg, u, numTargs, caller);
469 }
470 
471 void validateUnitaryComplexPair(Complex alpha, Complex beta, const char* caller) {
473 }
474 
475 void validateVector(Vector vec, const char* caller) {
476  QuESTAssert(getVectorMagnitude(vec) > REAL_EPS, E_ZERO_VECTOR, caller);
477 }
478 
479 void validateStateVecQureg(Qureg qureg, const char* caller) {
481 }
482 
483 void validateDensityMatrQureg(Qureg qureg, const char* caller) {
485 }
486 
487 void validateOutcome(int outcome, const char* caller) {
488  QuESTAssert(outcome==0 || outcome==1, E_INVALID_QUBIT_OUTCOME, caller);
489 }
490 
491 void validateMeasurementProb(qreal prob, const char* caller) {
492  QuESTAssert(prob>REAL_EPS, E_COLLAPSE_STATE_ZERO_PROB, caller);
493 }
494 
495 void validateMatchingQuregDims(Qureg qureg1, Qureg qureg2, const char *caller) {
497 }
498 
499 void validateMatchingQuregTypes(Qureg qureg1, Qureg qureg2, const char *caller) {
501 }
502 
503 void validateSecondQuregStateVec(Qureg qureg2, const char *caller) {
505 }
506 
507 void validateFileOpened(int opened, char* fn, const char* caller) {
508  if (!opened) {
509 
512  }
513 }
514 
515 void validateProb(qreal prob, const char* caller) {
516  QuESTAssert(prob >= 0 && prob <= 1, E_INVALID_PROB, caller);
517 }
518 
519 void validateNormProbs(qreal prob1, qreal prob2, const char* caller) {
520  validateProb(prob1, caller);
521  validateProb(prob2, caller);
522 
523  qreal sum = prob1 + prob2;
524  QuESTAssert(absReal(1 - sum) < REAL_EPS, E_UNNORM_PROBS, caller);
525 }
526 
527 void validateOneQubitDephaseProb(qreal prob, const char* caller) {
528  validateProb(prob, caller);
529  QuESTAssert(prob <= 1/2.0, E_INVALID_ONE_QUBIT_DEPHASE_PROB, caller);
530 }
531 
532 void validateTwoQubitDephaseProb(qreal prob, const char* caller) {
533  validateProb(prob, caller);
534  QuESTAssert(prob <= 3/4.0, E_INVALID_TWO_QUBIT_DEPHASE_PROB, caller);
535 }
536 
537 void validateOneQubitDepolProb(qreal prob, const char* caller) {
538  validateProb(prob, caller);
539  QuESTAssert(prob <= 3/4.0, E_INVALID_ONE_QUBIT_DEPOL_PROB, caller);
540 }
541 
542 void validateOneQubitDampingProb(qreal prob, const char* caller) {
543  validateProb(prob, caller);
544  QuESTAssert(prob <= 1.0, E_INVALID_ONE_QUBIT_DEPOL_PROB, caller);
545 }
546 
547 void validateTwoQubitDepolProb(qreal prob, const char* caller) {
548  validateProb(prob, caller);
549  QuESTAssert(prob <= 15/16.0, E_INVALID_TWO_QUBIT_DEPOL_PROB, caller);
550 }
551 
552 void validateOneQubitPauliProbs(qreal probX, qreal probY, qreal probZ, const char* caller) {
553  validateProb(probX, caller);
554  validateProb(probY, caller);
555  validateProb(probZ, caller);
556 
557  qreal probNoError = 1 - probX - probY - probZ;
558  QuESTAssert(probX <= probNoError, E_INVALID_ONE_QUBIT_PAULI_PROBS, caller);
559  QuESTAssert(probY <= probNoError, E_INVALID_ONE_QUBIT_PAULI_PROBS, caller);
560  QuESTAssert(probZ <= probNoError, E_INVALID_ONE_QUBIT_PAULI_PROBS, caller);
561 }
562 
563 void validatePauliCodes(enum pauliOpType* pauliCodes, int numPauliCodes, const char* caller) {
564  for (int i=0; i < numPauliCodes; i++) {
565  enum pauliOpType code = pauliCodes[i];
567  }
568 }
569 
570 void validateNumPauliSumTerms(int numTerms, const char* caller) {
571  QuESTAssert(numTerms > 0, E_INVALID_NUM_SUM_TERMS, caller);
572 }
573 
574 void validateOneQubitKrausMap(Qureg qureg, ComplexMatrix2* ops, int numOps, const char* caller) {
575  int opNumQubits = 1;
576  int superOpNumQubits = 2*opNumQubits;
577  int maxNumOps = superOpNumQubits*superOpNumQubits;
578  QuESTAssert(numOps > 0 && numOps <= maxNumOps, E_INVALID_NUM_ONE_QUBIT_KRAUS_OPS, caller);
579 
580  validateMultiQubitMatrixFitsInNode(qureg, superOpNumQubits, caller);
581 
582  int isPos = isCompletelyPositiveMap2(ops, numOps);
583  QuESTAssert(isPos, E_INVALID_KRAUS_OPS, caller);
584 }
585 
586 void validateTwoQubitKrausMap(Qureg qureg, ComplexMatrix4* ops, int numOps, const char* caller) {
587  int opNumQubits = 2;
588  int superOpNumQubits = 2*opNumQubits;
589  int maxNumOps = superOpNumQubits*superOpNumQubits;
590  QuESTAssert(numOps > 0 && numOps <= maxNumOps, E_INVALID_NUM_TWO_QUBIT_KRAUS_OPS, caller);
591 
592  validateMultiQubitMatrixFitsInNode(qureg, superOpNumQubits, caller);
593 
594  int isPos = isCompletelyPositiveMap4(ops, numOps);
595  QuESTAssert(isPos, E_INVALID_KRAUS_OPS, caller);
596 }
597 
598 void validateMultiQubitKrausMap(Qureg qureg, int numTargs, ComplexMatrixN* ops, int numOps, const char* caller) {
599  int opNumQubits = numTargs;
600  int superOpNumQubits = 2*opNumQubits;
601  int maxNumOps = superOpNumQubits*superOpNumQubits;
602  QuESTAssert(numOps>0 && numOps <= maxNumOps, E_INVALID_NUM_N_QUBIT_KRAUS_OPS, caller);
603 
604  for (int n=0; n<numOps; n++) {
605  validateMatrixInit(ops[n], __func__);
606  QuESTAssert(ops[n].numQubits == numTargs, E_MISMATCHING_NUM_TARGS_KRAUS_SIZE, caller);
607  }
608 
609  validateMultiQubitMatrixFitsInNode(qureg, superOpNumQubits, caller);
610 
611  int isPos = isCompletelyPositiveMapN(ops, numOps);
612  QuESTAssert(isPos, E_INVALID_KRAUS_OPS, caller);
613 }
614 
615 void validateHamilParams(int numQubits, int numTerms, const char* caller) {
616  QuESTAssert(numQubits > 0 && numTerms > 0, E_INVALID_PAULI_HAMIL_PARAMS, caller);
617 }
618 
619 void validatePauliHamil(PauliHamil hamil, const char* caller) {
620  validateHamilParams(hamil.numQubits, hamil.numSumTerms, caller);
621  validatePauliCodes(hamil.pauliCodes, hamil.numSumTerms*hamil.numQubits, caller);
622 }
623 
624 void validateMatchingQuregPauliHamilDims(Qureg qureg, PauliHamil hamil, const char* caller) {
626 }
627 
628 void validateHamilFileParams(int numQubits, int numTerms, FILE* file, char* fn, const char* caller) {
629  if (!(numQubits > 0 && numTerms > 0)) {
630  fclose(file);
631 
634  }
635 }
636 
637 void validateHamilFileCoeffParsed(int parsed, PauliHamil h, FILE* file, char* fn, const char* caller) {
638  if (!parsed) {
640  fclose(file);
641 
644  }
645 }
646 
647 void validateHamilFilePauliParsed(int parsed, PauliHamil h, FILE* file, char* fn, const char* caller) {
648  if (!parsed) {
650  fclose(file);
651 
654  }
655 }
656 
657 void validateHamilFilePauliCode(enum pauliOpType code, PauliHamil h, FILE* file, char* fn, const char* caller) {
658  if (!isValidPauliCode(code)) {
660  fclose(file);
661 
664  }
665 }
666 
667 void validateTrotterParams(int order, int reps, const char* caller) {
668  int isEven = (order % 2) == 0;
669  QuESTAssert(order > 0 && (isEven || order==1), E_INVALID_TROTTER_ORDER, caller);
670  QuESTAssert(reps > 0, E_INVALID_TROTTER_REPS, caller);
671 }
672 
673 void validateDiagOpInit(DiagonalOp op, const char* caller) {
674  QuESTAssert(op.real != NULL && op.imag != NULL, E_DIAGONAL_OP_NOT_INITIALISED, caller);
675 }
676 
677 void validateDiagonalOp(Qureg qureg, DiagonalOp op, const char* caller) {
678  validateDiagOpInit(op, caller);
680 }
681 
682 #ifdef __cplusplus
683 }
684 #endif
void validateDensityMatrQureg(Qureg qureg, const char *caller)
Represents a 3-vector of real numbers.
Definition: QuEST.h:148
void validateMultiControlsTarget(Qureg qureg, int *controlQubits, int numControlQubits, int targetQubit, const char *caller)
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)
@ E_CANNOT_PARSE_PAULI_HAMIL_FILE_COEFF
int isMatrix2Unitary(ComplexMatrix2 u)
@ PAULI_Z
Definition: QuEST.h:96
void validateHamilFileCoeffParsed(int parsed, PauliHamil h, FILE *file, char *fn, const char *caller)
@ E_INVALID_PAULI_CODE
void validateStateIndex(Qureg qureg, long long int stateInd, const char *caller)
@ E_NON_UNITARY_MATRIX
void validateHamilParams(int numQubits, int numTerms, const char *caller)
@ 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
@ E_INVALID_ELEM_INDEX
int isMatrix4Unitary(ComplexMatrix4 u)
void validateNumQubitsInQureg(int numQubits, int numRanks, const char *caller)
void validateMultiQubitUnitaryMatrix(Qureg qureg, ComplexMatrixN u, int numTargs, const char *caller)
void validateHamilFilePauliParsed(int parsed, PauliHamil h, FILE *file, char *fn, const char *caller)
@ E_MISMATCHING_QUREG_TYPES
void validateNumControls(Qureg qureg, int numControlQubits, const char *caller)
int isCompletelyPositiveMap4(ComplexMatrix4 *ops, int numOps)
@ E_CANNOT_PARSE_PAULI_HAMIL_FILE_PAULI
#define macro_isCompletelyPositiveMap(ops, numOps, opDim)
@ E_INVALID_QUBIT_INDEX
void validateHamilFilePauliCode(enum pauliOpType code, PauliHamil h, FILE *file, char *fn, const char *caller)
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
@ E_INVALID_CONTROLS_BIT_STATE
@ E_INVALID_TROTTER_ORDER
@ E_INVALID_NUM_TWO_QUBIT_KRAUS_OPS
@ E_DISTRIB_DIAG_OP_TOO_SMALL
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)
void validateFileOpened(int opened, char *fn, const char *caller)
int isCompletelyPositiveMap2(ComplexMatrix2 *ops, int numOps)
@ E_INVALID_PAULI_HAMIL_FILE_PAULI_CODE
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
void validateNumTargets(Qureg qureg, int numTargetQubits, const char *caller)
int isMatrixNUnitary(ComplexMatrixN u)
@ E_QUBITS_NOT_UNIQUE
void validateVector(Vector vec, const char *caller)
void validateMultiQubits(Qureg qureg, int *qubits, int numQubits, const char *caller)
@ E_CONTROL_TARGET_COLLISION
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_OFFSET_NUM_AMPS_QUREG
@ E_INVALID_STATE_INDEX
void validateControlTarget(Qureg qureg, int controlQubit, int targetQubit, const char *caller)
void exitWithError(const char *msg, const char *func)
void validateDiagonalOp(Qureg qureg, DiagonalOp op, const char *caller)
qreal * imag
The imaginary values of the 2^numQubits complex elements.
Definition: QuEST.h:191
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:213
@ E_TARGET_IS_CONTROL
@ E_INVALID_PAULI_HAMIL_PARAMS
@ E_INVALID_UNITARY_SIZE
@ E_INVALID_ONE_QUBIT_PAULI_PROBS
void validateOneQubitDephaseProb(qreal prob, const char *caller)
enum pauliOpType * pauliCodes
The Pauli operators acting on each qubit, flattened over every operator.
Definition: QuEST.h:162
@ E_MISMATCHING_NUM_TARGS_KRAUS_SIZE
void validateControlState(int *controlState, int numControlQubits, const char *caller)
void validateMultiTargets(Qureg qureg, int *targetQubits, int numTargetQubits, const char *caller)
int isValidPauliCode(enum pauliOpType code)
@ 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
int numQubits
The number of qubits this operator can act on (informing its size)
Definition: QuEST.h:181
@ E_INVALID_NUM_ONE_QUBIT_KRAUS_OPS
int numSumTerms
The number of terms in the weighted sum, or the number of Pauli products.
Definition: QuEST.h:166
long long int getQubitBitMask(int *qubits, int numQubits)
Definition: QuEST_common.c:44
@ E_MISMATCHING_QUREG_DIAGONAL_OP_SIZE
Represents a diagonal complex operator on the full Hilbert state of a Qureg.
Definition: QuEST.h:178
@ PAULI_Y
Definition: QuEST.h:96
Represents a weighted sum of pauli products.
Definition: QuEST.h:158
void validateNumElems(DiagonalOp op, long long int startInd, long long int numElems, const char *caller)
@ 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
@ E_MISMATCHING_PAULI_HAMIL_QUREG_NUM_QUBITS
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 validateTwoQubitKrausMap(Qureg qureg, ComplexMatrix4 *ops, int numOps, const char *caller)
@ E_TARGETS_NOT_UNIQUE
Represents a system of qubits.
Definition: QuEST.h:203
void validateNumQubitsInMatrix(int numQubits, const char *caller)
qreal ** imag
Definition: QuEST.h:140
@ E_MISMATCHING_QUREG_DIMENSIONS
ErrorCode
@ E_INVALID_TROTTER_REPS
@ E_INVALID_NUM_CONTROLS
void validatePauliHamil(PauliHamil hamil, const char *caller)
void validateTwoQubitUnitaryMatrix(Qureg qureg, ComplexMatrix4 u, const char *caller)
char errMsgBuffer[1024]
@ E_INVALID_NUM_CREATE_QUBITS
void validateDiagOpInit(DiagonalOp op, const char *caller)
void validateMatchingQuregPauliHamilDims(Qureg qureg, PauliHamil hamil, const char *caller)
int isDensityMatrix
Whether this instance is a density-state representation.
Definition: QuEST.h:206
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)
@ E_INVALID_OFFSET_NUM_ELEMS_DIAG
qreal getVectorMagnitude(Vector vec)
Definition: QuEST_common.c:73
void validateHamilFileParams(int numQubits, int numTerms, FILE *file, char *fn, const char *caller)
void validateOneQubitUnitaryMatrix(ComplexMatrix2 u, const char *caller)
@ E_INVALID_PAULI_HAMIL_FILE_PARAMS
void validateSecondQuregStateVec(Qureg qureg2, const char *caller)
int numQubits
The number of qubits for which this Hamiltonian is defined.
Definition: QuEST.h:168
@ E_UNNORM_PROBS
int numQubitsRepresented
The number of qubits represented in either the state-vector or density matrix.
Definition: QuEST.h:208
long long int numAmpsTotal
Total number of amplitudes, which are possibly distributed among machines.
Definition: QuEST.h:215
void validateMultiControlsMultiTargets(Qureg qureg, int *controlQubits, int numControlQubits, int *targetQubits, int numTargetQubits, const char *caller)
qreal * real
The real values of the 2^numQubits complex elements.
Definition: QuEST.h:189
qreal real
Definition: QuEST.h:105
void destroyPauliHamil(PauliHamil h)
Destroy a PauliHamil instance, created with either createPauliHamil() or createPauliHamilFromFile().
Definition: QuEST.c:1163
int isCompletelyPositiveMapN(ComplexMatrixN *ops, int numOps)
qreal imag
Definition: QuEST.h:106
void validateMultiControls(Qureg qureg, int *controlQubits, int numControlQubits, const char *caller)
@ E_INVALID_NUM_ELEMS
void validateMultiQubitKrausMap(Qureg qureg, int numTargs, ComplexMatrixN *ops, int numOps, const char *caller)
void validateMultiQubitMatrix(Qureg qureg, ComplexMatrixN u, int numTargs, const char *caller)
void validateNumQubitsInDiagOp(int numQubits, int numRanks, const char *caller)
@ E_INVALID_NUM_TARGETS
@ E_SYS_TOO_BIG_TO_PRINT
void validateNumRanks(int numRanks, const char *caller)
Represents one complex number.
Definition: QuEST.h:103
void validateTrotterParams(int order, int reps, const char *caller)
int isComplexPairUnitary(Complex alpha, Complex beta)
void validatePauliCodes(enum pauliOpType *pauliCodes, int numPauliCodes, const char *caller)
@ E_DIAGONAL_OP_NOT_INITIALISED
void validateUnitaryComplexPair(Complex alpha, Complex beta, 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)