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