QuEST_common.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 
18 # include "QuEST.h"
19 # include "QuEST_internal.h"
20 # include "QuEST_precision.h"
21 # include "QuEST_validation.h"
22 # include "mt19937ar.h"
23 
24 #if defined(_WIN32) && ! defined(__MINGW32__)
25  #include <Windows.h>
26  #include <io.h>
27  #include <process.h>
28 #else
29  #include <unistd.h>
30  #include <sys/time.h>
31 #endif
32 
33 # include <sys/types.h>
34 # include <stdio.h>
35 # include <stdlib.h>
36 
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /* builds a bit-string where 1 indicates a qubit is present in this list */
43 long long int getQubitBitMask(int* qubits, const int numQubits) {
44 
45  long long int mask=0;
46  for (int i=0; i<numQubits; i++)
47  mask = mask | (1LL << qubits[i]);
48 
49  return mask;
50 }
51 
52 /* builds a bit-string where 1 indicates control qubits conditioned on 0 ('flipped') */
53 long long int getControlFlipMask(int* controlQubits, int* controlState, const int numControlQubits) {
54 
55  long long int mask=0;
56  for (int i=0; i<numControlQubits; i++)
57  if (controlState[i] == 0)
58  mask = mask | (1LL << controlQubits[i]);
59 
60  return mask;
61 }
62 
63 void ensureIndsIncrease(int* ind1, int* ind2) {
64 
65  if (*ind1 > *ind2) {
66  int copy = *ind1;
67  *ind1 = *ind2;
68  *ind2 = copy;
69  }
70 }
71 
73 
74  return sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
75 }
76 
78 
79  qreal mag = getVectorMagnitude(vec);
80  Vector unitVec = (Vector) {.x=vec.x/mag, .y=vec.y/mag, .z=vec.z/mag};
81  return unitVec;
82 }
83 
85 
86  Complex conjScalar;
87  conjScalar.real = scalar.real;
88  conjScalar.imag = - scalar.imag;
89  return conjScalar;
90 }
91 
92 #define macro_setConjugateMatrix(dest, src, dim) \
93  for (int i=0; i<dim; i++) \
94  for (int j=0; j<dim; j++) { \
95  dest.real[i][j] = src.real[i][j]; \
96  dest.imag[i][j] = - src.imag[i][j]; /* negative for conjugate */ \
97  }
99  ComplexMatrix2 conj;
100  macro_setConjugateMatrix(conj, src, 2);
101  return conj;
102 }
104  ComplexMatrix4 conj;
105  macro_setConjugateMatrix(conj, src, 4);
106  return conj;
107 }
109  int len = 1 << m.numQubits;
110  macro_setConjugateMatrix(m, m, len);
111 }
112 
113 void getComplexPairFromRotation(qreal angle, Vector axis, Complex* alpha, Complex* beta) {
114 
115  Vector unitAxis = getUnitVector(axis);
116  alpha->real = cos(angle/2.0);
117  alpha->imag = - sin(angle/2.0)*unitAxis.z;
118  beta->real = sin(angle/2.0)*unitAxis.y;
119  beta->imag = - sin(angle/2.0)*unitAxis.x;
120 }
121 
123 void getZYZRotAnglesFromComplexPair(Complex alpha, Complex beta, qreal* rz2, qreal* ry, qreal* rz1) {
124 
125  qreal alphaMag = sqrt(alpha.real*alpha.real + alpha.imag*alpha.imag);
126  *ry = 2.0 * acos(alphaMag);
127 
128  qreal alphaPhase = atan2(alpha.imag, alpha.real);
129  qreal betaPhase = atan2(beta.imag, beta.real);
130  *rz2 = - alphaPhase + betaPhase;
131  *rz1 = - alphaPhase - betaPhase;
132 }
133 
136 
137  qreal r0c0Phase = atan2(u.imag[0][0], u.real[0][0]);
138  qreal r1c1Phase = atan2(u.imag[1][1], u.real[1][1]);
139  *globalPhase = (r0c0Phase + r1c1Phase)/2.0;
140 
141  qreal cosPhase = cos(*globalPhase);
142  qreal sinPhase = sin(*globalPhase);
143  alpha->real = u.real[0][0]*cosPhase + u.imag[0][0]*sinPhase;
144  alpha->imag = u.imag[0][0]*cosPhase - u.real[0][0]*sinPhase;
145  beta->real = u.real[1][0]*cosPhase + u.imag[1][0]*sinPhase;
146  beta->imag = u.imag[1][0]*cosPhase - u.real[1][0]*sinPhase;
147 }
148 
149 void shiftIndices(int* indices, int numIndices, int shift) {
150  for (int j=0; j < numIndices; j++)
151  indices[j] += shift;
152 }
153 
154 int generateMeasurementOutcome(qreal zeroProb, qreal *outcomeProb) {
155 
156  // randomly choose outcome
157  int outcome;
158  if (zeroProb < REAL_EPS)
159  outcome = 1;
160  else if (1-zeroProb < REAL_EPS)
161  outcome = 0;
162  else
163  outcome = (genrand_real1() > zeroProb);
164 
165  // set probability of outcome
166  *outcomeProb = (outcome==0)? zeroProb : 1-zeroProb;
167 
168  return outcome;
169 }
170 
171 unsigned long int hashString(char *str){
172  unsigned long int hash = 5381;
173  int c;
174 
175  while ((c = *str++))
176  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
177 
178  return hash;
179 }
180 
181 void getQuESTDefaultSeedKey(unsigned long int *key){
182  // init MT random number generator with two keys -- time and pid
183  // for the MPI version, it is ok that all procs will get the same seed as random numbers will only be
184  // used by the master process
185 #if defined(_WIN32) && ! defined(__MINGW32__)
186 
187  unsigned long int pid = (unsigned long int) _getpid();
188  unsigned long int msecs = (unsigned long int) GetTickCount64();
189 
190  key[0] = msecs; key[1] = pid;
191 #else
192  struct timeval tv;
193  gettimeofday(&tv, NULL);
194 
195  double time_in_mill =
196  (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
197 
198  unsigned long int pid = getpid();
199  unsigned long int msecs = (unsigned long int) time_in_mill;
200 
201  key[0] = msecs; key[1] = pid;
202 #endif
203 }
204 
208 void seedQuEST(unsigned long int *seedArray, int numSeeds){
209  // init MT random number generator with user defined list of seeds
210  // for the MPI version, it is ok that all procs will get the same seed as random numbers will only be
211  // used by the master process
212  init_by_array(seedArray, numSeeds);
213 }
214 
215 void reportState(Qureg qureg){
216  FILE *state;
217  char filename[100];
218  long long int index;
219  sprintf(filename, "state_rank_%d.csv", qureg.chunkId);
220  state = fopen(filename, "w");
221  if (qureg.chunkId==0) fprintf(state, "real, imag\n");
222 
223  for(index=0; index<qureg.numAmpsPerChunk; index++){
224  # if QuEST_PREC==1 || QuEST_PREC==2
225  fprintf(state, "%.12f, %.12f\n", qureg.stateVec.real[index], qureg.stateVec.imag[index]);
226  # elif QuEST_PREC == 4
227  fprintf(state, "%.12Lf, %.12Lf\n", qureg.stateVec.real[index], qureg.stateVec.imag[index]);
228  #endif
229  }
230  fclose(state);
231 }
232 
234  long long int numAmps = 1LL << qureg.numQubitsInStateVec;
235  long long int numAmpsPerRank = numAmps/qureg.numChunks;
236  if (qureg.chunkId==0){
237  printf("QUBITS:\n");
238  printf("Number of qubits is %d.\n", qureg.numQubitsInStateVec);
239  printf("Number of amps is %lld.\n", numAmps);
240  printf("Number of amps per rank is %lld.\n", numAmpsPerRank);
241  }
242 }
243 
244 qreal statevec_getProbAmp(Qureg qureg, long long int index){
245  qreal real = statevec_getRealAmp(qureg, index);
246  qreal imag = statevec_getImagAmp(qureg, index);
247  return real*real + imag*imag;
248 }
249 
250 void statevec_phaseShift(Qureg qureg, const int targetQubit, qreal angle) {
251  Complex term;
252  term.real = cos(angle);
253  term.imag = sin(angle);
254  statevec_phaseShiftByTerm(qureg, targetQubit, term);
255 }
256 
257 void statevec_pauliZ(Qureg qureg, const int targetQubit) {
258  Complex term;
259  term.real = -1;
260  term.imag = 0;
261  statevec_phaseShiftByTerm(qureg, targetQubit, term);
262 }
263 
264 void statevec_sGate(Qureg qureg, const int targetQubit) {
265  Complex term;
266  term.real = 0;
267  term.imag = 1;
268  statevec_phaseShiftByTerm(qureg, targetQubit, term);
269 }
270 
271 void statevec_tGate(Qureg qureg, const int targetQubit) {
272  Complex term;
273  term.real = 1/sqrt(2);
274  term.imag = 1/sqrt(2);
275  statevec_phaseShiftByTerm(qureg, targetQubit, term);
276 }
277 
278 void statevec_sGateConj(Qureg qureg, const int targetQubit) {
279  Complex term;
280  term.real = 0;
281  term.imag = -1;
282  statevec_phaseShiftByTerm(qureg, targetQubit, term);
283 }
284 
285 void statevec_tGateConj(Qureg qureg, const int targetQubit) {
286  Complex term;
287  term.real = 1/sqrt(2);
288  term.imag = -1/sqrt(2);
289  statevec_phaseShiftByTerm(qureg, targetQubit, term);
290 }
291 
292 void statevec_rotateX(Qureg qureg, const int rotQubit, qreal angle){
293 
294  Vector unitAxis = {1, 0, 0};
295  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
296 }
297 
298 void statevec_rotateY(Qureg qureg, const int rotQubit, qreal angle){
299 
300  Vector unitAxis = {0, 1, 0};
301  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
302 }
303 
304 void statevec_rotateZ(Qureg qureg, const int rotQubit, qreal angle){
305 
306  Vector unitAxis = {0, 0, 1};
307  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
308 }
309 
310 void statevec_rotateAroundAxis(Qureg qureg, const int rotQubit, qreal angle, Vector axis){
311 
312  Complex alpha, beta;
313  getComplexPairFromRotation(angle, axis, &alpha, &beta);
314  statevec_compactUnitary(qureg, rotQubit, alpha, beta);
315 }
316 
317 void statevec_rotateAroundAxisConj(Qureg qureg, const int rotQubit, qreal angle, Vector axis){
318 
319  Complex alpha, beta;
320  getComplexPairFromRotation(angle, axis, &alpha, &beta);
321  alpha.imag *= -1;
322  beta.imag *= -1;
323  statevec_compactUnitary(qureg, rotQubit, alpha, beta);
324 }
325 
326 void statevec_controlledRotateAroundAxis(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle, Vector axis){
327 
328  Complex alpha, beta;
329  getComplexPairFromRotation(angle, axis, &alpha, &beta);
330  statevec_controlledCompactUnitary(qureg, controlQubit, targetQubit, alpha, beta);
331 }
332 
333 void statevec_controlledRotateAroundAxisConj(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle, Vector axis){
334 
335  Complex alpha, beta;
336  getComplexPairFromRotation(angle, axis, &alpha, &beta);
337  alpha.imag *= -1;
338  beta.imag *= -1;
339  statevec_controlledCompactUnitary(qureg, controlQubit, targetQubit, alpha, beta);
340 }
341 
342 void statevec_controlledRotateX(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle){
343 
344  Vector unitAxis = {1, 0, 0};
345  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
346 }
347 
348 void statevec_controlledRotateY(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle){
349 
350  Vector unitAxis = {0, 1, 0};
351  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
352 }
353 
354 void statevec_controlledRotateZ(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle){
355 
356  Vector unitAxis = {0, 0, 1};
357  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
358 }
359 
360 int statevec_measureWithStats(Qureg qureg, int measureQubit, qreal *outcomeProb) {
361 
362  qreal zeroProb = statevec_calcProbOfOutcome(qureg, measureQubit, 0);
363  int outcome = generateMeasurementOutcome(zeroProb, outcomeProb);
364  statevec_collapseToKnownProbOutcome(qureg, measureQubit, outcome, *outcomeProb);
365  return outcome;
366 }
367 
368 int densmatr_measureWithStats(Qureg qureg, int measureQubit, qreal *outcomeProb) {
369 
370  qreal zeroProb = densmatr_calcProbOfOutcome(qureg, measureQubit, 0);
371  int outcome = generateMeasurementOutcome(zeroProb, outcomeProb);
372  densmatr_collapseToKnownProbOutcome(qureg, measureQubit, outcome, *outcomeProb);
373  return outcome;
374 }
375 
377 
378  Complex innerProd = statevec_calcInnerProduct(qureg, pureState);
379  qreal innerProdMag = innerProd.real*innerProd.real + innerProd.imag*innerProd.imag;
380  return innerProdMag;
381 }
382 
383 void statevec_sqrtSwapGate(Qureg qureg, int qb1, int qb2) {
384 
385  ComplexMatrix4 u = (ComplexMatrix4) {.real={{0}}, .imag={{0}}};
386  u.real[0][0]=1;
387  u.real[3][3]=1;
388  u.real[1][1] = .5; u.imag[1][1] = .5;
389  u.real[1][2] = .5; u.imag[1][2] =-.5;
390  u.real[2][1] = .5; u.imag[2][1] =-.5;
391  u.real[2][2] = .5; u.imag[2][2] = .5;
392 
393  statevec_twoQubitUnitary(qureg, qb1, qb2, u);
394 }
395 
396 void statevec_sqrtSwapGateConj(Qureg qureg, int qb1, int qb2) {
397 
398  ComplexMatrix4 u = (ComplexMatrix4) {.real={{0}}, .imag={{0}}};
399  u.real[0][0]=1;
400  u.real[3][3]=1;
401  u.real[1][1] = .5; u.imag[1][1] =-.5;
402  u.real[1][2] = .5; u.imag[1][2] = .5;
403  u.real[2][1] = .5; u.imag[2][1] = .5;
404  u.real[2][2] = .5; u.imag[2][2] =-.5;
405 
406  statevec_twoQubitUnitary(qureg, qb1, qb2, u);
407 }
408 
411  Qureg qureg, int* targetQubits, enum pauliOpType* targetPaulis, int numTargets, qreal angle,
412  int applyConj
413 ) {
414  qreal fac = 1/sqrt(2);
415  Complex uRxAlpha = {.real = fac, .imag = 0}; // Rx(pi/2)* rotates Z -> Y
416  Complex uRxBeta = {.real = 0, .imag = (applyConj)? fac : -fac};
417  Complex uRyAlpha = {.real = fac, .imag = 0}; // Ry(-pi/2) rotates Z -> X
418  Complex uRyBeta = {.real = -fac, .imag = 0};
419 
420  // mask may be modified to remove superfluous Identity ops
421  long long int mask = getQubitBitMask(targetQubits, numTargets);
422 
423  // rotate basis so that exp(Z) will effect exp(Y) and exp(X)
424  for (int t=0; t < numTargets; t++) {
425  if (targetPaulis[t] == PAULI_I)
426  mask -= 1LL << targetQubits[t]; // remove target from mask
427  if (targetPaulis[t] == PAULI_X)
428  statevec_compactUnitary(qureg, targetQubits[t], uRyAlpha, uRyBeta);
429  if (targetPaulis[t] == PAULI_Y)
430  statevec_compactUnitary(qureg, targetQubits[t], uRxAlpha, uRxBeta);
431  // (targetPaulis[t] == 3) is Z basis
432  }
433 
434  // does nothing if there are no qubits to 'rotate'
435  if (mask != 0)
436  statevec_multiRotateZ(qureg, mask, (applyConj)? -angle : angle);
437 
438  // undo X and Y basis rotations
439  uRxBeta.imag *= -1;
440  uRyBeta.real *= -1;
441  for (int t=0; t < numTargets; t++) {
442  if (targetPaulis[t] == PAULI_X)
443  statevec_compactUnitary(qureg, targetQubits[t], uRyAlpha, uRyBeta);
444  if (targetPaulis[t] == PAULI_Y)
445  statevec_compactUnitary(qureg, targetQubits[t], uRxAlpha, uRxBeta);
446  }
447 }
448 
449 /* produces both pauli|qureg> or pauli * qureg (as a density matrix) */
450 void statevec_applyPauliProd(Qureg workspace, int* targetQubits, enum pauliOpType* pauliCodes, int numTargets) {
451 
452  for (int i=0; i < numTargets; i++) {
453  // (pauliCodes[i] == PAULI_I) applies no operation
454  if (pauliCodes[i] == PAULI_X)
455  statevec_pauliX(workspace, targetQubits[i]);
456  if (pauliCodes[i] == PAULI_Y)
457  statevec_pauliY(workspace, targetQubits[i]);
458  if (pauliCodes[i] == PAULI_Z)
459  statevec_pauliZ(workspace, targetQubits[i]);
460  }
461 }
462 
463 // <pauli> = <qureg|pauli|qureg> = qureg . pauli(qureg)
464 qreal statevec_calcExpecPauliProd(Qureg qureg, int* targetQubits, enum pauliOpType* pauliCodes, int numTargets, Qureg workspace) {
465 
466  statevec_cloneQureg(workspace, qureg);
467  statevec_applyPauliProd(workspace, targetQubits, pauliCodes, numTargets);
468 
469  // compute the expected value
470  qreal value;
471  if (qureg.isDensityMatrix)
472  value = densmatr_calcTotalProb(workspace); // Trace(ops qureg)
473  else
474  value = statevec_calcInnerProduct(workspace, qureg).real; // <qureg|ops|qureg>
475 
476  return value;
477 }
478 
479 qreal statevec_calcExpecPauliSum(Qureg qureg, enum pauliOpType* allCodes, qreal* termCoeffs, int numSumTerms, Qureg workspace) {
480 
481  int numQb = qureg.numQubitsRepresented;
482  int targs[numQb];
483  for (int q=0; q < numQb; q++)
484  targs[q] = q;
485 
486  qreal value = 0;
487  for (int t=0; t < numSumTerms; t++)
488  value += termCoeffs[t] * statevec_calcExpecPauliProd(qureg, targs, &allCodes[t*numQb], numQb, workspace);
489 
490  return value;
491 }
492 
493 void statevec_applyPauliSum(Qureg inQureg, enum pauliOpType* allCodes, qreal* termCoeffs, int numSumTerms, Qureg outQureg) {
494 
495  int numQb = inQureg.numQubitsRepresented;
496  int targs[numQb];
497  for (int q=0; q < numQb; q++)
498  targs[q] = q;
499 
500  statevec_initBlankState(outQureg);
501 
502  for (int t=0; t < numSumTerms; t++) {
503  Complex coef = (Complex) {.real=termCoeffs[t], .imag=0};
504  Complex iden = (Complex) {.real=1, .imag=0};
505  Complex zero = (Complex) {.real=0, .imag=0};
506 
507  // outQureg += coef paulis(inQureg)
508  statevec_applyPauliProd(inQureg, targs, &allCodes[t*numQb], numQb);
509  statevec_setWeightedQureg(coef, inQureg, iden, outQureg, zero, outQureg);
510 
511  // undero paulis(inQureg), exploiting XX=YY=ZZ=I
512  statevec_applyPauliProd(inQureg, targs, &allCodes[t*numQb], numQb);
513  }
514 }
515 
516 void statevec_twoQubitUnitary(Qureg qureg, const int targetQubit1, const int targetQubit2, ComplexMatrix4 u) {
517 
518  long long int ctrlMask = 0;
519  statevec_multiControlledTwoQubitUnitary(qureg, ctrlMask, targetQubit1, targetQubit2, u);
520 }
521 
522 void statevec_controlledTwoQubitUnitary(Qureg qureg, const int controlQubit, const int targetQubit1, const int targetQubit2, ComplexMatrix4 u) {
523 
524  long long int ctrlMask = 1LL << controlQubit;
525  statevec_multiControlledTwoQubitUnitary(qureg, ctrlMask, targetQubit1, targetQubit2, u);
526 }
527 
528 void statevec_multiQubitUnitary(Qureg qureg, int* targets, const int numTargets, ComplexMatrixN u) {
529 
530  long long int ctrlMask = 0;
531  statevec_multiControlledMultiQubitUnitary(qureg, ctrlMask, targets, numTargets, u);
532 }
533 
534 void statevec_controlledMultiQubitUnitary(Qureg qureg, int ctrl, int* targets, const int numTargets, ComplexMatrixN u) {
535 
536  long long int ctrlMask = 1LL << ctrl;
537  statevec_multiControlledMultiQubitUnitary(qureg, ctrlMask, targets, numTargets, u);
538 }
539 
540 #define macro_populateKrausOperator(superOp, ops, numOps, opDim) \
541  /* clear the superop */ \
542  for (int r=0; r < (opDim)*(opDim); r++) \
543  for (int c=0; c < (opDim)*(opDim); c++) { \
544  superOp->real[r][c] = 0; \
545  superOp->imag[r][c] = 0; \
546  } \
547  /* add each op's contribution to the superop */ \
548  for (int n=0; n<(numOps); n++) \
549  /* superop += conjugate(op) (x) op, where (x) is a tensor product */ \
550  for (int i = 0; i < (opDim); i++) \
551  for (int j = 0; j < (opDim); j++) \
552  for (int k = 0; k < (opDim); k++) \
553  for (int l = 0; l < (opDim); l++) { \
554  superOp->real[i*(opDim) + k][j*(opDim) + l] += \
555  ops[n].real[i][j]*ops[n].real[k][l] + \
556  ops[n].imag[i][j]*ops[n].imag[k][l]; \
557  superOp->imag[i*(opDim) + k][j*(opDim) + l] += \
558  ops[n].real[i][j]*ops[n].imag[k][l] - \
559  ops[n].imag[i][j]*ops[n].real[k][l]; \
560  }
561 
563  int opDim = 2;
564  macro_populateKrausOperator(superOp, ops, numOps, opDim);
565 }
567  int opDim = 4;
568  macro_populateKrausOperator(superOp, ops, numOps, opDim);
569 }
571  int opDim = 1 << ops[0].numQubits;
572  macro_populateKrausOperator(superOp, ops, numOps, opDim);
573 }
574 
575 void densmatr_applyKrausSuperoperator(Qureg qureg, int target, ComplexMatrix4 superOp) {
576 
577  long long int ctrlMask = 0;
578  statevec_multiControlledTwoQubitUnitary(qureg, ctrlMask, target, target + qureg.numQubitsRepresented, superOp);
579 }
580 
581 void densmatr_applyTwoQubitKrausSuperoperator(Qureg qureg, int target1, int target2, ComplexMatrixN superOp) {
582 
583  long long int ctrlMask = 0;
584  int numQb = qureg.numQubitsRepresented;
585  int allTargets[4] = {target1, target2, target1+numQb, target2+numQb};
586  statevec_multiControlledMultiQubitUnitary(qureg, ctrlMask, allTargets, 4, superOp);
587 }
588 
589 void densmatr_applyMultiQubitKrausSuperoperator(Qureg qureg, int *targets, int numTargets, ComplexMatrixN superOp) {
590  long long int ctrlMask = 0;
591  int allTargets[2*numTargets];
592  for (int t=0; t < numTargets; t++) {
593  allTargets[t] = targets[t];
594  allTargets[t+numTargets] = targets[t] + qureg.numQubitsRepresented;
595  }
596  statevec_multiControlledMultiQubitUnitary(qureg, ctrlMask, allTargets, 2*numTargets, superOp);
597 }
598 
599 void densmatr_mixKrausMap(Qureg qureg, int target, ComplexMatrix2 *ops, int numOps) {
600 
601  ComplexMatrix4 superOp;
602  populateKrausSuperOperator2(&superOp, ops, numOps);
603  densmatr_applyKrausSuperoperator(qureg, target, superOp);
604 }
605 
607  int numQubits, qreal re[][1<<numQubits], qreal im[][1<<numQubits],
608  qreal** reStorage, qreal** imStorage
609 ) {
610  ComplexMatrixN m;
611  m.numQubits = numQubits;
612  m.real = reStorage;
613  m.imag = imStorage;
614 
615  int len = 1<<numQubits;
616  for (int i=0; i<len; i++) {
617  m.real[i] = re[i];
618  m.imag[i] = im[i];
619  }
620  return m;
621 }
622 #define macro_initialiseStackComplexMatrixN(matrix, numQubits, real, imag) \
623  /* reStorage_ and imStorage_ must not exist in calling scope */ \
624  qreal* reStorage_[1<<(numQubits)]; \
625  qreal* imStorage_[1<<(numQubits)]; \
626  matrix = bindArraysToStackComplexMatrixN((numQubits), real, imag, reStorage_, imStorage_);
627 
628 #define macro_allocStackComplexMatrixN(matrix, numQubits) \
629  /* reArr_, imArr_, reStorage_, and imStorage_ must not exist in calling scope */ \
630  qreal reArr_[1<<(numQubits)][1<<(numQubits)]; \
631  qreal imArr_[1<<(numQubits)][1<<(numQubits)]; \
632  macro_initialiseStackComplexMatrixN(matrix, (numQubits), reArr_, imArr_);
633 
634 void densmatr_mixTwoQubitKrausMap(Qureg qureg, int target1, int target2, ComplexMatrix4 *ops, int numOps) {
635 
636  ComplexMatrixN superOp;
637  macro_allocStackComplexMatrixN(superOp, 4);
638  populateKrausSuperOperator4(&superOp, ops, numOps);
639  densmatr_applyTwoQubitKrausSuperoperator(qureg, target1, target2, superOp);
640 }
641 
642 void densmatr_mixMultiQubitKrausMap(Qureg qureg, int* targets, int numTargets, ComplexMatrixN* ops, int numOps) {
643 
644  ComplexMatrixN superOp;
645 
646  /* superOp will contain 2^(4 numTargets) complex numbers.
647  * At double precision, superOp will cost additional memory:
648  * numTargs=1 -> 0.25 KiB
649  * numTargs=2 -> 4 KiB
650  * numTargs=3 -> 64 KiB
651  * numTargs=4 -> 1 MiB
652  * numTargs=5 -> 16 MiB.
653  * At quad precision (usually 10 B per number, but possibly 16 B due to alignment),
654  * this costs at most double.
655  *
656  * Hence, if superOp is kept in the stack, numTargs >= 4 would exceed Windows' 1 MB
657  * maximum stack-space allocation (numTargs >= 5 exceeding Linux' 8 MB). Therefore,
658  * for numTargets < 4, superOp will be kept in the stack, else in the heap
659  */
660 
661  if (numTargets < 4) {
662  // everything must live in 'if' since this macro declares local vars
663  macro_allocStackComplexMatrixN(superOp, 2*numTargets);
664  populateKrausSuperOperatorN(&superOp, ops, numOps);
665  densmatr_applyMultiQubitKrausSuperoperator(qureg, targets, numTargets, superOp);
666  }
667  else {
668  superOp = createComplexMatrixN(2*numTargets);
669  populateKrausSuperOperatorN(&superOp, ops, numOps);
670  densmatr_applyMultiQubitKrausSuperoperator(qureg, targets, numTargets, superOp);
671  destroyComplexMatrixN(superOp);
672  }
673 }
674 
675 void densmatr_mixPauli(Qureg qureg, int qubit, qreal probX, qreal probY, qreal probZ) {
676 
677  // convert pauli probabilities into Kraus map
678  const int numOps = 4;
679  ComplexMatrix2 ops[numOps];
680  for (int n=0; n < numOps; n++)
681  ops[n] = (ComplexMatrix2) {.real={{0}}, .imag={{0}}};
682 
683  qreal facs[4] = { // literal numOps=4 for valid initialisation
684  sqrt(1-(probX + probY + probZ)),
685  sqrt(probX),
686  sqrt(probY),
687  sqrt(probZ)
688  };
689  ops[0].real[0][0] = facs[0]; ops[0].real[1][1] = facs[0];
690  ops[1].real[0][1] = facs[1]; ops[1].real[1][0] = facs[1];
691  ops[2].imag[0][1] = -facs[2]; ops[2].imag[1][0] = facs[2];
692  ops[3].real[0][0] = facs[3]; ops[3].real[1][1] = -facs[3];
693 
694  densmatr_mixKrausMap(qureg, qubit, ops, numOps);
695 }
696 
697 #ifdef __cplusplus
698 }
699 #endif
Represents a 3-vector of real numbers.
Definition: QuEST.h:148
pauliOpType
Codes for specifying Pauli operators.
Definition: QuEST.h:96
void init_by_array(unsigned long init_key[], int key_length)
Definition: mt19937ar.c:80
void reportQuregParams(Qureg qureg)
Report metainformation about a set of qubits: number of qubits, number of probability amplitudes.
Definition: QuEST_common.c:233
#define macro_setConjugateMatrix(dest, src, dim)
Definition: QuEST_common.c:92
qreal real[4][4]
Definition: QuEST.h:127
void densmatr_mixKrausMap(Qureg qureg, int target, ComplexMatrix2 *ops, int numOps)
Definition: QuEST_common.c:599
void statevec_multiQubitUnitary(Qureg qureg, int *targets, const int numTargets, ComplexMatrixN u)
Definition: QuEST_common.c:528
@ PAULI_Z
Definition: QuEST.h:96
void statevec_pauliY(Qureg qureg, const int targetQubit)
void populateKrausSuperOperator4(ComplexMatrixN *superOp, ComplexMatrix4 *ops, int numOps)
Definition: QuEST_common.c:566
void populateKrausSuperOperatorN(ComplexMatrixN *superOp, ComplexMatrixN *ops, int numOps)
Definition: QuEST_common.c:570
void destroyComplexMatrixN(ComplexMatrixN m)
Destroy a ComplexMatrixN instance created with createComplexMatrixN()
Definition: QuEST.c:1021
void shiftIndices(int *indices, int numIndices, int shift)
Definition: QuEST_common.c:149
qreal statevec_calcExpecPauliProd(Qureg qureg, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets, Qureg workspace)
Definition: QuEST_common.c:464
@ PAULI_I
Definition: QuEST.h:96
void statevec_controlledRotateAroundAxisConj(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle, Vector axis)
Definition: QuEST_common.c:333
ComplexMatrixN createComplexMatrixN(int numQubits)
Create (dynamically) a square complex matrix which can be passed to the multi-qubit general unitary f...
Definition: QuEST.c:1000
qreal statevec_calcExpecPauliSum(Qureg qureg, enum pauliOpType *allCodes, qreal *termCoeffs, int numSumTerms, Qureg workspace)
Definition: QuEST_common.c:479
void statevec_controlledTwoQubitUnitary(Qureg qureg, const int controlQubit, const int targetQubit1, const int targetQubit2, ComplexMatrix4 u)
Definition: QuEST_common.c:522
qreal z
Definition: QuEST.h:150
void statevec_phaseShift(Qureg qureg, const int targetQubit, qreal angle)
Definition: QuEST_common.c:250
ComplexMatrix4 getConjugateMatrix4(ComplexMatrix4 src)
Definition: QuEST_common.c:103
int numChunks
Number of chunks the state vector is broken up into – the number of MPI processes used.
Definition: QuEST.h:176
void statevec_applyPauliProd(Qureg workspace, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets)
Definition: QuEST_common.c:450
void statevec_multiRotateZ(Qureg qureg, long long int mask, qreal angle)
Definition: QuEST_cpu.c:3069
void getQuESTDefaultSeedKey(unsigned long int *key)
Definition: QuEST_common.c:181
void statevec_multiControlledMultiQubitUnitary(Qureg qureg, long long int ctrlMask, int *targs, const int numTargs, ComplexMatrixN u)
This calls swapQubitAmps only when it would involve a distributed communication; if the qubit chunks ...
void densmatr_collapseToKnownProbOutcome(Qureg qureg, const int measureQubit, int outcome, qreal outcomeProb)
Renorms (/prob) every | * outcome * >< * outcome * | state, setting all others to zero.
Definition: QuEST_cpu.c:784
void statevec_pauliX(Qureg qureg, const int targetQubit)
void seedQuEST(unsigned long int *seedArray, int numSeeds)
numSeeds <= 64
Definition: QuEST_common.c:208
void densmatr_mixMultiQubitKrausMap(Qureg qureg, int *targets, int numTargets, ComplexMatrixN *ops, int numOps)
Definition: QuEST_common.c:642
Complex getConjugateScalar(Complex scalar)
Definition: QuEST_common.c:84
ComplexMatrix2 getConjugateMatrix2(ComplexMatrix2 src)
Definition: QuEST_common.c:98
void statevec_rotateZ(Qureg qureg, const int rotQubit, qreal angle)
Definition: QuEST_common.c:304
Vector getUnitVector(Vector vec)
Definition: QuEST_common.c:77
Represents a 4x4 matrix of complex numbers.
Definition: QuEST.h:125
void getComplexPairFromRotation(qreal angle, Vector axis, Complex *alpha, Complex *beta)
Definition: QuEST_common.c:113
ComplexMatrixN bindArraysToStackComplexMatrixN(int numQubits, qreal re[][1<< numQubits], qreal im[][1<< numQubits], qreal **reStorage, qreal **imStorage)
Definition: QuEST_common.c:606
Represents a general 2^N by 2^N matrix of complex numbers.
Definition: QuEST.h:136
long long int getControlFlipMask(int *controlQubits, int *controlState, const int numControlQubits)
Definition: QuEST_common.c:53
qreal statevec_calcFidelity(Qureg qureg, Qureg pureState)
Definition: QuEST_common.c:376
#define qreal
#define macro_allocStackComplexMatrixN(matrix, numQubits)
Definition: QuEST_common.c:628
void statevec_sqrtSwapGate(Qureg qureg, int qb1, int qb2)
Definition: QuEST_common.c:383
@ PAULI_X
Definition: QuEST.h:96
qreal statevec_getProbAmp(Qureg qureg, long long int index)
Definition: QuEST_common.c:244
void reportState(Qureg qureg)
Print the current state vector of probability amplitudes for a set of qubits to file.
Definition: QuEST_common.c:215
int numQubitsInStateVec
Number of qubits in the state-vector - this is double the number represented for mixed states.
Definition: QuEST.h:167
void statevec_tGate(Qureg qureg, const int targetQubit)
Definition: QuEST_common.c:271
qreal densmatr_calcTotalProb(Qureg qureg)
void statevec_rotateAroundAxisConj(Qureg qureg, const int rotQubit, qreal angle, Vector axis)
Definition: QuEST_common.c:317
long long int getQubitBitMask(int *qubits, const int numQubits)
Definition: QuEST_common.c:43
int chunkId
The position of the chunk of the state vector held by this process in the full state vector.
Definition: QuEST.h:174
qreal y
Definition: QuEST.h:150
unsigned long int hashString(char *str)
Definition: QuEST_common.c:171
qreal imag[2][2]
Definition: QuEST.h:117
void statevec_rotateX(Qureg qureg, const int rotQubit, qreal angle)
Definition: QuEST_common.c:292
qreal x
Definition: QuEST.h:150
int generateMeasurementOutcome(qreal zeroProb, qreal *outcomeProb)
Definition: QuEST_common.c:154
void statevec_twoQubitUnitary(Qureg qureg, const int targetQubit1, const int targetQubit2, ComplexMatrix4 u)
Definition: QuEST_common.c:516
long long int numAmpsPerChunk
Number of probability amplitudes held in stateVec by this process In the non-MPI version,...
Definition: QuEST.h:170
void statevec_pauliZ(Qureg qureg, const int targetQubit)
Definition: QuEST_common.c:257
void statevec_controlledRotateZ(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle)
Definition: QuEST_common.c:354
void densmatr_applyKrausSuperoperator(Qureg qureg, int target, ComplexMatrix4 superOp)
Definition: QuEST_common.c:575
void statevec_initBlankState(Qureg qureg)
Definition: QuEST_cpu.c:1366
void populateKrausSuperOperator2(ComplexMatrix4 *superOp, ComplexMatrix2 *ops, int numOps)
Definition: QuEST_common.c:562
void statevec_cloneQureg(Qureg targetQureg, Qureg copyQureg)
works for both statevectors and density matrices
Definition: QuEST_cpu.c:1474
qreal imag[4][4]
Definition: QuEST.h:128
void setConjugateMatrixN(ComplexMatrixN m)
Definition: QuEST_common.c:108
void densmatr_mixTwoQubitKrausMap(Qureg qureg, int target1, int target2, ComplexMatrix4 *ops, int numOps)
Definition: QuEST_common.c:634
void statevec_phaseShiftByTerm(Qureg qureg, const int targetQubit, Complex term)
Definition: QuEST_cpu.c:2940
@ PAULI_Y
Definition: QuEST.h:96
double genrand_real1(void)
Definition: mt19937ar.c:150
void statevec_multiRotatePauli(Qureg qureg, int *targetQubits, enum pauliOpType *targetPaulis, int numTargets, qreal angle, int applyConj)
applyConj=1 will apply conjugate operation, else applyConj=0
Definition: QuEST_common.c:410
void statevec_sGateConj(Qureg qureg, const int targetQubit)
Definition: QuEST_common.c:278
qreal ** real
Definition: QuEST.h:139
void statevec_rotateY(Qureg qureg, const int rotQubit, qreal angle)
Definition: QuEST_common.c:298
void statevec_applyPauliSum(Qureg inQureg, enum pauliOpType *allCodes, qreal *termCoeffs, int numSumTerms, Qureg outQureg)
Definition: QuEST_common.c:493
Complex statevec_calcInnerProduct(Qureg bra, Qureg ket)
Terrible code which unnecessarily individually computes and sums the real and imaginary components of...
void statevec_setWeightedQureg(Complex fac1, Qureg qureg1, Complex fac2, Qureg qureg2, Complex facOut, Qureg out)
Definition: QuEST_cpu.c:3579
qreal statevec_calcProbOfOutcome(Qureg qureg, const int measureQubit, int outcome)
void statevec_collapseToKnownProbOutcome(Qureg qureg, const int measureQubit, int outcome, qreal outcomeProb)
qreal statevec_getImagAmp(Qureg qureg, long long int index)
Represents a system of qubits.
Definition: QuEST.h:160
int statevec_measureWithStats(Qureg qureg, int measureQubit, qreal *outcomeProb)
Definition: QuEST_common.c:360
qreal ** imag
Definition: QuEST.h:140
void getZYZRotAnglesFromComplexPair(Complex alpha, Complex beta, qreal *rz2, qreal *ry, qreal *rz1)
maps U(alpha, beta) to Rz(rz2) Ry(ry) Rz(rz1)
Definition: QuEST_common.c:123
qreal densmatr_calcProbOfOutcome(Qureg qureg, const int measureQubit, int outcome)
ComplexArray stateVec
Computational state amplitudes - a subset thereof in the MPI version.
Definition: QuEST.h:179
qreal real[2][2]
Definition: QuEST.h:116
void statevec_controlledRotateY(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle)
Definition: QuEST_common.c:348
int isDensityMatrix
Whether this instance is a density-state representation.
Definition: QuEST.h:163
void statevec_controlledCompactUnitary(Qureg qureg, const int controlQubit, const int targetQubit, Complex alpha, Complex beta)
void statevec_sGate(Qureg qureg, const int targetQubit)
Definition: QuEST_common.c:264
int numQubits
Definition: QuEST.h:138
qreal getVectorMagnitude(Vector vec)
Definition: QuEST_common.c:72
void statevec_tGateConj(Qureg qureg, const int targetQubit)
Definition: QuEST_common.c:285
void densmatr_applyTwoQubitKrausSuperoperator(Qureg qureg, int target1, int target2, ComplexMatrixN superOp)
Definition: QuEST_common.c:581
void statevec_sqrtSwapGateConj(Qureg qureg, int qb1, int qb2)
Definition: QuEST_common.c:396
void statevec_controlledMultiQubitUnitary(Qureg qureg, int ctrl, int *targets, const int numTargets, ComplexMatrixN u)
Definition: QuEST_common.c:534
int numQubitsRepresented
The number of qubits represented in either the state-vector or density matrix.
Definition: QuEST.h:165
qreal real
Definition: QuEST.h:105
void statevec_controlledRotateX(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle)
Definition: QuEST_common.c:342
void densmatr_applyMultiQubitKrausSuperoperator(Qureg qureg, int *targets, int numTargets, ComplexMatrixN superOp)
Definition: QuEST_common.c:589
void densmatr_mixPauli(Qureg qureg, int qubit, qreal probX, qreal probY, qreal probZ)
Definition: QuEST_common.c:675
qreal imag
Definition: QuEST.h:106
void statevec_controlledRotateAroundAxis(Qureg qureg, const int controlQubit, const int targetQubit, qreal angle, Vector axis)
Definition: QuEST_common.c:326
void ensureIndsIncrease(int *ind1, int *ind2)
Definition: QuEST_common.c:63
Represents one complex number.
Definition: QuEST.h:103
void statevec_rotateAroundAxis(Qureg qureg, const int rotQubit, qreal angle, Vector axis)
Definition: QuEST_common.c:310
void statevec_multiControlledTwoQubitUnitary(Qureg qureg, long long int ctrlMask, const int targetQubit1, const int targetQubit2, ComplexMatrix4 u)
This calls swapQubitAmps only when it would involve a distributed communication; if the qubit chunks ...
#define macro_populateKrausOperator(superOp, ops, numOps, opDim)
Definition: QuEST_common.c:540
qreal statevec_getRealAmp(Qureg qureg, long long int index)
int densmatr_measureWithStats(Qureg qureg, int measureQubit, qreal *outcomeProb)
Definition: QuEST_common.c:368
Represents a 2x2 matrix of complex numbers.
Definition: QuEST.h:114
void getComplexPairAndPhaseFromUnitary(ComplexMatrix2 u, Complex *alpha, Complex *beta, qreal *globalPhase)
maps U(r0c0, r0c1, r1c0, r1c1) to exp(i globalPhase) U(alpha, beta)
Definition: QuEST_common.c:135
void statevec_compactUnitary(Qureg qureg, const int targetQubit, Complex alpha, Complex beta)