QuEST_internal.h File Reference
#include "QuEST.h"
#include "QuEST_precision.h"

Go to the source code of this file.

Functions

void agnostic_applyTrotterCircuit (Qureg qureg, PauliHamil hamil, qreal time, int order, int reps)
 
DiagonalOp agnostic_createDiagonalOp (int numQubits, QuESTEnv env)
 
void agnostic_destroyDiagonalOp (DiagonalOp op)
 
void agnostic_setDiagonalOpElems (DiagonalOp op, long long int startInd, qreal *real, qreal *imag, long long int numElems)
 
void agnostic_syncDiagonalOp (DiagonalOp op)
 
void conjugateMatrixN (ComplexMatrixN u)
 
void densmatr_applyDiagonalOp (Qureg qureg, DiagonalOp op)
 
Complex densmatr_calcExpecDiagonalOp (Qureg qureg, DiagonalOp op)
 
qreal densmatr_calcFidelity (Qureg qureg, Qureg pureState)
 
qreal densmatr_calcHilbertSchmidtDistance (Qureg a, Qureg b)
 
qreal densmatr_calcInnerProduct (Qureg a, Qureg b)
 
qreal densmatr_calcProbOfOutcome (Qureg qureg, int measureQubit, int outcome)
 
qreal densmatr_calcPurity (Qureg qureg)
 Computes the trace of the density matrix squared. More...
 
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. More...
 
void densmatr_initClassicalState (Qureg qureg, long long int stateInd)
 
void densmatr_initPlusState (Qureg targetQureg)
 
void densmatr_initPureState (Qureg targetQureg, Qureg copyQureg)
 
int densmatr_measureWithStats (Qureg qureg, int measureQubit, qreal *outcomeProb)
 
void densmatr_mixDamping (Qureg qureg, int targetQubit, qreal damping)
 
void densmatr_mixDensityMatrix (Qureg combineQureg, qreal otherProb, Qureg otherQureg)
 
void densmatr_mixDephasing (Qureg qureg, int targetQubit, qreal dephase)
 
void densmatr_mixDepolarising (Qureg qureg, int targetQubit, qreal depolLevel)
 
void densmatr_mixKrausMap (Qureg qureg, int target, ComplexMatrix2 *ops, int numOps)
 
void densmatr_mixMultiQubitKrausMap (Qureg qureg, int *targets, int numTargets, ComplexMatrixN *ops, int numOps)
 
void densmatr_mixPauli (Qureg qureg, int qubit, qreal pX, qreal pY, qreal pZ)
 
void densmatr_mixTwoQubitDephasing (Qureg qureg, int qubit1, int qubit2, qreal dephase)
 
void densmatr_mixTwoQubitDepolarising (Qureg qureg, int qubit1, int qubit2, qreal depolLevel)
 
void densmatr_mixTwoQubitKrausMap (Qureg qureg, int target1, int target2, ComplexMatrix4 *ops, int numOps)
 
void ensureIndsIncrease (int *ind1, int *ind2)
 
void getComplexPairAndPhaseFromUnitary (ComplexMatrix2 u, Complex *alpha, Complex *beta, qreal *globalPhase)
 maps U(r0c0, r0c1, r1c0, r1c1) to exp(i globalPhase) U(alpha, beta) More...
 
void getComplexPairFromRotation (qreal angle, Vector axis, Complex *alpha, Complex *beta)
 
ComplexMatrix2 getConjugateMatrix2 (ComplexMatrix2 src)
 
ComplexMatrix4 getConjugateMatrix4 (ComplexMatrix4 src)
 
Complex getConjugateScalar (Complex scalar)
 
long long int getControlFlipMask (int *controlQubits, int *controlState, int numControlQubits)
 
long long int getQubitBitMask (int *controlQubits, int numControlQubits)
 
void getQuESTDefaultSeedKey (unsigned long int *key)
 
qreal getVectorMagnitude (Vector vec)
 
void getZYZRotAnglesFromComplexPair (Complex alpha, Complex beta, qreal *rz2, qreal *ry, qreal *rz1)
 maps U(alpha, beta) to Rz(rz2) Ry(ry) Rz(rz1) More...
 
unsigned long int hashString (char *str)
 
void setConjugateMatrixN (ComplexMatrixN m)
 
void shiftIndices (int *indices, int numIndices, int shift)
 
void statevec_applyDiagonalOp (Qureg qureg, DiagonalOp op)
 
void statevec_applyPauliSum (Qureg inQureg, enum pauliOpType *allCodes, qreal *termCoeffs, int numSumTerms, Qureg outQureg)
 
Complex statevec_calcExpecDiagonalOp (Qureg qureg, DiagonalOp op)
 
qreal statevec_calcExpecPauliProd (Qureg qureg, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets, Qureg workspace)
 
qreal statevec_calcExpecPauliSum (Qureg qureg, enum pauliOpType *allCodes, qreal *termCoeffs, int numSumTerms, Qureg workspace)
 
qreal statevec_calcFidelity (Qureg qureg, Qureg pureState)
 
Complex statevec_calcInnerProduct (Qureg bra, Qureg ket)
 Terrible code which unnecessarily individually computes and sums the real and imaginary components of the inner product, so as to not have to worry about keeping the sums separated during reduction. More...
 
qreal statevec_calcProbOfOutcome (Qureg qureg, int measureQubit, int outcome)
 
qreal statevec_calcTotalProb (Qureg qureg)
 
void statevec_cloneQureg (Qureg targetQureg, Qureg copyQureg)
 works for both statevectors and density matrices More...
 
void statevec_collapseToKnownProbOutcome (Qureg qureg, int measureQubit, int outcome, qreal outcomeProb)
 
void statevec_compactUnitary (Qureg qureg, int targetQubit, Complex alpha, Complex beta)
 
int statevec_compareStates (Qureg mq1, Qureg mq2, qreal precision)
 
void statevec_controlledCompactUnitary (Qureg qureg, int controlQubit, int targetQubit, Complex alpha, Complex beta)
 
void statevec_controlledMultiQubitUnitary (Qureg qureg, int ctrl, int *targets, int numTargets, ComplexMatrixN u)
 
void statevec_controlledNot (Qureg qureg, int controlQubit, int targetQubit)
 
void statevec_controlledPauliY (Qureg qureg, int controlQubit, int targetQubit)
 
void statevec_controlledPauliYConj (Qureg qureg, int controlQubit, int targetQubit)
 
void statevec_controlledPhaseFlip (Qureg qureg, int idQubit1, int idQubit2)
 
void statevec_controlledPhaseShift (Qureg qureg, int idQubit1, int idQubit2, qreal angle)
 
void statevec_controlledRotateAroundAxis (Qureg qureg, int controlQubit, int targetQubit, qreal angle, Vector axis)
 
void statevec_controlledRotateAroundAxisConj (Qureg qureg, int controlQubit, int targetQubit, qreal angle, Vector axis)
 
void statevec_controlledRotateX (Qureg qureg, int controlQubit, int targetQubit, qreal angle)
 
void statevec_controlledRotateY (Qureg qureg, int controlQubit, int targetQubit, qreal angle)
 
void statevec_controlledRotateZ (Qureg qureg, int controlQubit, int targetQubit, qreal angle)
 
void statevec_controlledTwoQubitUnitary (Qureg qureg, int controlQubit, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
 
void statevec_controlledUnitary (Qureg qureg, int controlQubit, int targetQubit, ComplexMatrix2 u)
 
void statevec_createQureg (Qureg *qureg, int numQubits, QuESTEnv env)
 
void statevec_destroyQureg (Qureg qureg, QuESTEnv env)
 
qreal statevec_getImagAmp (Qureg qureg, long long int index)
 
qreal statevec_getProbAmp (Qureg qureg, long long int index)
 
qreal statevec_getRealAmp (Qureg qureg, long long int index)
 
void statevec_hadamard (Qureg qureg, int targetQubit)
 
void statevec_initBlankState (Qureg qureg)
 
void statevec_initClassicalState (Qureg qureg, long long int stateInd)
 
void statevec_initDebugState (Qureg qureg)
 Initialise the state vector of probability amplitudes to an (unphysical) state with each component of each probability amplitude a unique floating point value. More...
 
void statevec_initPlusState (Qureg qureg)
 
int statevec_initStateFromSingleFile (Qureg *qureg, char filename[200], QuESTEnv env)
 
void statevec_initStateOfSingleQubit (Qureg *qureg, int qubitId, int outcome)
 Initialise the state vector of probability amplitudes such that one qubit is set to 'outcome' and all other qubits are in an equal superposition of zero and one. More...
 
void statevec_initZeroState (Qureg qureg)
 
int statevec_measureWithStats (Qureg qureg, int measureQubit, qreal *outcomeProb)
 
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 already fit in the node, it operates the unitary direct. More...
 
void statevec_multiControlledPhaseFlip (Qureg qureg, int *controlQubits, int numControlQubits)
 
void statevec_multiControlledPhaseShift (Qureg qureg, int *controlQubits, int numControlQubits, qreal angle)
 
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 already fit in the node, it operates the unitary direct. More...
 
void statevec_multiControlledUnitary (Qureg qureg, long long int ctrlQubitsMask, long long int ctrlFlipMask, int targetQubit, ComplexMatrix2 u)
 
void statevec_multiQubitUnitary (Qureg qureg, int *targets, int numTargets, ComplexMatrixN u)
 
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 More...
 
void statevec_multiRotateZ (Qureg qureg, long long int mask, qreal angle)
 
void statevec_pauliX (Qureg qureg, int targetQubit)
 
void statevec_pauliY (Qureg qureg, int targetQubit)
 
void statevec_pauliYConj (Qureg qureg, int targetQubit)
 
void statevec_pauliZ (Qureg qureg, int targetQubit)
 
void statevec_phaseShift (Qureg qureg, int targetQubit, qreal angle)
 
void statevec_phaseShiftByTerm (Qureg qureg, int targetQubit, Complex term)
 
void statevec_reportStateToScreen (Qureg qureg, QuESTEnv env, int reportRank)
 Print the current state vector of probability amplitudes for a set of qubits to standard out. More...
 
void statevec_rotateAroundAxis (Qureg qureg, int rotQubit, qreal angle, Vector axis)
 
void statevec_rotateAroundAxisConj (Qureg qureg, int rotQubit, qreal angle, Vector axis)
 
void statevec_rotateX (Qureg qureg, int rotQubit, qreal angle)
 
void statevec_rotateY (Qureg qureg, int rotQubit, qreal angle)
 
void statevec_rotateZ (Qureg qureg, int rotQubit, qreal angle)
 
void statevec_setAmps (Qureg qureg, long long int startInd, qreal *reals, qreal *imags, long long int numAmps)
 
void statevec_setWeightedQureg (Complex fac1, Qureg qureg1, Complex fac2, Qureg qureg2, Complex facOut, Qureg out)
 
void statevec_sGate (Qureg qureg, int targetQubit)
 
void statevec_sGateConj (Qureg qureg, int targetQubit)
 
void statevec_sqrtSwapGate (Qureg qureg, int qb1, int qb2)
 
void statevec_sqrtSwapGateConj (Qureg qureg, int qb1, int qb2)
 
void statevec_swapQubitAmps (Qureg qureg, int qb1, int qb2)
 
void statevec_tGate (Qureg qureg, int targetQubit)
 
void statevec_tGateConj (Qureg qureg, int targetQubit)
 
void statevec_twoQubitUnitary (Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
 
void statevec_unitary (Qureg qureg, int targetQubit, ComplexMatrix2 u)
 

Detailed Description

General functions used internally, supplied by QuEST_common or by hardware-specific backends. Note that some bespoke functions used only internally exist in QuEST_qasm.h and QuEST_validation.h

Author
Ania Brown (statevecs, original architecture)
Tyson Jones (re-architecture, statevecs, density matrices)

Definition in file QuEST_internal.h.

Function Documentation

◆ agnostic_applyTrotterCircuit()

void agnostic_applyTrotterCircuit ( Qureg  qureg,
PauliHamil  hamil,
qreal  time,
int  order,
int  reps 
)

Definition at line 773 of file QuEST_common.c.

773  {
774 
775  if (time == 0)
776  return;
777 
778  for (int r=0; r<reps; r++)
779  applySymmetrizedTrotterCircuit(qureg, hamil, time/reps, order);
780 }

References applySymmetrizedTrotterCircuit().

Referenced by applyTrotterCircuit().

◆ agnostic_createDiagonalOp()

DiagonalOp agnostic_createDiagonalOp ( int  numQubits,
QuESTEnv  env 
)

Definition at line 1335 of file QuEST_cpu.c.

1335  {
1336 
1337  // the 2^numQubits values will be evenly split between the env.numRanks nodes
1338  DiagonalOp op;
1339  op.numQubits = numQubits;
1340  op.numElemsPerChunk = (1LL << numQubits) / env.numRanks;
1341  op.chunkId = env.rank;
1342  op.numChunks = env.numRanks;
1343 
1344  // allocate CPU memory (initialised to zero)
1345  op.real = (qreal*) calloc(op.numElemsPerChunk, sizeof(qreal));
1346  op.imag = (qreal*) calloc(op.numElemsPerChunk, sizeof(qreal));
1347 
1348  // check cpu memory allocation was successful
1349  if ( !op.real || !op.imag ) {
1350  printf("Could not allocate memory!\n");
1351  exit(EXIT_FAILURE);
1352  }
1353 
1354  return op;
1355 }

References DiagonalOp::chunkId, DiagonalOp::deviceOperator, DiagonalOp::imag, DiagonalOp::numChunks, DiagonalOp::numElemsPerChunk, DiagonalOp::numQubits, QuESTEnv::numRanks, qreal, QuESTEnv::rank, and DiagonalOp::real.

Referenced by createDiagonalOp().

◆ agnostic_destroyDiagonalOp()

void agnostic_destroyDiagonalOp ( DiagonalOp  op)

Definition at line 1357 of file QuEST_cpu.c.

1357  {
1358  free(op.real);
1359  free(op.imag);
1360 }

References DiagonalOp::deviceOperator, DiagonalOp::imag, and DiagonalOp::real.

Referenced by destroyDiagonalOp().

◆ agnostic_setDiagonalOpElems()

void agnostic_setDiagonalOpElems ( DiagonalOp  op,
long long int  startInd,
qreal real,
qreal imag,
long long int  numElems 
)

Definition at line 3842 of file QuEST_cpu.c.

3842  {
3843 
3844  // local start/end indices of the given amplitudes, assuming they fit in this chunk
3845  // these may be negative or above qureg.numAmpsPerChunk
3846  long long int localStartInd = startInd - op.chunkId*op.numElemsPerChunk;
3847  long long int localEndInd = localStartInd + numElems; // exclusive
3848 
3849  // add this to a local index to get corresponding elem in reals & imags
3850  long long int offset = op.chunkId*op.numElemsPerChunk - startInd;
3851 
3852  // restrict these indices to fit into this chunk
3853  if (localStartInd < 0)
3854  localStartInd = 0;
3855  if (localEndInd > op.numElemsPerChunk)
3856  localEndInd = op.numElemsPerChunk;
3857  // they may now be out of order = no iterations
3858 
3859  // unpacking OpenMP vars
3860  long long int index;
3861  qreal* vecRe = op.real;
3862  qreal* vecIm = op.imag;
3863 
3864 # ifdef _OPENMP
3865 # pragma omp parallel \
3866  default (none) \
3867  shared (localStartInd,localEndInd, vecRe,vecIm, real,imag, offset) \
3868  private (index)
3869 # endif
3870  {
3871 # ifdef _OPENMP
3872 # pragma omp for schedule (static)
3873 # endif
3874  // iterate these local inds - this might involve no iterations
3875  for (index=localStartInd; index < localEndInd; index++) {
3876  vecRe[index] = real[index + offset];
3877  vecIm[index] = imag[index + offset];
3878  }
3879  }
3880 }

References DiagonalOp::chunkId, DiagonalOp::deviceOperator, DiagonalOp::imag, DiagonalOp::numElemsPerChunk, qreal, and DiagonalOp::real.

Referenced by initDiagonalOp(), and setDiagonalOpElems().

◆ agnostic_syncDiagonalOp()

void agnostic_syncDiagonalOp ( DiagonalOp  op)

Definition at line 1362 of file QuEST_cpu.c.

1362  {
1363  // nothing to do on CPU
1364 }

References DiagonalOp::deviceOperator, DiagonalOp::imag, DiagonalOp::numQubits, qreal, and DiagonalOp::real.

Referenced by syncDiagonalOp().

◆ conjugateMatrixN()

void conjugateMatrixN ( ComplexMatrixN  u)

◆ densmatr_applyDiagonalOp()

void densmatr_applyDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

◆ densmatr_calcExpecDiagonalOp()

Complex densmatr_calcExpecDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 1541 of file QuEST_cpu_distributed.c.

1541  {
1542 
1543  Complex localVal = densmatr_calcExpecDiagonalOpLocal(qureg, op);
1544  if (qureg.numChunks == 1)
1545  return localVal;
1546 
1547  qreal localRe = localVal.real;
1548  qreal localIm = localVal.imag;
1549  qreal globalRe, globalIm;
1550 
1551  MPI_Allreduce(&localRe, &globalRe, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1552  MPI_Allreduce(&localIm, &globalIm, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1553 
1554  Complex globalVal;
1555  globalVal.real = globalRe;
1556  globalVal.imag = globalIm;
1557  return globalVal;
1558 }

References copySharedReduceBlock(), densmatr_calcExpecDiagonalOpLocal(), DiagonalOp::deviceOperator, Qureg::deviceStateVec, Qureg::firstLevelReduction, Complex::imag, Qureg::numAmpsPerChunk, Qureg::numChunks, DiagonalOp::numQubits, qreal, Complex::real, REDUCE_SHARED_SIZE, Qureg::secondLevelReduction, and swapDouble().

Referenced by calcExpecDiagonalOp().

◆ densmatr_calcFidelity()

qreal densmatr_calcFidelity ( Qureg  qureg,
Qureg  pureState 
)

Definition at line 415 of file QuEST_cpu_distributed.c.

415  {
416 
417  // set qureg's pairState is to be the full pureState (on every node)
418  copyVecIntoMatrixPairState(qureg, pureState);
419 
420  // collect calcFidelityLocal by every machine
421  qreal localSum = densmatr_calcFidelityLocal(qureg, pureState);
422 
423  // sum each localSum
424  qreal globalSum;
425  MPI_Allreduce(&localSum, &globalSum, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
426 
427  return globalSum;
428 }

References copySharedReduceBlock(), copyVecIntoMatrixPairState(), densmatr_calcFidelityLocal(), Qureg::firstLevelReduction, Qureg::numQubitsRepresented, Qureg::pairStateVec, qreal, REDUCE_SHARED_SIZE, Qureg::secondLevelReduction, Qureg::stateVec, and swapDouble().

Referenced by calcFidelity().

◆ densmatr_calcHilbertSchmidtDistance()

qreal densmatr_calcHilbertSchmidtDistance ( Qureg  a,
Qureg  b 
)

Definition at line 430 of file QuEST_cpu_distributed.c.

430  {
431 
433 
434  qreal globalSum;
435  MPI_Allreduce(&localSum, &globalSum, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
436 
437  qreal dist = sqrt(globalSum);
438  return dist;
439 }

References copySharedReduceBlock(), densmatr_calcHilbertSchmidtDistanceSquaredLocal(), Qureg::deviceStateVec, Qureg::firstLevelReduction, Qureg::numAmpsPerChunk, qreal, REDUCE_SHARED_SIZE, Qureg::secondLevelReduction, and swapDouble().

Referenced by calcHilbertSchmidtDistance().

◆ densmatr_calcInnerProduct()

qreal densmatr_calcInnerProduct ( Qureg  a,
Qureg  b 
)

Definition at line 441 of file QuEST_cpu_distributed.c.

441  {
442 
443  qreal localSum = densmatr_calcInnerProductLocal(a, b);
444 
445  qreal globalSum;
446  MPI_Allreduce(&localSum, &globalSum, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
447 
448  qreal dist = globalSum;
449  return dist;
450 }

References copySharedReduceBlock(), densmatr_calcInnerProductLocal(), Qureg::firstLevelReduction, Qureg::numAmpsTotal, qreal, REDUCE_SHARED_SIZE, Qureg::secondLevelReduction, and swapDouble().

Referenced by calcDensityInnerProduct().

◆ densmatr_calcProbOfOutcome()

qreal densmatr_calcProbOfOutcome ( Qureg  qureg,
int  measureQubit,
int  outcome 
)

Definition at line 1276 of file QuEST_cpu_distributed.c.

1276  {
1277 
1278  qreal zeroProb = densmatr_findProbabilityOfZeroLocal(qureg, measureQubit);
1279 
1280  qreal outcomeProb;
1281  MPI_Allreduce(&zeroProb, &outcomeProb, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1282  if (outcome == 1)
1283  outcomeProb = 1.0 - outcomeProb;
1284 
1285  return outcomeProb;
1286 }

References densmatr_findProbabilityOfZero(), densmatr_findProbabilityOfZeroLocal(), and qreal.

Referenced by calcProbOfOutcome(), collapseToOutcome(), and densmatr_measureWithStats().

◆ densmatr_calcPurity()

qreal densmatr_calcPurity ( Qureg  qureg)

Computes the trace of the density matrix squared.

Definition at line 1288 of file QuEST_cpu_distributed.c.

1288  {
1289 
1290  qreal localPurity = densmatr_calcPurityLocal(qureg);
1291 
1292  qreal globalPurity;
1293  MPI_Allreduce(&localPurity, &globalPurity, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1294 
1295  return globalPurity;
1296 }

References copySharedReduceBlock(), densmatr_calcPurityLocal(), Qureg::deviceStateVec, Qureg::firstLevelReduction, Qureg::numAmpsPerChunk, qreal, REDUCE_SHARED_SIZE, Qureg::secondLevelReduction, and swapDouble().

Referenced by calcPurity().

◆ densmatr_calcTotalProb()

qreal densmatr_calcTotalProb ( Qureg  qureg)

Definition at line 53 of file QuEST_cpu_distributed.c.

53  {
54 
55  // computes the trace by summing every element ("diag") with global index (2^n + 1)i for i in [0, 2^n-1]
56 
57  // computes first local index containing a diagonal element
58  long long int diagSpacing = 1LL + (1LL << qureg.numQubitsRepresented);
59  long long int numPrevDiags = (qureg.chunkId>0)? 1+(qureg.chunkId*qureg.numAmpsPerChunk)/diagSpacing : 0;
60  long long int globalIndNextDiag = diagSpacing * numPrevDiags;
61  long long int localIndNextDiag = globalIndNextDiag % qureg.numAmpsPerChunk;
62  long long int index;
63 
64  qreal rankTotal = 0;
65  qreal y, t, c;
66  c = 0;
67 
68  // iterates every local diagonal
69  for (index=localIndNextDiag; index < qureg.numAmpsPerChunk; index += diagSpacing) {
70 
71  // Kahan summation - brackets are important
72  y = qureg.stateVec.real[index] - c;
73  t = rankTotal + y;
74  c = ( t - rankTotal ) - y;
75  rankTotal = t;
76  }
77 
78  // combine each node's sum of diagonals
79  qreal globalTotal;
80  if (qureg.numChunks > 1)
81  MPI_Allreduce(&rankTotal, &globalTotal, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
82  else
83  globalTotal = rankTotal;
84 
85  return globalTotal;
86 }

References Qureg::chunkId, copyStateFromGPU(), Qureg::numAmpsPerChunk, Qureg::numChunks, Qureg::numQubitsRepresented, qreal, and Qureg::stateVec.

Referenced by calcTotalProb(), and statevec_calcExpecPauliProd().

◆ densmatr_collapseToKnownProbOutcome()

void densmatr_collapseToKnownProbOutcome ( Qureg  qureg,
int  measureQubit,
int  outcome,
qreal  outcomeProb 
)

Renorms (/prob) every | * outcome * >< * outcome * | state, setting all others to zero.

Renorms (/prob) every | * outcome * >< * outcome * | state, setting all others to zero.

Definition at line 785 of file QuEST_cpu.c.

785  {
786 
787  // only (global) indices (as bit sequence): '* outcome *(n+q) outcome *q are spared
788  // where n = measureQubit, q = qureg.numQubitsRepresented.
789  // We can thus step in blocks of 2^q+n, killing every second, and inside the others,
790  // stepping in sub-blocks of 2^q, killing every second.
791  // When outcome=1, we offset the start of these blocks by their size.
792  long long int innerBlockSize = (1LL << measureQubit);
793  long long int outerBlockSize = (1LL << (measureQubit + qureg.numQubitsRepresented));
794 
795  // Because there are 2^a number of nodes(/chunks), each node will contain 2^b number of blocks,
796  // or each block will span 2^c number of nodes. Similarly for the innerblocks.
797  long long int locNumAmps = qureg.numAmpsPerChunk;
798  long long int globalStartInd = qureg.chunkId * locNumAmps;
799  int innerBit = extractBit(measureQubit, globalStartInd);
800  int outerBit = extractBit(measureQubit + qureg.numQubitsRepresented, globalStartInd);
801 
802  // If this chunk's amps are entirely inside an outer block
803  if (locNumAmps <= outerBlockSize) {
804 
805  // if this is an undesired outer block, kill all elems
806  if (outerBit != outcome)
807  return zeroSomeAmps(qureg, 0, qureg.numAmpsPerChunk);
808 
809  // othwerwise, if this is a desired outer block, and also entirely an inner block
810  if (locNumAmps <= innerBlockSize) {
811 
812  // and that inner block is undesired, kill all elems
813  if (innerBit != outcome)
814  return zeroSomeAmps(qureg, 0, qureg.numAmpsPerChunk);
815  // otherwise normalise all elems
816  else
817  return normaliseSomeAmps(qureg, totalStateProb, 0, qureg.numAmpsPerChunk);
818  }
819 
820  // otherwise this is a desired outer block which contains 2^a inner blocks; kill/renorm every second inner block
822  qureg, totalStateProb, innerBit==outcome, 0, qureg.numAmpsPerChunk, innerBlockSize);
823  }
824 
825  // Otherwise, this chunk's amps contain multiple outer blocks (and hence multiple inner blocks)
826  long long int numOuterDoubleBlocks = locNumAmps / (2*outerBlockSize);
827  long long int firstBlockInd;
828 
829  // alternate norming* and zeroing the outer blocks (with order based on the desired outcome)
830  // These loops aren't parallelised, since they could have 1 or 2 iterations and will prevent
831  // inner parallelisation
832  if (outerBit == outcome) {
833 
834  for (long long int outerDubBlockInd = 0; outerDubBlockInd < numOuterDoubleBlocks; outerDubBlockInd++) {
835  firstBlockInd = outerDubBlockInd*2*outerBlockSize;
836 
837  // *norm only the desired inner blocks in the desired outer block
839  qureg, totalStateProb, innerBit==outcome,
840  firstBlockInd, outerBlockSize, innerBlockSize);
841 
842  // zero the undesired outer block
843  zeroSomeAmps(qureg, firstBlockInd + outerBlockSize, outerBlockSize);
844  }
845 
846  } else {
847 
848  for (long long int outerDubBlockInd = 0; outerDubBlockInd < numOuterDoubleBlocks; outerDubBlockInd++) {
849  firstBlockInd = outerDubBlockInd*2*outerBlockSize;
850 
851  // same thing but undesired outer blocks come first
852  zeroSomeAmps(qureg, firstBlockInd, outerBlockSize);
854  qureg, totalStateProb, innerBit==outcome,
855  firstBlockInd + outerBlockSize, outerBlockSize, innerBlockSize);
856  }
857  }
858 
859 }

References alternateNormZeroingSomeAmpBlocks(), Qureg::chunkId, Qureg::deviceStateVec, extractBit(), normaliseSomeAmps(), Qureg::numAmpsPerChunk, Qureg::numQubitsRepresented, qreal, and zeroSomeAmps().

Referenced by collapseToOutcome(), and densmatr_measureWithStats().

◆ densmatr_initClassicalState()

void densmatr_initClassicalState ( Qureg  qureg,
long long int  stateInd 
)

Definition at line 1115 of file QuEST_cpu.c.

1116 {
1117  // dimension of the state vector
1118  long long int densityNumElems = qureg.numAmpsPerChunk;
1119 
1120  // Can't use qureg->stateVec as a private OMP var
1121  qreal *densityReal = qureg.stateVec.real;
1122  qreal *densityImag = qureg.stateVec.imag;
1123 
1124  // initialise the state to all zeros
1125  long long int index;
1126 # ifdef _OPENMP
1127 # pragma omp parallel \
1128  default (none) \
1129  shared (densityNumElems, densityReal, densityImag) \
1130  private (index)
1131 # endif
1132  {
1133 # ifdef _OPENMP
1134 # pragma omp for schedule (static)
1135 # endif
1136  for (index=0; index<densityNumElems; index++) {
1137  densityReal[index] = 0.0;
1138  densityImag[index] = 0.0;
1139  }
1140  }
1141 
1142  // index of the single density matrix elem to set non-zero
1143  long long int densityDim = 1LL << qureg.numQubitsRepresented;
1144  long long int densityInd = (densityDim + 1)*stateInd;
1145 
1146  // give the specified classical state prob 1
1147  if (qureg.chunkId == densityInd / densityNumElems){
1148  densityReal[densityInd % densityNumElems] = 1.0;
1149  densityImag[densityInd % densityNumElems] = 0.0;
1150  }
1151 }

References Qureg::chunkId, Qureg::deviceStateVec, Qureg::numAmpsPerChunk, Qureg::numQubitsRepresented, qreal, and Qureg::stateVec.

Referenced by initClassicalState().

◆ densmatr_initPlusState()

void densmatr_initPlusState ( Qureg  targetQureg)

Definition at line 1154 of file QuEST_cpu.c.

1155 {
1156  // |+><+| = sum_i 1/sqrt(2^N) |i> 1/sqrt(2^N) <j| = sum_ij 1/2^N |i><j|
1157  long long int dim = (1LL << qureg.numQubitsRepresented);
1158  qreal probFactor = 1.0/((qreal) dim);
1159 
1160  // Can't use qureg->stateVec as a private OMP var
1161  qreal *densityReal = qureg.stateVec.real;
1162  qreal *densityImag = qureg.stateVec.imag;
1163 
1164  long long int index;
1165  long long int chunkSize = qureg.numAmpsPerChunk;
1166  // initialise the state to |+++..+++> = 1/normFactor {1, 1, 1, ...}
1167 # ifdef _OPENMP
1168 # pragma omp parallel \
1169  default (none) \
1170  shared (chunkSize, densityReal, densityImag, probFactor) \
1171  private (index)
1172 # endif
1173  {
1174 # ifdef _OPENMP
1175 # pragma omp for schedule (static)
1176 # endif
1177  for (index=0; index<chunkSize; index++) {
1178  densityReal[index] = probFactor;
1179  densityImag[index] = 0.0;
1180  }
1181  }
1182 }

References Qureg::deviceStateVec, Qureg::numAmpsPerChunk, Qureg::numQubitsRepresented, qreal, and Qureg::stateVec.

Referenced by initPlusState().

◆ densmatr_initPureState()

void densmatr_initPureState ( Qureg  targetQureg,
Qureg  copyQureg 
)

Definition at line 452 of file QuEST_cpu_distributed.c.

452  {
453 
454  if (targetQureg.numChunks==1){
455  // local version
456  // save pointers to qureg's pair state
457  qreal* quregPairRePtr = targetQureg.pairStateVec.real;
458  qreal* quregPairImPtr = targetQureg.pairStateVec.imag;
459 
460  // populate qureg pair state with pure state (by repointing)
461  targetQureg.pairStateVec.real = copyQureg.stateVec.real;
462  targetQureg.pairStateVec.imag = copyQureg.stateVec.imag;
463 
464  // populate density matrix via it's pairState
465  densmatr_initPureStateLocal(targetQureg, copyQureg);
466 
467  // restore pointers
468  targetQureg.pairStateVec.real = quregPairRePtr;
469  targetQureg.pairStateVec.imag = quregPairImPtr;
470  } else {
471  // set qureg's pairState is to be the full pure state (on every node)
472  copyVecIntoMatrixPairState(targetQureg, copyQureg);
473 
474  // update every density matrix chunk using pairState
475  densmatr_initPureStateLocal(targetQureg, copyQureg);
476  }
477 }

References copyVecIntoMatrixPairState(), densmatr_initPureStateLocal(), Qureg::deviceStateVec, Qureg::numAmpsPerChunk, Qureg::numChunks, Qureg::pairStateVec, qreal, and Qureg::stateVec.

Referenced by initPureState().

◆ densmatr_measureWithStats()

int densmatr_measureWithStats ( Qureg  qureg,
int  measureQubit,
qreal outcomeProb 
)

Definition at line 369 of file QuEST_common.c.

369  {
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 }

References densmatr_calcProbOfOutcome(), densmatr_collapseToKnownProbOutcome(), generateMeasurementOutcome(), and qreal.

Referenced by measure(), and measureWithStats().

◆ densmatr_mixDamping()

void densmatr_mixDamping ( Qureg  qureg,
int  targetQubit,
qreal  damping 
)

Definition at line 725 of file QuEST_cpu_distributed.c.

725  {
726  if (damping == 0)
727  return;
728 
729  int rankIsUpper; // rank is in the upper half of an outer block
730  int pairRank; // rank of corresponding chunk
731 
732  int useLocalDataOnly = densityMatrixBlockFitsInChunk(qureg.numAmpsPerChunk,
733  qureg.numQubitsRepresented, targetQubit);
734 
735  if (useLocalDataOnly){
736  densmatr_mixDampingLocal(qureg, targetQubit, damping);
737  } else {
738  // pack data to send to my pair process into the first half of pairStateVec
739  compressPairVectorForSingleQubitDepolarise(qureg, targetQubit);
740 
741  rankIsUpper = chunkIsUpperInOuterBlock(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit,
742  qureg.numQubitsRepresented);
743  pairRank = getChunkOuterBlockPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk,
744  targetQubit, qureg.numQubitsRepresented);
745 
746  exchangePairStateVectorHalves(qureg, pairRank);
747  densmatr_mixDampingDistributed(qureg, targetQubit, damping);
748  }
749 
750 }

References Qureg::chunkId, chunkIsUpperInOuterBlock(), compressPairVectorForSingleQubitDepolarise(), densityMatrixBlockFitsInChunk(), densmatr_mixDampingDistributed(), densmatr_mixDampingLocal(), densmatr_oneQubitDegradeOffDiagonal(), Qureg::deviceStateVec, exchangePairStateVectorHalves(), getChunkOuterBlockPairId(), Qureg::numAmpsPerChunk, Qureg::numQubitsRepresented, and qreal.

Referenced by mixDamping().

◆ densmatr_mixDensityMatrix()

void densmatr_mixDensityMatrix ( Qureg  combineQureg,
qreal  otherProb,
Qureg  otherQureg 
)

Definition at line 890 of file QuEST_cpu.c.

890  {
891 
892  /* corresponding amplitudes live on the same node (same dimensions) */
893 
894  // unpack vars for OpenMP
895  qreal* combineVecRe = combineQureg.stateVec.real;
896  qreal* combineVecIm = combineQureg.stateVec.imag;
897  qreal* otherVecRe = otherQureg.stateVec.real;
898  qreal* otherVecIm = otherQureg.stateVec.imag;
899  long long int numAmps = combineQureg.numAmpsPerChunk;
900  long long int index;
901 
902 # ifdef _OPENMP
903 # pragma omp parallel \
904  default (none) \
905  shared (combineVecRe,combineVecIm,otherVecRe,otherVecIm, otherProb, numAmps) \
906  private (index)
907 # endif
908  {
909 # ifdef _OPENMP
910 # pragma omp for schedule (static)
911 # endif
912  for (index=0; index < numAmps; index++) {
913  combineVecRe[index] *= 1-otherProb;
914  combineVecIm[index] *= 1-otherProb;
915 
916  combineVecRe[index] += otherProb * otherVecRe[index];
917  combineVecIm[index] += otherProb * otherVecIm[index];
918  }
919  }
920 }

References Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by mixDensityMatrix().

◆ densmatr_mixDephasing()

void densmatr_mixDephasing ( Qureg  qureg,
int  targetQubit,
qreal  dephase 
)

Definition at line 79 of file QuEST_cpu.c.

79  {
80  qreal retain=1-dephase;
81  densmatr_oneQubitDegradeOffDiagonal(qureg, targetQubit, retain);
82 }

References densmatr_oneQubitDegradeOffDiagonal(), and qreal.

Referenced by densmatr_mixDepolarising(), densmatr_mixDepolarisingDistributed(), and mixDephasing().

◆ densmatr_mixDepolarising()

void densmatr_mixDepolarising ( Qureg  qureg,
int  targetQubit,
qreal  depolLevel 
)

Definition at line 698 of file QuEST_cpu_distributed.c.

698  {
699  if (depolLevel == 0)
700  return;
701 
702  int rankIsUpper; // rank is in the upper half of an outer block
703  int pairRank; // rank of corresponding chunk
704 
705  int useLocalDataOnly = densityMatrixBlockFitsInChunk(qureg.numAmpsPerChunk,
706  qureg.numQubitsRepresented, targetQubit);
707 
708  if (useLocalDataOnly){
709  densmatr_mixDepolarisingLocal(qureg, targetQubit, depolLevel);
710  } else {
711  // pack data to send to my pair process into the first half of pairStateVec
712  compressPairVectorForSingleQubitDepolarise(qureg, targetQubit);
713 
714  rankIsUpper = chunkIsUpperInOuterBlock(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit,
715  qureg.numQubitsRepresented);
716  pairRank = getChunkOuterBlockPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk,
717  targetQubit, qureg.numQubitsRepresented);
718 
719  exchangePairStateVectorHalves(qureg, pairRank);
720  densmatr_mixDepolarisingDistributed(qureg, targetQubit, depolLevel);
721  }
722 
723 }

References Qureg::chunkId, chunkIsUpperInOuterBlock(), compressPairVectorForSingleQubitDepolarise(), densityMatrixBlockFitsInChunk(), densmatr_mixDephasing(), densmatr_mixDepolarisingDistributed(), densmatr_mixDepolarisingLocal(), Qureg::deviceStateVec, exchangePairStateVectorHalves(), getChunkOuterBlockPairId(), Qureg::numAmpsPerChunk, Qureg::numQubitsRepresented, and qreal.

Referenced by mixDepolarising().

◆ densmatr_mixKrausMap()

void densmatr_mixKrausMap ( Qureg  qureg,
int  target,
ComplexMatrix2 ops,
int  numOps 
)

Definition at line 600 of file QuEST_common.c.

600  {
601 
602  ComplexMatrix4 superOp;
603  populateKrausSuperOperator2(&superOp, ops, numOps);
604  densmatr_applyKrausSuperoperator(qureg, target, superOp);
605 }

References densmatr_applyKrausSuperoperator(), and populateKrausSuperOperator2().

Referenced by densmatr_mixPauli(), and mixKrausMap().

◆ densmatr_mixMultiQubitKrausMap()

void densmatr_mixMultiQubitKrausMap ( Qureg  qureg,
int *  targets,
int  numTargets,
ComplexMatrixN ops,
int  numOps 
)

Definition at line 643 of file QuEST_common.c.

643  {
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 }

References createComplexMatrixN(), densmatr_applyMultiQubitKrausSuperoperator(), destroyComplexMatrixN(), macro_allocStackComplexMatrixN, and populateKrausSuperOperatorN().

Referenced by mixMultiQubitKrausMap().

◆ densmatr_mixPauli()

void densmatr_mixPauli ( Qureg  qureg,
int  qubit,
qreal  pX,
qreal  pY,
qreal  pZ 
)

Definition at line 676 of file QuEST_common.c.

676  {
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 }

References densmatr_mixKrausMap(), ComplexMatrix2::imag, qreal, and ComplexMatrix2::real.

Referenced by mixPauli().

◆ densmatr_mixTwoQubitDephasing()

void densmatr_mixTwoQubitDephasing ( Qureg  qureg,
int  qubit1,
int  qubit2,
qreal  dephase 
)

Definition at line 84 of file QuEST_cpu.c.

84  {
85  qreal retain=1-dephase;
86 
87  long long int numTasks = qureg.numAmpsPerChunk;
88  long long int innerMaskQubit1 = 1LL << qubit1;
89  long long int outerMaskQubit1 = 1LL << (qubit1 + (qureg.numQubitsRepresented));
90  long long int innerMaskQubit2 = 1LL << qubit2;
91  long long int outerMaskQubit2 = 1LL << (qubit2 + (qureg.numQubitsRepresented));
92  long long int totMaskQubit1 = innerMaskQubit1|outerMaskQubit1;
93  long long int totMaskQubit2 = innerMaskQubit2|outerMaskQubit2;
94 
95  long long int thisTask;
96  long long int thisPatternQubit1, thisPatternQubit2;
97 
98 # ifdef _OPENMP
99 # pragma omp parallel \
100  default (none) \
101  shared (innerMaskQubit1,outerMaskQubit1,totMaskQubit1,innerMaskQubit2,outerMaskQubit2, \
102  totMaskQubit2,qureg,retain,numTasks) \
103  private (thisTask,thisPatternQubit1,thisPatternQubit2)
104 # endif
105  {
106 # ifdef _OPENMP
107 # pragma omp for schedule (static)
108 # endif
109  for (thisTask=0; thisTask<numTasks; thisTask++){
110  thisPatternQubit1 = (thisTask+qureg.numAmpsPerChunk*qureg.chunkId)&totMaskQubit1;
111  thisPatternQubit2 = (thisTask+qureg.numAmpsPerChunk*qureg.chunkId)&totMaskQubit2;
112 
113  // any mismatch |...0...><...1...| etc
114  if ( (thisPatternQubit1==innerMaskQubit1) || (thisPatternQubit1==outerMaskQubit1) ||
115  (thisPatternQubit2==innerMaskQubit2) || (thisPatternQubit2==outerMaskQubit2) ){
116  // do dephase
117  // the lines below will degrade the off-diagonal terms |..0..><..1..| and |..1..><..0..|
118  qureg.stateVec.real[thisTask] = retain*qureg.stateVec.real[thisTask];
119  qureg.stateVec.imag[thisTask] = retain*qureg.stateVec.imag[thisTask];
120  }
121  }
122  }
123 }

References Qureg::chunkId, Qureg::deviceStateVec, Qureg::numAmpsPerChunk, Qureg::numQubitsRepresented, qreal, and Qureg::stateVec.

Referenced by densmatr_mixTwoQubitDepolarising(), and mixTwoQubitDephasing().

◆ densmatr_mixTwoQubitDepolarising()

void densmatr_mixTwoQubitDepolarising ( Qureg  qureg,
int  qubit1,
int  qubit2,
qreal  depolLevel 
)

Definition at line 752 of file QuEST_cpu_distributed.c.

752  {
753  if (depolLevel == 0)
754  return;
755  int rankIsUpperBiggerQubit, rankIsUpperSmallerQubit;
756  int pairRank; // rank of corresponding chunk
757  int biggerQubit, smallerQubit;
758 
759  densmatr_mixTwoQubitDephasing(qureg, qubit1, qubit2, depolLevel);
760 
761  qreal eta = 2/depolLevel;
762  qreal delta = eta - 1 - sqrt( (eta-1)*(eta-1) - 1 );
763  qreal gamma = 1+delta;
764  gamma = 1/(gamma*gamma*gamma);
765  qreal GAMMA_PARTS_1_OR_2 = 1.0;
766  // TODO -- test delta too small
767  /*
768  if (fabs(4*delta*(1+delta)*gamma-depolLevel)>1e-5){
769  printf("Numerical error in delta; for small error rates try Taylor expansion.\n");
770  exit(1);
771  }
772  */
773 
774  biggerQubit = qubit1 > qubit2 ? qubit1 : qubit2;
775  smallerQubit = qubit1 < qubit2 ? qubit1 : qubit2;
776  int useLocalDataOnlyBigQubit, useLocalDataOnlySmallQubit;
777 
778  useLocalDataOnlyBigQubit = densityMatrixBlockFitsInChunk(qureg.numAmpsPerChunk,
779  qureg.numQubitsRepresented, biggerQubit);
780  if (useLocalDataOnlyBigQubit){
781  // does parts 1, 2 and 3 locally in one go
782  densmatr_mixTwoQubitDepolarisingLocal(qureg, qubit1, qubit2, delta, gamma);
783  } else {
784  useLocalDataOnlySmallQubit = densityMatrixBlockFitsInChunk(qureg.numAmpsPerChunk,
785  qureg.numQubitsRepresented, smallerQubit);
786  if (useLocalDataOnlySmallQubit){
787  // do part 1 locally
788  densmatr_mixTwoQubitDepolarisingLocalPart1(qureg, smallerQubit, biggerQubit, delta);
789 
790  // do parts 2 and 3 distributed (if part 2 is distributed part 3 is also distributed)
791  // part 2 will be distributed and the value of the small qubit won't matter
792  compressPairVectorForTwoQubitDepolarise(qureg, smallerQubit, biggerQubit);
793  rankIsUpperBiggerQubit = chunkIsUpperInOuterBlock(qureg.chunkId, qureg.numAmpsPerChunk, biggerQubit,
794  qureg.numQubitsRepresented);
795  pairRank = getChunkOuterBlockPairId(rankIsUpperBiggerQubit, qureg.chunkId, qureg.numAmpsPerChunk,
796  biggerQubit, qureg.numQubitsRepresented);
797 
798  exchangePairStateVectorHalves(qureg, pairRank);
799  densmatr_mixTwoQubitDepolarisingDistributed(qureg, smallerQubit, biggerQubit, delta, GAMMA_PARTS_1_OR_2);
800 
801  // part 3 will be distributed but involve rearranging for the smaller qubit
802  compressPairVectorForTwoQubitDepolarise(qureg, smallerQubit, biggerQubit);
803  rankIsUpperBiggerQubit = chunkIsUpperInOuterBlock(qureg.chunkId, qureg.numAmpsPerChunk, biggerQubit,
804  qureg.numQubitsRepresented);
805  pairRank = getChunkOuterBlockPairId(rankIsUpperBiggerQubit, qureg.chunkId, qureg.numAmpsPerChunk,
806  biggerQubit, qureg.numQubitsRepresented);
807 
808  exchangePairStateVectorHalves(qureg, pairRank);
809  densmatr_mixTwoQubitDepolarisingQ1LocalQ2DistributedPart3(qureg, smallerQubit, biggerQubit, delta, gamma);
810  } else {
811  // do part 1, 2 and 3 distributed
812  // part 1
813  compressPairVectorForTwoQubitDepolarise(qureg, smallerQubit, biggerQubit);
814  rankIsUpperSmallerQubit = chunkIsUpperInOuterBlock(qureg.chunkId, qureg.numAmpsPerChunk, smallerQubit,
815  qureg.numQubitsRepresented);
816  pairRank = getChunkOuterBlockPairId(rankIsUpperSmallerQubit, qureg.chunkId, qureg.numAmpsPerChunk,
817  smallerQubit, qureg.numQubitsRepresented);
818 
819  exchangePairStateVectorHalves(qureg, pairRank);
820  densmatr_mixTwoQubitDepolarisingDistributed(qureg, smallerQubit, biggerQubit, delta, GAMMA_PARTS_1_OR_2);
821 
822  // part 2
823  compressPairVectorForTwoQubitDepolarise(qureg, smallerQubit, biggerQubit);
824  rankIsUpperBiggerQubit = chunkIsUpperInOuterBlock(qureg.chunkId, qureg.numAmpsPerChunk, biggerQubit,
825  qureg.numQubitsRepresented);
826  pairRank = getChunkOuterBlockPairId(rankIsUpperBiggerQubit, qureg.chunkId, qureg.numAmpsPerChunk,
827  biggerQubit, qureg.numQubitsRepresented);
828 
829  exchangePairStateVectorHalves(qureg, pairRank);
830  densmatr_mixTwoQubitDepolarisingDistributed(qureg, smallerQubit, biggerQubit, delta, GAMMA_PARTS_1_OR_2);
831 
832  // part 3
833  compressPairVectorForTwoQubitDepolarise(qureg, smallerQubit, biggerQubit);
834  pairRank = getChunkOuterBlockPairIdForPart3(rankIsUpperSmallerQubit, rankIsUpperBiggerQubit,
835  qureg.chunkId, qureg.numAmpsPerChunk, smallerQubit, biggerQubit, qureg.numQubitsRepresented);
836  exchangePairStateVectorHalves(qureg, pairRank);
837  densmatr_mixTwoQubitDepolarisingDistributed(qureg, smallerQubit, biggerQubit, delta, gamma);
838 
839  }
840  }
841 
842 }

References Qureg::chunkId, chunkIsUpperInOuterBlock(), compressPairVectorForTwoQubitDepolarise(), densityMatrixBlockFitsInChunk(), densmatr_mixTwoQubitDephasing(), densmatr_mixTwoQubitDepolarisingDistributed(), densmatr_mixTwoQubitDepolarisingLocal(), densmatr_mixTwoQubitDepolarisingLocalPart1(), densmatr_mixTwoQubitDepolarisingQ1LocalQ2DistributedPart3(), Qureg::deviceStateVec, exchangePairStateVectorHalves(), getChunkOuterBlockPairId(), getChunkOuterBlockPairIdForPart3(), Qureg::numAmpsPerChunk, Qureg::numQubitsRepresented, and qreal.

Referenced by mixTwoQubitDepolarising().

◆ densmatr_mixTwoQubitKrausMap()

void densmatr_mixTwoQubitKrausMap ( Qureg  qureg,
int  target1,
int  target2,
ComplexMatrix4 ops,
int  numOps 
)

Definition at line 635 of file QuEST_common.c.

635  {
636 
637  ComplexMatrixN superOp;
638  macro_allocStackComplexMatrixN(superOp, 4);
639  populateKrausSuperOperator4(&superOp, ops, numOps);
640  densmatr_applyTwoQubitKrausSuperoperator(qureg, target1, target2, superOp);
641 }

References densmatr_applyTwoQubitKrausSuperoperator(), macro_allocStackComplexMatrixN, and populateKrausSuperOperator4().

Referenced by mixTwoQubitKrausMap().

◆ ensureIndsIncrease()

void ensureIndsIncrease ( int *  ind1,
int *  ind2 
)

Definition at line 64 of file QuEST_common.c.

64  {
65 
66  if (*ind1 > *ind2) {
67  int copy = *ind1;
68  *ind1 = *ind2;
69  *ind2 = copy;
70  }
71 }

Referenced by mixTwoQubitDephasing(), and mixTwoQubitDepolarising().

◆ getComplexPairAndPhaseFromUnitary()

void getComplexPairAndPhaseFromUnitary ( ComplexMatrix2  u,
Complex alpha,
Complex beta,
qreal globalPhase 
)

maps U(r0c0, r0c1, r1c0, r1c1) to exp(i globalPhase) U(alpha, beta)

Definition at line 136 of file QuEST_common.c.

136  {
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 }

References Complex::imag, ComplexMatrix2::imag, qreal, Complex::real, and ComplexMatrix2::real.

Referenced by qasm_recordControlledUnitary(), qasm_recordMultiControlledUnitary(), and qasm_recordUnitary().

◆ getComplexPairFromRotation()

void getComplexPairFromRotation ( qreal  angle,
Vector  axis,
Complex alpha,
Complex beta 
)

Definition at line 114 of file QuEST_common.c.

114  {
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 }

References getUnitVector(), Complex::imag, Complex::real, Vector::x, Vector::y, and Vector::z.

Referenced by qasm_recordAxisRotation(), qasm_recordControlledAxisRotation(), statevec_controlledRotateAroundAxis(), statevec_controlledRotateAroundAxisConj(), statevec_rotateAroundAxis(), and statevec_rotateAroundAxisConj().

◆ getConjugateMatrix2()

ComplexMatrix2 getConjugateMatrix2 ( ComplexMatrix2  src)

Definition at line 99 of file QuEST_common.c.

99  {
100  ComplexMatrix2 conj;
101  macro_setConjugateMatrix(conj, src, 2);
102  return conj;
103 }

References macro_setConjugateMatrix.

Referenced by controlledUnitary(), multiControlledUnitary(), multiStateControlledUnitary(), and unitary().

◆ getConjugateMatrix4()

ComplexMatrix4 getConjugateMatrix4 ( ComplexMatrix4  src)

Definition at line 104 of file QuEST_common.c.

104  {
105  ComplexMatrix4 conj;
106  macro_setConjugateMatrix(conj, src, 4);
107  return conj;
108 }

References macro_setConjugateMatrix.

Referenced by controlledTwoQubitUnitary(), multiControlledTwoQubitUnitary(), and twoQubitUnitary().

◆ getConjugateScalar()

Complex getConjugateScalar ( Complex  scalar)

Definition at line 85 of file QuEST_common.c.

85  {
86 
87  Complex conjScalar;
88  conjScalar.real = scalar.real;
89  conjScalar.imag = - scalar.imag;
90  return conjScalar;
91 }

References Complex::imag, and Complex::real.

Referenced by compactUnitary(), and controlledCompactUnitary().

◆ getControlFlipMask()

long long int getControlFlipMask ( int *  controlQubits,
int *  controlState,
int  numControlQubits 
)

Definition at line 54 of file QuEST_common.c.

54  {
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 }

Referenced by multiStateControlledUnitary().

◆ getQubitBitMask()

long long int getQubitBitMask ( int *  controlQubits,
int  numControlQubits 
)

◆ getQuESTDefaultSeedKey()

void getQuESTDefaultSeedKey ( unsigned long int *  key)

Definition at line 182 of file QuEST_common.c.

182  {
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 }

Referenced by seedQuESTDefault().

◆ getVectorMagnitude()

qreal getVectorMagnitude ( Vector  vec)

Definition at line 73 of file QuEST_common.c.

73  {
74 
75  return sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
76 }

References Vector::x, Vector::y, and Vector::z.

Referenced by getUnitVector(), and validateVector().

◆ getZYZRotAnglesFromComplexPair()

void getZYZRotAnglesFromComplexPair ( Complex  alpha,
Complex  beta,
qreal rz2,
qreal ry,
qreal rz1 
)

maps U(alpha, beta) to Rz(rz2) Ry(ry) Rz(rz1)

Definition at line 124 of file QuEST_common.c.

124  {
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 }

References Complex::imag, qreal, and Complex::real.

Referenced by qasm_recordAxisRotation(), qasm_recordCompactUnitary(), qasm_recordControlledAxisRotation(), qasm_recordControlledCompactUnitary(), qasm_recordControlledUnitary(), qasm_recordMultiControlledUnitary(), and qasm_recordUnitary().

◆ hashString()

unsigned long int hashString ( char *  str)

Definition at line 172 of file QuEST_common.c.

172  {
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 }

◆ setConjugateMatrixN()

void setConjugateMatrixN ( ComplexMatrixN  m)

Definition at line 109 of file QuEST_common.c.

109  {
110  int len = 1 << m.numQubits;
111  macro_setConjugateMatrix(m, m, len);
112 }

References macro_setConjugateMatrix, and ComplexMatrixN::numQubits.

Referenced by controlledMultiQubitUnitary(), multiControlledMultiQubitUnitary(), and multiQubitUnitary().

◆ shiftIndices()

void shiftIndices ( int *  indices,
int  numIndices,
int  shift 
)

Definition at line 150 of file QuEST_common.c.

150  {
151  for (int j=0; j < numIndices; j++)
152  indices[j] += shift;
153 }

Referenced by controlledMultiQubitUnitary(), multiControlledMultiQubitUnitary(), multiControlledPhaseFlip(), multiControlledPhaseShift(), multiQubitUnitary(), and multiRotatePauli().

◆ statevec_applyDiagonalOp()

void statevec_applyDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 3661 of file QuEST_cpu.c.

3661  {
3662 
3663  // each node/chunk modifies only its values in an embarrassingly parallelisable way
3664  long long int numAmps = qureg.numAmpsPerChunk;
3665 
3666  qreal* stateRe = qureg.stateVec.real;
3667  qreal* stateIm = qureg.stateVec.imag;
3668  qreal* opRe = op.real;
3669  qreal* opIm = op.imag;
3670 
3671  qreal a,b,c,d;
3672  long long int index;
3673 
3674 # ifdef _OPENMP
3675 # pragma omp parallel \
3676  shared (stateRe,stateIm, opRe,opIm, numAmps) \
3677  private (index, a,b,c,d)
3678 # endif
3679  {
3680 # ifdef _OPENMP
3681 # pragma omp for schedule (static)
3682 # endif
3683  for (index=0LL; index<numAmps; index++) {
3684  a = stateRe[index];
3685  b = stateIm[index];
3686  c = opRe[index];
3687  d = opIm[index];
3688 
3689  // (a + b i)(c + d i) = (a c - b d) + i (a d + b c)
3690  stateRe[index] = a*c - b*d;
3691  stateIm[index] = a*d + b*c;
3692  }
3693  }
3694 }

References DiagonalOp::imag, Qureg::numAmpsPerChunk, qreal, DiagonalOp::real, and Qureg::stateVec.

Referenced by applyDiagonalOp().

◆ statevec_applyPauliSum()

void statevec_applyPauliSum ( Qureg  inQureg,
enum pauliOpType allCodes,
qreal termCoeffs,
int  numSumTerms,
Qureg  outQureg 
)

Definition at line 494 of file QuEST_common.c.

494  {
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 }

References Qureg::numQubitsRepresented, Complex::real, statevec_applyPauliProd(), statevec_initBlankState(), and statevec_setWeightedQureg().

Referenced by applyPauliHamil(), and applyPauliSum().

◆ statevec_calcExpecDiagonalOp()

Complex statevec_calcExpecDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 1523 of file QuEST_cpu_distributed.c.

1523  {
1524 
1525  Complex localExpec = statevec_calcExpecDiagonalOpLocal(qureg, op);
1526  if (qureg.numChunks == 1)
1527  return localExpec;
1528 
1529  qreal localReal = localExpec.real;
1530  qreal localImag = localExpec.imag;
1531  qreal globalReal, globalImag;
1532  MPI_Allreduce(&localReal, &globalReal, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1533  MPI_Allreduce(&localImag, &globalImag, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1534 
1535  Complex globalExpec;
1536  globalExpec.real = globalReal;
1537  globalExpec.imag = globalImag;
1538  return globalExpec;
1539 }

References copySharedReduceBlock(), DiagonalOp::deviceOperator, Qureg::deviceStateVec, Qureg::firstLevelReduction, Complex::imag, Qureg::numAmpsPerChunk, Qureg::numChunks, qreal, Complex::real, REDUCE_SHARED_SIZE, Qureg::secondLevelReduction, statevec_calcExpecDiagonalOpLocal(), and swapDouble().

Referenced by calcExpecDiagonalOp().

◆ statevec_calcExpecPauliProd()

qreal statevec_calcExpecPauliProd ( Qureg  qureg,
int *  targetQubits,
enum pauliOpType pauliCodes,
int  numTargets,
Qureg  workspace 
)

Definition at line 465 of file QuEST_common.c.

465  {
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 }

References densmatr_calcTotalProb(), Qureg::isDensityMatrix, qreal, Complex::real, statevec_applyPauliProd(), statevec_calcInnerProduct(), and statevec_cloneQureg().

Referenced by calcExpecPauliProd(), and statevec_calcExpecPauliSum().

◆ statevec_calcExpecPauliSum()

qreal statevec_calcExpecPauliSum ( Qureg  qureg,
enum pauliOpType allCodes,
qreal termCoeffs,
int  numSumTerms,
Qureg  workspace 
)

Definition at line 480 of file QuEST_common.c.

480  {
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 }

References Qureg::numQubitsRepresented, qreal, and statevec_calcExpecPauliProd().

Referenced by calcExpecPauliHamil(), and calcExpecPauliSum().

◆ statevec_calcFidelity()

qreal statevec_calcFidelity ( Qureg  qureg,
Qureg  pureState 
)

Definition at line 377 of file QuEST_common.c.

377  {
378 
379  Complex innerProd = statevec_calcInnerProduct(qureg, pureState);
380  qreal innerProdMag = innerProd.real*innerProd.real + innerProd.imag*innerProd.imag;
381  return innerProdMag;
382 }

References Complex::imag, qreal, Complex::real, and statevec_calcInnerProduct().

Referenced by calcFidelity().

◆ statevec_calcInnerProduct()

Complex statevec_calcInnerProduct ( Qureg  bra,
Qureg  ket 
)

Terrible code which unnecessarily individually computes and sums the real and imaginary components of the inner product, so as to not have to worry about keeping the sums separated during reduction.

Truly disgusting, probably doubles runtime, please fix. @TODO could even do the kernel twice, storing real in bra.reduc and imag in ket.reduc?

Definition at line 35 of file QuEST_cpu_distributed.c.

35  {
36 
37  Complex localInnerProd = statevec_calcInnerProductLocal(bra, ket);
38  if (bra.numChunks == 1)
39  return localInnerProd;
40 
41  qreal localReal = localInnerProd.real;
42  qreal localImag = localInnerProd.imag;
43  qreal globalReal, globalImag;
44  MPI_Allreduce(&localReal, &globalReal, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
45  MPI_Allreduce(&localImag, &globalImag, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
46 
47  Complex globalInnerProd;
48  globalInnerProd.real = globalReal;
49  globalInnerProd.imag = globalImag;
50  return globalInnerProd;
51 }

References copySharedReduceBlock(), Qureg::deviceStateVec, Qureg::firstLevelReduction, Complex::imag, Qureg::numAmpsPerChunk, Qureg::numChunks, qreal, Complex::real, REDUCE_SHARED_SIZE, Qureg::secondLevelReduction, statevec_calcInnerProductLocal(), and swapDouble().

Referenced by calcInnerProduct(), statevec_calcExpecPauliProd(), and statevec_calcFidelity().

◆ statevec_calcProbOfOutcome()

qreal statevec_calcProbOfOutcome ( Qureg  qureg,
int  measureQubit,
int  outcome 
)

Definition at line 1260 of file QuEST_cpu_distributed.c.

1261 {
1262  qreal stateProb=0, totalStateProb=0;
1263  int skipValuesWithinRank = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, measureQubit);
1264  if (skipValuesWithinRank) {
1265  stateProb = statevec_findProbabilityOfZeroLocal(qureg, measureQubit);
1266  } else {
1267  if (!isChunkToSkipInFindPZero(qureg.chunkId, qureg.numAmpsPerChunk, measureQubit)){
1268  stateProb = statevec_findProbabilityOfZeroDistributed(qureg);
1269  } else stateProb = 0;
1270  }
1271  MPI_Allreduce(&stateProb, &totalStateProb, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1272  if (outcome==1) totalStateProb = 1.0 - totalStateProb;
1273  return totalStateProb;
1274 }

References Qureg::chunkId, halfMatrixBlockFitsInChunk(), isChunkToSkipInFindPZero(), Qureg::numAmpsPerChunk, qreal, statevec_findProbabilityOfZero(), statevec_findProbabilityOfZeroDistributed(), and statevec_findProbabilityOfZeroLocal().

Referenced by calcProbOfOutcome(), collapseToOutcome(), and statevec_measureWithStats().

◆ statevec_calcTotalProb()

qreal statevec_calcTotalProb ( Qureg  qureg)

Definition at line 88 of file QuEST_cpu_distributed.c.

88  {
89  // Implemented using Kahan summation for greater accuracy at a slight floating
90  // point operation overhead. For more details see https://en.wikipedia.org/wiki/Kahan_summation_algorithm
91  qreal pTotal=0;
92  qreal y, t, c;
93  qreal allRankTotals=0;
94  long long int index;
95  long long int numAmpsPerRank = qureg.numAmpsPerChunk;
96  c = 0.0;
97  for (index=0; index<numAmpsPerRank; index++){
98  // Perform pTotal+=qureg.stateVec.real[index]*qureg.stateVec.real[index]; by Kahan
99  y = qureg.stateVec.real[index]*qureg.stateVec.real[index] - c;
100  t = pTotal + y;
101  // Don't change the bracketing on the following line
102  c = ( t - pTotal ) - y;
103  pTotal = t;
104  // Perform pTotal+=qureg.stateVec.imag[index]*qureg.stateVec.imag[index]; by Kahan
105  y = qureg.stateVec.imag[index]*qureg.stateVec.imag[index] - c;
106  t = pTotal + y;
107  // Don't change the bracketing on the following line
108  c = ( t - pTotal ) - y;
109  pTotal = t;
110  }
111  if (qureg.numChunks>1)
112  MPI_Allreduce(&pTotal, &allRankTotals, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
113  else
114  allRankTotals=pTotal;
115 
116  return allRankTotals;
117 }

References copyStateFromGPU(), Qureg::numAmpsPerChunk, Qureg::numChunks, qreal, and Qureg::stateVec.

Referenced by calcTotalProb().

◆ statevec_cloneQureg()

void statevec_cloneQureg ( Qureg  targetQureg,
Qureg  copyQureg 
)

works for both statevectors and density matrices

Definition at line 1506 of file QuEST_cpu.c.

1506  {
1507 
1508  // registers are equal sized, so nodes hold the same state-vector partitions
1509  long long int stateVecSize;
1510  long long int index;
1511 
1512  // dimension of the state vector
1513  stateVecSize = targetQureg.numAmpsPerChunk;
1514 
1515  // Can't use qureg->stateVec as a private OMP var
1516  qreal *targetStateVecReal = targetQureg.stateVec.real;
1517  qreal *targetStateVecImag = targetQureg.stateVec.imag;
1518  qreal *copyStateVecReal = copyQureg.stateVec.real;
1519  qreal *copyStateVecImag = copyQureg.stateVec.imag;
1520 
1521  // initialise the state to |0000..0000>
1522 # ifdef _OPENMP
1523 # pragma omp parallel \
1524  default (none) \
1525  shared (stateVecSize, targetStateVecReal, targetStateVecImag, copyStateVecReal, copyStateVecImag) \
1526  private (index)
1527 # endif
1528  {
1529 # ifdef _OPENMP
1530 # pragma omp for schedule (static)
1531 # endif
1532  for (index=0; index<stateVecSize; index++) {
1533  targetStateVecReal[index] = copyStateVecReal[index];
1534  targetStateVecImag[index] = copyStateVecImag[index];
1535  }
1536  }
1537 }

References Qureg::deviceStateVec, Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by cloneQureg(), createCloneQureg(), initPureState(), and statevec_calcExpecPauliProd().

◆ statevec_collapseToKnownProbOutcome()

void statevec_collapseToKnownProbOutcome ( Qureg  qureg,
int  measureQubit,
int  outcome,
qreal  outcomeProb 
)

Definition at line 1298 of file QuEST_cpu_distributed.c.

1299 {
1300  int skipValuesWithinRank = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, measureQubit);
1301  if (skipValuesWithinRank) {
1302  statevec_collapseToKnownProbOutcomeLocal(qureg, measureQubit, outcome, totalStateProb);
1303  } else {
1304  if (!isChunkToSkipInFindPZero(qureg.chunkId, qureg.numAmpsPerChunk, measureQubit)){
1305  // chunk has amps for q=0
1306  if (outcome==0) statevec_collapseToKnownProbOutcomeDistributedRenorm(qureg, measureQubit,
1307  totalStateProb);
1309  } else {
1310  // chunk has amps for q=1
1311  if (outcome==1) statevec_collapseToKnownProbOutcomeDistributedRenorm(qureg, measureQubit,
1312  totalStateProb);
1314  }
1315  }
1316 }

References Qureg::chunkId, halfMatrixBlockFitsInChunk(), isChunkToSkipInFindPZero(), Qureg::numAmpsPerChunk, qreal, statevec_collapseToKnownProbOutcomeDistributedRenorm(), statevec_collapseToKnownProbOutcomeLocal(), and statevec_collapseToOutcomeDistributedSetZero().

Referenced by collapseToOutcome(), and statevec_measureWithStats().

◆ statevec_compactUnitary()

void statevec_compactUnitary ( Qureg  qureg,
int  targetQubit,
Complex  alpha,
Complex  beta 
)

Definition at line 844 of file QuEST_cpu_distributed.c.

845 {
846  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
847  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
848  Complex rot1, rot2;
849 
850  // rank's chunk is in upper half of block
851  int rankIsUpper;
852  int pairRank; // rank of corresponding chunk
853 
854  if (useLocalDataOnly){
855  // all values required to update state vector lie in this rank
856  statevec_compactUnitaryLocal(qureg, targetQubit, alpha, beta);
857  } else {
858  // need to get corresponding chunk of state vector from other rank
859  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
860  getRotAngle(rankIsUpper, &rot1, &rot2, alpha, beta);
861  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
862  // get corresponding values from my pair
863  exchangeStateVectors(qureg, pairRank);
864 
865  // this rank's values are either in the upper of lower half of the block.
866  // send values to compactUnitaryDistributed in the correct order
867  if (rankIsUpper){
868  statevec_compactUnitaryDistributed(qureg,rot1,rot2,
869  qureg.stateVec, //upper
870  qureg.pairStateVec, //lower
871  qureg.stateVec); //output
872  } else {
873  statevec_compactUnitaryDistributed(qureg,rot1,rot2,
874  qureg.pairStateVec, //upper
875  qureg.stateVec, //lower
876  qureg.stateVec); //output
877  }
878  }
879 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), getRotAngle(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_compactUnitaryDistributed(), and statevec_compactUnitaryLocal().

Referenced by compactUnitary(), statevec_multiRotatePauli(), statevec_rotateAroundAxis(), and statevec_rotateAroundAxisConj().

◆ statevec_compareStates()

int statevec_compareStates ( Qureg  mq1,
Qureg  mq2,
qreal  precision 
)

Definition at line 1675 of file QuEST_cpu.c.

1675  {
1676  qreal diff;
1677  long long int chunkSize = mq1.numAmpsPerChunk;
1678 
1679  for (long long int i=0; i<chunkSize; i++){
1680  diff = absReal(mq1.stateVec.real[i] - mq2.stateVec.real[i]);
1681  if (diff>precision) return 0;
1682  diff = absReal(mq1.stateVec.imag[i] - mq2.stateVec.imag[i]);
1683  if (diff>precision) return 0;
1684  }
1685  return 1;
1686 }

References copyStateFromGPU(), Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by compareStates().

◆ statevec_controlledCompactUnitary()

void statevec_controlledCompactUnitary ( Qureg  qureg,
int  controlQubit,
int  targetQubit,
Complex  alpha,
Complex  beta 
)

Definition at line 920 of file QuEST_cpu_distributed.c.

921 {
922  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
923  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
924  Complex rot1, rot2;
925 
926  // rank's chunk is in upper half of block
927  int rankIsUpper;
928  int pairRank; // rank of corresponding chunk
929 
930  if (useLocalDataOnly){
931  // all values required to update state vector lie in this rank
932  statevec_controlledCompactUnitaryLocal(qureg, controlQubit, targetQubit, alpha, beta);
933  } else {
934  // need to get corresponding chunk of state vector from other rank
935  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
936  getRotAngle(rankIsUpper, &rot1, &rot2, alpha, beta);
937  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
938  //printf("%d rank has pair rank: %d\n", qureg.rank, pairRank);
939  // get corresponding values from my pair
940  exchangeStateVectors(qureg, pairRank);
941 
942  // this rank's values are either in the upper of lower half of the block. send values to controlledCompactUnitaryDistributed
943  // in the correct order
944  if (rankIsUpper){
945  statevec_controlledCompactUnitaryDistributed(qureg,controlQubit,rot1,rot2,
946  qureg.stateVec, //upper
947  qureg.pairStateVec, //lower
948  qureg.stateVec); //output
949  } else {
950  statevec_controlledCompactUnitaryDistributed(qureg,controlQubit,rot1,rot2,
951  qureg.pairStateVec, //upper
952  qureg.stateVec, //lower
953  qureg.stateVec); //output
954  }
955  }
956 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), getRotAngle(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_controlledCompactUnitaryDistributed(), and statevec_controlledCompactUnitaryLocal().

Referenced by controlledCompactUnitary(), statevec_controlledRotateAroundAxis(), and statevec_controlledRotateAroundAxisConj().

◆ statevec_controlledMultiQubitUnitary()

void statevec_controlledMultiQubitUnitary ( Qureg  qureg,
int  ctrl,
int *  targets,
int  numTargets,
ComplexMatrixN  u 
)

Definition at line 535 of file QuEST_common.c.

535  {
536 
537  long long int ctrlMask = 1LL << ctrl;
538  statevec_multiControlledMultiQubitUnitary(qureg, ctrlMask, targets, numTargets, u);
539 }

References statevec_multiControlledMultiQubitUnitary().

Referenced by controlledMultiQubitUnitary().

◆ statevec_controlledNot()

void statevec_controlledNot ( Qureg  qureg,
int  controlQubit,
int  targetQubit 
)

Definition at line 1061 of file QuEST_cpu_distributed.c.

1062 {
1063  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1064  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1065  int rankIsUpper; // rank's chunk is in upper half of block
1066  int pairRank; // rank of corresponding chunk
1067 
1068  if (useLocalDataOnly){
1069  // all values required to update state vector lie in this rank
1070  statevec_controlledNotLocal(qureg, controlQubit, targetQubit);
1071  } else {
1072  // need to get corresponding chunk of state vector from other rank
1073  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1074  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1075  // get corresponding values from my pair
1076  exchangeStateVectors(qureg, pairRank);
1077  // this rank's values are either in the upper of lower half of the block
1078  if (rankIsUpper){
1079  statevec_controlledNotDistributed(qureg,controlQubit,
1080  qureg.pairStateVec, //in
1081  qureg.stateVec); //out
1082  } else {
1083  statevec_controlledNotDistributed(qureg,controlQubit,
1084  qureg.pairStateVec, //in
1085  qureg.stateVec); //out
1086  }
1087  }
1088 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_controlledNotDistributed(), and statevec_controlledNotLocal().

Referenced by controlledNot().

◆ statevec_controlledPauliY()

void statevec_controlledPauliY ( Qureg  qureg,
int  controlQubit,
int  targetQubit 
)

Definition at line 1140 of file QuEST_cpu_distributed.c.

1141 {
1142  int conjFac = 1;
1143 
1144  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1145  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1146  int rankIsUpper; // rank's chunk is in upper half of block
1147  int pairRank; // rank of corresponding chunk
1148 
1149  if (useLocalDataOnly){
1150  // all values required to update state vector lie in this rank
1151  statevec_controlledPauliYLocal(qureg, controlQubit, targetQubit, conjFac);
1152  } else {
1153  // need to get corresponding chunk of state vector from other rank
1154  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1155  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1156  // get corresponding values from my pair
1157  exchangeStateVectors(qureg, pairRank);
1158  // this rank's values are either in the upper of lower half of the block
1159  if (rankIsUpper){
1160  statevec_controlledPauliYDistributed(qureg,controlQubit,
1161  qureg.pairStateVec, //in
1162  qureg.stateVec,
1163  conjFac); //out
1164  } else {
1165  statevec_controlledPauliYDistributed(qureg,controlQubit,
1166  qureg.pairStateVec, //in
1167  qureg.stateVec,
1168  -conjFac); //out
1169  }
1170  }
1171 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_controlledPauliYDistributed(), and statevec_controlledPauliYLocal().

Referenced by controlledPauliY().

◆ statevec_controlledPauliYConj()

void statevec_controlledPauliYConj ( Qureg  qureg,
int  controlQubit,
int  targetQubit 
)

Definition at line 1173 of file QuEST_cpu_distributed.c.

1174 {
1175  int conjFac = -1;
1176 
1177  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1178  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1179  int rankIsUpper; // rank's chunk is in upper half of block
1180  int pairRank; // rank of corresponding chunk
1181 
1182  if (useLocalDataOnly){
1183  // all values required to update state vector lie in this rank
1184  statevec_controlledPauliYLocal(qureg, controlQubit, targetQubit, conjFac);
1185  } else {
1186  // need to get corresponding chunk of state vector from other rank
1187  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1188  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1189  // get corresponding values from my pair
1190  exchangeStateVectors(qureg, pairRank);
1191  // this rank's values are either in the upper of lower half of the block
1192  if (rankIsUpper){
1193  statevec_controlledPauliYDistributed(qureg,controlQubit,
1194  qureg.pairStateVec, //in
1195  qureg.stateVec,
1196  conjFac); //out
1197  } else {
1198  statevec_controlledPauliYDistributed(qureg,controlQubit,
1199  qureg.pairStateVec, //in
1200  qureg.stateVec,
1201  -conjFac); //out
1202  }
1203  }
1204 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_controlledPauliYDistributed(), and statevec_controlledPauliYLocal().

Referenced by controlledPauliY().

◆ statevec_controlledPhaseFlip()

void statevec_controlledPhaseFlip ( Qureg  qureg,
int  idQubit1,
int  idQubit2 
)

Definition at line 3300 of file QuEST_cpu.c.

3301 {
3302  long long int index;
3303  long long int stateVecSize;
3304  int bit1, bit2;
3305 
3306  long long int chunkSize=qureg.numAmpsPerChunk;
3307  long long int chunkId=qureg.chunkId;
3308 
3309  // dimension of the state vector
3310  stateVecSize = qureg.numAmpsPerChunk;
3311  qreal *stateVecReal = qureg.stateVec.real;
3312  qreal *stateVecImag = qureg.stateVec.imag;
3313 
3314 # ifdef _OPENMP
3315 # pragma omp parallel for \
3316  default (none) \
3317  shared (stateVecSize, stateVecReal,stateVecImag, chunkId,chunkSize,idQubit1,idQubit2 ) \
3318  private (index,bit1,bit2) \
3319  schedule (static)
3320 # endif
3321  for (index=0; index<stateVecSize; index++) {
3322  bit1 = extractBit (idQubit1, index+chunkId*chunkSize);
3323  bit2 = extractBit (idQubit2, index+chunkId*chunkSize);
3324  if (bit1 && bit2) {
3325  stateVecReal [index] = - stateVecReal [index];
3326  stateVecImag [index] = - stateVecImag [index];
3327  }
3328  }
3329 }

References Qureg::chunkId, extractBit(), Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by controlledPhaseFlip().

◆ statevec_controlledPhaseShift()

void statevec_controlledPhaseShift ( Qureg  qureg,
int  idQubit1,
int  idQubit2,
qreal  angle 
)

Definition at line 3019 of file QuEST_cpu.c.

3020 {
3021  long long int index;
3022  long long int stateVecSize;
3023  int bit1, bit2;
3024 
3025  long long int chunkSize=qureg.numAmpsPerChunk;
3026  long long int chunkId=qureg.chunkId;
3027 
3028  // dimension of the state vector
3029  stateVecSize = qureg.numAmpsPerChunk;
3030  qreal *stateVecReal = qureg.stateVec.real;
3031  qreal *stateVecImag = qureg.stateVec.imag;
3032 
3033  qreal stateRealLo, stateImagLo;
3034  qreal cosAngle = cos(angle);
3035  qreal sinAngle = sin(angle);
3036 
3037 # ifdef _OPENMP
3038 # pragma omp parallel for \
3039  default (none) \
3040  shared (stateVecSize, stateVecReal,stateVecImag, chunkId,chunkSize, \
3041  idQubit1,idQubit2,cosAngle,sinAngle ) \
3042  private (index,bit1,bit2,stateRealLo,stateImagLo) \
3043  schedule (static)
3044 # endif
3045  for (index=0; index<stateVecSize; index++) {
3046  bit1 = extractBit (idQubit1, index+chunkId*chunkSize);
3047  bit2 = extractBit (idQubit2, index+chunkId*chunkSize);
3048  if (bit1 && bit2) {
3049 
3050  stateRealLo = stateVecReal[index];
3051  stateImagLo = stateVecImag[index];
3052 
3053  stateVecReal[index] = cosAngle*stateRealLo - sinAngle*stateImagLo;
3054  stateVecImag[index] = sinAngle*stateRealLo + cosAngle*stateImagLo;
3055  }
3056  }
3057 }

References Qureg::chunkId, extractBit(), Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by controlledPhaseShift().

◆ statevec_controlledRotateAroundAxis()

void statevec_controlledRotateAroundAxis ( Qureg  qureg,
int  controlQubit,
int  targetQubit,
qreal  angle,
Vector  axis 
)

Definition at line 327 of file QuEST_common.c.

327  {
328 
329  Complex alpha, beta;
330  getComplexPairFromRotation(angle, axis, &alpha, &beta);
331  statevec_controlledCompactUnitary(qureg, controlQubit, targetQubit, alpha, beta);
332 }

References getComplexPairFromRotation(), and statevec_controlledCompactUnitary().

Referenced by controlledRotateAroundAxis(), statevec_controlledRotateX(), statevec_controlledRotateY(), and statevec_controlledRotateZ().

◆ statevec_controlledRotateAroundAxisConj()

void statevec_controlledRotateAroundAxisConj ( Qureg  qureg,
int  controlQubit,
int  targetQubit,
qreal  angle,
Vector  axis 
)

Definition at line 334 of file QuEST_common.c.

334  {
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 }

References getComplexPairFromRotation(), Complex::imag, and statevec_controlledCompactUnitary().

Referenced by controlledRotateAroundAxis().

◆ statevec_controlledRotateX()

void statevec_controlledRotateX ( Qureg  qureg,
int  controlQubit,
int  targetQubit,
qreal  angle 
)

Definition at line 343 of file QuEST_common.c.

343  {
344 
345  Vector unitAxis = {1, 0, 0};
346  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
347 }

References statevec_controlledRotateAroundAxis().

Referenced by controlledRotateX().

◆ statevec_controlledRotateY()

void statevec_controlledRotateY ( Qureg  qureg,
int  controlQubit,
int  targetQubit,
qreal  angle 
)

Definition at line 349 of file QuEST_common.c.

349  {
350 
351  Vector unitAxis = {0, 1, 0};
352  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
353 }

References statevec_controlledRotateAroundAxis().

Referenced by controlledRotateY().

◆ statevec_controlledRotateZ()

void statevec_controlledRotateZ ( Qureg  qureg,
int  controlQubit,
int  targetQubit,
qreal  angle 
)

Definition at line 355 of file QuEST_common.c.

355  {
356 
357  Vector unitAxis = {0, 0, 1};
358  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
359 }

References statevec_controlledRotateAroundAxis().

Referenced by controlledRotateZ().

◆ statevec_controlledTwoQubitUnitary()

void statevec_controlledTwoQubitUnitary ( Qureg  qureg,
int  controlQubit,
int  targetQubit1,
int  targetQubit2,
ComplexMatrix4  u 
)

Definition at line 523 of file QuEST_common.c.

523  {
524 
525  long long int ctrlMask = 1LL << controlQubit;
526  statevec_multiControlledTwoQubitUnitary(qureg, ctrlMask, targetQubit1, targetQubit2, u);
527 }

References statevec_multiControlledTwoQubitUnitary().

Referenced by controlledTwoQubitUnitary().

◆ statevec_controlledUnitary()

void statevec_controlledUnitary ( Qureg  qureg,
int  controlQubit,
int  targetQubit,
ComplexMatrix2  u 
)

Definition at line 958 of file QuEST_cpu_distributed.c.

960 {
961  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
962  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
963  Complex rot1, rot2;
964 
965  // rank's chunk is in upper half of block
966  int rankIsUpper;
967  int pairRank; // rank of corresponding chunk
968 
969  if (useLocalDataOnly){
970  // all values required to update state vector lie in this rank
971  statevec_controlledUnitaryLocal(qureg, controlQubit, targetQubit, u);
972  } else {
973  // need to get corresponding chunk of state vector from other rank
974  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
975  getRotAngleFromUnitaryMatrix(rankIsUpper, &rot1, &rot2, u);
976  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
977  //printf("%d rank has pair rank: %d\n", qureg.rank, pairRank);
978  // get corresponding values from my pair
979  exchangeStateVectors(qureg, pairRank);
980 
981  // this rank's values are either in the upper of lower half of the block. send values to controlledUnitaryDistributed
982  // in the correct order
983  if (rankIsUpper){
984  statevec_controlledUnitaryDistributed(qureg,controlQubit,rot1,rot2,
985  qureg.stateVec, //upper
986  qureg.pairStateVec, //lower
987  qureg.stateVec); //output
988  } else {
989  statevec_controlledUnitaryDistributed(qureg,controlQubit,rot1,rot2,
990  qureg.pairStateVec, //upper
991  qureg.stateVec, //lower
992  qureg.stateVec); //output
993  }
994  }
995 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), getRotAngleFromUnitaryMatrix(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_controlledUnitaryDistributed(), and statevec_controlledUnitaryLocal().

Referenced by controlledUnitary().

◆ statevec_createQureg()

void statevec_createQureg ( Qureg qureg,
int  numQubits,
QuESTEnv  env 
)

Definition at line 1279 of file QuEST_cpu.c.

1280 {
1281  long long int numAmps = 1LL << numQubits;
1282  long long int numAmpsPerRank = numAmps/env.numRanks;
1283 
1284  if (numAmpsPerRank > SIZE_MAX) {
1285  printf("Could not allocate memory (cannot fit numAmps into size_t)!");
1286  exit (EXIT_FAILURE);
1287  }
1288 
1289  size_t arrSize = (size_t) (numAmpsPerRank * sizeof(*(qureg->stateVec.real)));
1290  qureg->stateVec.real = malloc(arrSize);
1291  qureg->stateVec.imag = malloc(arrSize);
1292  if (env.numRanks>1){
1293  qureg->pairStateVec.real = malloc(arrSize);
1294  qureg->pairStateVec.imag = malloc(arrSize);
1295  }
1296 
1297  if ( (!(qureg->stateVec.real) || !(qureg->stateVec.imag))
1298  && numAmpsPerRank ) {
1299  printf("Could not allocate memory!");
1300  exit (EXIT_FAILURE);
1301  }
1302 
1303  if ( env.numRanks>1 && (!(qureg->pairStateVec.real) || !(qureg->pairStateVec.imag))
1304  && numAmpsPerRank ) {
1305  printf("Could not allocate memory!");
1306  exit (EXIT_FAILURE);
1307  }
1308 
1309  qureg->numQubitsInStateVec = numQubits;
1310  qureg->numAmpsTotal = numAmps;
1311  qureg->numAmpsPerChunk = numAmpsPerRank;
1312  qureg->chunkId = env.rank;
1313  qureg->numChunks = env.numRanks;
1314  qureg->isDensityMatrix = 0;
1315 }

References Qureg::chunkId, Qureg::deviceStateVec, Qureg::firstLevelReduction, Qureg::isDensityMatrix, Qureg::numAmpsPerChunk, Qureg::numAmpsTotal, Qureg::numChunks, Qureg::numQubitsInStateVec, QuESTEnv::numRanks, Qureg::pairStateVec, qreal, QuESTEnv::rank, REDUCE_SHARED_SIZE, Qureg::secondLevelReduction, and Qureg::stateVec.

Referenced by createCloneQureg(), createDensityQureg(), and createQureg().

◆ statevec_destroyQureg()

void statevec_destroyQureg ( Qureg  qureg,
QuESTEnv  env 
)

Definition at line 1317 of file QuEST_cpu.c.

1317  {
1318 
1319  qureg.numQubitsInStateVec = 0;
1320  qureg.numAmpsTotal = 0;
1321  qureg.numAmpsPerChunk = 0;
1322 
1323  free(qureg.stateVec.real);
1324  free(qureg.stateVec.imag);
1325  if (env.numRanks>1){
1326  free(qureg.pairStateVec.real);
1327  free(qureg.pairStateVec.imag);
1328  }
1329  qureg.stateVec.real = NULL;
1330  qureg.stateVec.imag = NULL;
1331  qureg.pairStateVec.real = NULL;
1332  qureg.pairStateVec.imag = NULL;
1333 }

References Qureg::deviceStateVec, Qureg::firstLevelReduction, Qureg::numAmpsPerChunk, Qureg::numAmpsTotal, Qureg::numQubitsInStateVec, QuESTEnv::numRanks, Qureg::pairStateVec, Qureg::secondLevelReduction, and Qureg::stateVec.

Referenced by destroyQureg().

◆ statevec_getImagAmp()

qreal statevec_getImagAmp ( Qureg  qureg,
long long int  index 
)

Definition at line 208 of file QuEST_cpu_distributed.c.

208  {
209  int chunkId = getChunkIdFromIndex(qureg, index);
210  qreal el;
211  if (qureg.chunkId==chunkId){
212  el = qureg.stateVec.imag[index-chunkId*qureg.numAmpsPerChunk];
213  }
214  MPI_Bcast(&el, 1, MPI_QuEST_REAL, chunkId, MPI_COMM_WORLD);
215  return el;
216 }

References Qureg::chunkId, Qureg::deviceStateVec, getChunkIdFromIndex(), Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by getAmp(), getDensityAmp(), getImagAmp(), and statevec_getProbAmp().

◆ statevec_getProbAmp()

qreal statevec_getProbAmp ( Qureg  qureg,
long long int  index 
)

Definition at line 245 of file QuEST_common.c.

245  {
246  qreal real = statevec_getRealAmp(qureg, index);
247  qreal imag = statevec_getImagAmp(qureg, index);
248  return real*real + imag*imag;
249 }

References qreal, statevec_getImagAmp(), and statevec_getRealAmp().

Referenced by getProbAmp().

◆ statevec_getRealAmp()

qreal statevec_getRealAmp ( Qureg  qureg,
long long int  index 
)

Definition at line 198 of file QuEST_cpu_distributed.c.

198  {
199  int chunkId = getChunkIdFromIndex(qureg, index);
200  qreal el;
201  if (qureg.chunkId==chunkId){
202  el = qureg.stateVec.real[index-chunkId*qureg.numAmpsPerChunk];
203  }
204  MPI_Bcast(&el, 1, MPI_QuEST_REAL, chunkId, MPI_COMM_WORLD);
205  return el;
206 }

References Qureg::chunkId, Qureg::deviceStateVec, getChunkIdFromIndex(), Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by getAmp(), getDensityAmp(), getRealAmp(), and statevec_getProbAmp().

◆ statevec_hadamard()

void statevec_hadamard ( Qureg  qureg,
int  targetQubit 
)

Definition at line 1206 of file QuEST_cpu_distributed.c.

1207 {
1208  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1209  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1210 
1211  // rank's chunk is in upper half of block
1212  int rankIsUpper;
1213  int pairRank; // rank of corresponding chunk
1214 
1215  if (useLocalDataOnly){
1216  // all values required to update state vector lie in this rank
1217  statevec_hadamardLocal(qureg, targetQubit);
1218  } else {
1219  // need to get corresponding chunk of state vector from other rank
1220  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1221  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1222  //printf("%d rank has pair rank: %d\n", qureg.rank, pairRank);
1223  // get corresponding values from my pair
1224  exchangeStateVectors(qureg, pairRank);
1225  // this rank's values are either in the upper of lower half of the block. send values to hadamardDistributed
1226  // in the correct order
1227  if (rankIsUpper){
1229  qureg.stateVec, //upper
1230  qureg.pairStateVec, //lower
1231  qureg.stateVec, rankIsUpper); //output
1232  } else {
1234  qureg.pairStateVec, //upper
1235  qureg.stateVec, //lower
1236  qureg.stateVec, rankIsUpper); //output
1237  }
1238  }
1239 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_hadamardDistributed(), and statevec_hadamardLocal().

Referenced by hadamard().

◆ statevec_initBlankState()

void statevec_initBlankState ( Qureg  qureg)

Definition at line 1398 of file QuEST_cpu.c.

1399 {
1400  long long int stateVecSize;
1401  long long int index;
1402 
1403  // dimension of the state vector
1404  stateVecSize = qureg.numAmpsPerChunk;
1405 
1406  // Can't use qureg->stateVec as a private OMP var
1407  qreal *stateVecReal = qureg.stateVec.real;
1408  qreal *stateVecImag = qureg.stateVec.imag;
1409 
1410  // initialise the state-vector to all-zeroes
1411 # ifdef _OPENMP
1412 # pragma omp parallel \
1413  default (none) \
1414  shared (stateVecSize, stateVecReal, stateVecImag) \
1415  private (index)
1416 # endif
1417  {
1418 # ifdef _OPENMP
1419 # pragma omp for schedule (static)
1420 # endif
1421  for (index=0; index<stateVecSize; index++) {
1422  stateVecReal[index] = 0.0;
1423  stateVecImag[index] = 0.0;
1424  }
1425  }
1426 }

References Qureg::deviceStateVec, Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by initBlankState(), statevec_applyPauliSum(), and statevec_initZeroState().

◆ statevec_initClassicalState()

void statevec_initClassicalState ( Qureg  qureg,
long long int  stateInd 
)

Definition at line 1470 of file QuEST_cpu.c.

1471 {
1472  long long int stateVecSize;
1473  long long int index;
1474 
1475  // dimension of the state vector
1476  stateVecSize = qureg.numAmpsPerChunk;
1477 
1478  // Can't use qureg->stateVec as a private OMP var
1479  qreal *stateVecReal = qureg.stateVec.real;
1480  qreal *stateVecImag = qureg.stateVec.imag;
1481 
1482  // initialise the state to vector to all zeros
1483 # ifdef _OPENMP
1484 # pragma omp parallel \
1485  default (none) \
1486  shared (stateVecSize, stateVecReal, stateVecImag) \
1487  private (index)
1488 # endif
1489  {
1490 # ifdef _OPENMP
1491 # pragma omp for schedule (static)
1492 # endif
1493  for (index=0; index<stateVecSize; index++) {
1494  stateVecReal[index] = 0.0;
1495  stateVecImag[index] = 0.0;
1496  }
1497  }
1498 
1499  // give the specified classical state prob 1
1500  if (qureg.chunkId == stateInd/stateVecSize){
1501  stateVecReal[stateInd % stateVecSize] = 1.0;
1502  stateVecImag[stateInd % stateVecSize] = 0.0;
1503  }
1504 }

References Qureg::chunkId, Qureg::deviceStateVec, Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by initClassicalState().

◆ statevec_initDebugState()

void statevec_initDebugState ( Qureg  qureg)

Initialise the state vector of probability amplitudes to an (unphysical) state with each component of each probability amplitude a unique floating point value.

For debugging processes

Parameters
[in,out]quregobject representing the set of qubits to be initialised

Definition at line 1591 of file QuEST_cpu.c.

1592 {
1593  long long int chunkSize;
1594  long long int index;
1595  long long int indexOffset;
1596 
1597  // dimension of the state vector
1598  chunkSize = qureg.numAmpsPerChunk;
1599 
1600  // Can't use qureg->stateVec as a private OMP var
1601  qreal *stateVecReal = qureg.stateVec.real;
1602  qreal *stateVecImag = qureg.stateVec.imag;
1603 
1604  indexOffset = chunkSize * qureg.chunkId;
1605 
1606  // initialise the state to |0000..0000>
1607 # ifdef _OPENMP
1608 # pragma omp parallel \
1609  default (none) \
1610  shared (chunkSize, stateVecReal, stateVecImag, indexOffset) \
1611  private (index)
1612 # endif
1613  {
1614 # ifdef _OPENMP
1615 # pragma omp for schedule (static)
1616 # endif
1617  for (index=0; index<chunkSize; index++) {
1618  stateVecReal[index] = ((indexOffset + index)*2.0)/10.0;
1619  stateVecImag[index] = ((indexOffset + index)*2.0+1.0)/10.0;
1620  }
1621  }
1622 }

References Qureg::chunkId, Qureg::deviceStateVec, Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by initDebugState().

◆ statevec_initPlusState()

void statevec_initPlusState ( Qureg  qureg)

Definition at line 1438 of file QuEST_cpu.c.

1439 {
1440  long long int chunkSize, stateVecSize;
1441  long long int index;
1442 
1443  // dimension of the state vector
1444  chunkSize = qureg.numAmpsPerChunk;
1445  stateVecSize = chunkSize*qureg.numChunks;
1446  qreal normFactor = 1.0/sqrt((qreal)stateVecSize);
1447 
1448  // Can't use qureg->stateVec as a private OMP var
1449  qreal *stateVecReal = qureg.stateVec.real;
1450  qreal *stateVecImag = qureg.stateVec.imag;
1451 
1452  // initialise the state to |+++..+++> = 1/normFactor {1, 1, 1, ...}
1453 # ifdef _OPENMP
1454 # pragma omp parallel \
1455  default (none) \
1456  shared (chunkSize, stateVecReal, stateVecImag, normFactor) \
1457  private (index)
1458 # endif
1459  {
1460 # ifdef _OPENMP
1461 # pragma omp for schedule (static)
1462 # endif
1463  for (index=0; index<chunkSize; index++) {
1464  stateVecReal[index] = normFactor;
1465  stateVecImag[index] = 0.0;
1466  }
1467  }
1468 }

References Qureg::deviceStateVec, Qureg::numAmpsPerChunk, Qureg::numChunks, qreal, and Qureg::stateVec.

Referenced by initPlusState().

◆ statevec_initStateFromSingleFile()

int statevec_initStateFromSingleFile ( Qureg qureg,
char  filename[200],
QuESTEnv  env 
)

Definition at line 1625 of file QuEST_cpu.c.

1625  {
1626  long long int chunkSize, stateVecSize;
1627  long long int indexInChunk, totalIndex;
1628 
1629  chunkSize = qureg->numAmpsPerChunk;
1630  stateVecSize = chunkSize*qureg->numChunks;
1631 
1632  qreal *stateVecReal = qureg->stateVec.real;
1633  qreal *stateVecImag = qureg->stateVec.imag;
1634 
1635  FILE *fp;
1636  char line[200];
1637 
1638  for (int rank=0; rank<(qureg->numChunks); rank++){
1639  if (rank==qureg->chunkId){
1640  fp = fopen(filename, "r");
1641 
1642  // indicate file open failure
1643  if (fp == NULL)
1644  return 0;
1645 
1646  indexInChunk = 0; totalIndex = 0;
1647  while (fgets(line, sizeof(char)*200, fp) != NULL && totalIndex<stateVecSize){
1648  if (line[0]!='#'){
1649  int chunkId = (int) (totalIndex/chunkSize);
1650  if (chunkId==qureg->chunkId){
1651  # if QuEST_PREC==1
1652  sscanf(line, "%f, %f", &(stateVecReal[indexInChunk]),
1653  &(stateVecImag[indexInChunk]));
1654  # elif QuEST_PREC==2
1655  sscanf(line, "%lf, %lf", &(stateVecReal[indexInChunk]),
1656  &(stateVecImag[indexInChunk]));
1657  # elif QuEST_PREC==4
1658  sscanf(line, "%Lf, %Lf", &(stateVecReal[indexInChunk]),
1659  &(stateVecImag[indexInChunk]));
1660  # endif
1661  indexInChunk += 1;
1662  }
1663  totalIndex += 1;
1664  }
1665  }
1666  fclose(fp);
1667  }
1668  syncQuESTEnv(env);
1669  }
1670 
1671  // indicate success
1672  return 1;
1673 }

References Qureg::chunkId, copyStateToGPU(), Qureg::numAmpsPerChunk, Qureg::numChunks, qreal, Qureg::stateVec, and syncQuESTEnv().

Referenced by initStateFromSingleFile().

◆ statevec_initStateOfSingleQubit()

void statevec_initStateOfSingleQubit ( Qureg qureg,
int  qubitId,
int  outcome 
)

Initialise the state vector of probability amplitudes such that one qubit is set to 'outcome' and all other qubits are in an equal superposition of zero and one.

Parameters
[in,out]quregobject representing the set of qubits to be initialised
[in]qubitIdid of qubit to set to state 'outcome'
[in]valueof qubit 'qubitId'

Definition at line 1545 of file QuEST_cpu.c.

1546 {
1547  long long int chunkSize, stateVecSize;
1548  long long int index;
1549  int bit;
1550  long long int chunkId=qureg->chunkId;
1551 
1552  // dimension of the state vector
1553  chunkSize = qureg->numAmpsPerChunk;
1554  stateVecSize = chunkSize*qureg->numChunks;
1555  qreal normFactor = 1.0/sqrt((qreal)stateVecSize/2.0);
1556 
1557  // Can't use qureg->stateVec as a private OMP var
1558  qreal *stateVecReal = qureg->stateVec.real;
1559  qreal *stateVecImag = qureg->stateVec.imag;
1560 
1561  // initialise the state to |0000..0000>
1562 # ifdef _OPENMP
1563 # pragma omp parallel \
1564  default (none) \
1565  shared (chunkSize, stateVecReal, stateVecImag, normFactor, qubitId, outcome, chunkId) \
1566  private (index, bit)
1567 # endif
1568  {
1569 # ifdef _OPENMP
1570 # pragma omp for schedule (static)
1571 # endif
1572  for (index=0; index<chunkSize; index++) {
1573  bit = extractBit(qubitId, index+chunkId*chunkSize);
1574  if (bit==outcome) {
1575  stateVecReal[index] = normFactor;
1576  stateVecImag[index] = 0.0;
1577  } else {
1578  stateVecReal[index] = 0.0;
1579  stateVecImag[index] = 0.0;
1580  }
1581  }
1582  }
1583 }

References Qureg::chunkId, Qureg::deviceStateVec, extractBit(), Qureg::numAmpsPerChunk, Qureg::numChunks, qreal, and Qureg::stateVec.

Referenced by initStateOfSingleQubit().

◆ statevec_initZeroState()

void statevec_initZeroState ( Qureg  qureg)

Definition at line 1428 of file QuEST_cpu.c.

1429 {
1430  statevec_initBlankState(qureg);
1431  if (qureg.chunkId==0){
1432  // zero state |0000..0000> has probability 1
1433  qureg.stateVec.real[0] = 1.0;
1434  qureg.stateVec.imag[0] = 0.0;
1435  }
1436 }

References Qureg::chunkId, Qureg::deviceStateVec, Qureg::numAmpsPerChunk, qreal, Qureg::stateVec, and statevec_initBlankState().

Referenced by initZeroState().

◆ statevec_measureWithStats()

int statevec_measureWithStats ( Qureg  qureg,
int  measureQubit,
qreal outcomeProb 
)

Definition at line 361 of file QuEST_common.c.

361  {
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 }

References generateMeasurementOutcome(), qreal, statevec_calcProbOfOutcome(), and statevec_collapseToKnownProbOutcome().

Referenced by measure(), and measureWithStats().

◆ statevec_multiControlledMultiQubitUnitary()

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 already fit in the node, it operates the unitary direct.

It is already gauranteed here that all target qubits can fit on each node (this is validated in the front-end)

@TODO: refactor so that the 'swap back' isn't performed; instead the qubit locations are updated.

Definition at line 1437 of file QuEST_cpu_distributed.c.

1437  {
1438 
1439  // bit mask of target qubits (for quick collision checking)
1440  long long int targMask = getQubitBitMask(targs, numTargs);
1441 
1442  // find lowest qubit available for swapping (isn't in targs)
1443  int freeQb=0;
1444  while (maskContainsBit(targMask, freeQb))
1445  freeQb++;
1446 
1447  // assign indices of where each target will be swapped to (else itself)
1448  int swapTargs[numTargs];
1449  for (int t=0; t<numTargs; t++) {
1450  if (halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targs[t]))
1451  swapTargs[t] = targs[t];
1452  else {
1453  // mark swap
1454  swapTargs[t] = freeQb;
1455 
1456  // update ctrlMask if swapped-out qubit was a control
1457  if (maskContainsBit(ctrlMask, swapTargs[t]))
1458  ctrlMask = flipBit(flipBit(ctrlMask, swapTargs[t]), targs[t]); // swap targ and ctrl
1459 
1460  // locate next available on-chunk qubit
1461  freeQb++;
1462  while (maskContainsBit(targMask, freeQb))
1463  freeQb++;
1464  }
1465  }
1466 
1467  // perform swaps as necessary
1468  for (int t=0; t<numTargs; t++)
1469  if (swapTargs[t] != targs[t])
1470  statevec_swapQubitAmps(qureg, targs[t], swapTargs[t]);
1471 
1472  // all target qubits have now been swapped into local memory
1473  statevec_multiControlledMultiQubitUnitaryLocal(qureg, ctrlMask, swapTargs, numTargs, u);
1474 
1475  // undo swaps
1476  for (int t=0; t<numTargs; t++)
1477  if (swapTargs[t] != targs[t])
1478  statevec_swapQubitAmps(qureg, targs[t], swapTargs[t]);
1479 }

References flipBit(), getQubitBitMask(), halfMatrixBlockFitsInChunk(), ComplexMatrixN::imag, maskContainsBit(), Qureg::numAmpsPerChunk, ComplexMatrixN::numQubits, qreal, ComplexMatrixN::real, statevec_multiControlledMultiQubitUnitaryLocal(), and statevec_swapQubitAmps().

Referenced by applyMultiControlledMatrixN(), densmatr_applyMultiQubitKrausSuperoperator(), densmatr_applyTwoQubitKrausSuperoperator(), multiControlledMultiQubitUnitary(), statevec_controlledMultiQubitUnitary(), and statevec_multiQubitUnitary().

◆ statevec_multiControlledPhaseFlip()

void statevec_multiControlledPhaseFlip ( Qureg  qureg,
int *  controlQubits,
int  numControlQubits 
)

Definition at line 3331 of file QuEST_cpu.c.

3332 {
3333  long long int index;
3334  long long int stateVecSize;
3335 
3336  long long int chunkSize=qureg.numAmpsPerChunk;
3337  long long int chunkId=qureg.chunkId;
3338 
3339  long long int mask = getQubitBitMask(controlQubits, numControlQubits);
3340 
3341  stateVecSize = qureg.numAmpsPerChunk;
3342  qreal *stateVecReal = qureg.stateVec.real;
3343  qreal *stateVecImag = qureg.stateVec.imag;
3344 
3345 # ifdef _OPENMP
3346 # pragma omp parallel \
3347  default (none) \
3348  shared (stateVecSize, stateVecReal,stateVecImag, mask, chunkId,chunkSize ) \
3349  private (index)
3350 # endif
3351  {
3352 # ifdef _OPENMP
3353 # pragma omp for schedule (static)
3354 # endif
3355  for (index=0; index<stateVecSize; index++) {
3356  if (mask == (mask & (index+chunkId*chunkSize)) ){
3357  stateVecReal [index] = - stateVecReal [index];
3358  stateVecImag [index] = - stateVecImag [index];
3359  }
3360  }
3361  }
3362 }

References Qureg::chunkId, getQubitBitMask(), Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by multiControlledPhaseFlip().

◆ statevec_multiControlledPhaseShift()

void statevec_multiControlledPhaseShift ( Qureg  qureg,
int *  controlQubits,
int  numControlQubits,
qreal  angle 
)

Definition at line 3059 of file QuEST_cpu.c.

3060 {
3061  long long int index;
3062  long long int stateVecSize;
3063 
3064  long long int chunkSize=qureg.numAmpsPerChunk;
3065  long long int chunkId=qureg.chunkId;
3066 
3067  long long int mask = getQubitBitMask(controlQubits, numControlQubits);
3068 
3069  stateVecSize = qureg.numAmpsPerChunk;
3070  qreal *stateVecReal = qureg.stateVec.real;
3071  qreal *stateVecImag = qureg.stateVec.imag;
3072 
3073  qreal stateRealLo, stateImagLo;
3074  qreal cosAngle = cos(angle);
3075  qreal sinAngle = sin(angle);
3076 
3077 # ifdef _OPENMP
3078 # pragma omp parallel \
3079  default (none) \
3080  shared (stateVecSize, stateVecReal, stateVecImag, mask, chunkId,chunkSize,cosAngle,sinAngle) \
3081  private (index, stateRealLo, stateImagLo)
3082 # endif
3083  {
3084 # ifdef _OPENMP
3085 # pragma omp for schedule (static)
3086 # endif
3087  for (index=0; index<stateVecSize; index++) {
3088  if (mask == (mask & (index+chunkId*chunkSize)) ){
3089 
3090  stateRealLo = stateVecReal[index];
3091  stateImagLo = stateVecImag[index];
3092 
3093  stateVecReal[index] = cosAngle*stateRealLo - sinAngle*stateImagLo;
3094  stateVecImag[index] = sinAngle*stateRealLo + cosAngle*stateImagLo;
3095  }
3096  }
3097  }
3098 }

References Qureg::chunkId, getQubitBitMask(), Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by multiControlledPhaseShift().

◆ statevec_multiControlledTwoQubitUnitary()

void statevec_multiControlledTwoQubitUnitary ( Qureg  qureg,
long long int  ctrlMask,
int  q1,
int  q2,
ComplexMatrix4  u 
)

This calls swapQubitAmps only when it would involve a distributed communication; if the qubit chunks already fit in the node, it operates the unitary direct.

Note the order of q1 and q2 in the call to twoQubitUnitaryLocal is important.

@TODO: refactor so that the 'swap back' isn't performed; instead the qubit locations are updated. @TODO: the double swap (q1,q2 to 0,1) may be possible simultaneously by a bespoke swap routine.

Definition at line 1381 of file QuEST_cpu_distributed.c.

1381  {
1382  int q1FitsInNode = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, q1);
1383  int q2FitsInNode = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, q2);
1384 
1385  if (q1FitsInNode && q2FitsInNode) {
1386  statevec_multiControlledTwoQubitUnitaryLocal(qureg, ctrlMask, q1, q2, u);
1387 
1388  } else if (q1FitsInNode) {
1389  int qSwap = (q1 > 0)? q1-1 : q1+1;
1390 
1391  // ensure ctrl == qSwap, ensure ctrlMask updates under the swap
1392  if (maskContainsBit(ctrlMask, qSwap))
1393  ctrlMask = flipBit(flipBit(ctrlMask, q2), qSwap);
1394 
1395  statevec_swapQubitAmps(qureg, q2, qSwap);
1396  statevec_multiControlledTwoQubitUnitaryLocal(qureg, ctrlMask, q1, qSwap, u);
1397  statevec_swapQubitAmps(qureg, q2, qSwap);
1398 
1399  } else if (q2FitsInNode) {
1400  int qSwap = (q2 > 0)? q2-1 : q2+1;
1401 
1402  // ensure ctrl == qSwap, ensure ctrlMask updates under the swap
1403  if (maskContainsBit(ctrlMask, qSwap))
1404  ctrlMask = flipBit(flipBit(ctrlMask, q1), qSwap);
1405 
1406  statevec_swapQubitAmps(qureg, q1, qSwap);
1407  statevec_multiControlledTwoQubitUnitaryLocal(qureg, ctrlMask, qSwap, q2, u);
1408  statevec_swapQubitAmps(qureg, q1, qSwap);
1409 
1410  } else {
1411  // we know with certainty that both q1 and q2 >= 2
1412  int swap1 = 0;
1413  int swap2 = 1;
1414 
1415  // if ctrl == swap1 or swap2, ensure ctrlMask updates under the swap
1416  if (maskContainsBit(ctrlMask, swap1))
1417  ctrlMask = flipBit(flipBit(ctrlMask, swap1), q1);
1418  if (maskContainsBit(ctrlMask, swap2))
1419  ctrlMask = flipBit(flipBit(ctrlMask, swap2), q2);
1420 
1421  statevec_swapQubitAmps(qureg, q1, swap1);
1422  statevec_swapQubitAmps(qureg, q2, swap2);
1423  statevec_multiControlledTwoQubitUnitaryLocal(qureg, ctrlMask, swap1, swap2, u);
1424  statevec_swapQubitAmps(qureg, q1, swap1);
1425  statevec_swapQubitAmps(qureg, q2, swap2);
1426  }
1427 }

References flipBit(), halfMatrixBlockFitsInChunk(), maskContainsBit(), Qureg::numAmpsPerChunk, qreal, statevec_multiControlledTwoQubitUnitaryLocal(), and statevec_swapQubitAmps().

Referenced by densmatr_applyKrausSuperoperator(), multiControlledTwoQubitUnitary(), statevec_controlledTwoQubitUnitary(), and statevec_twoQubitUnitary().

◆ statevec_multiControlledUnitary()

void statevec_multiControlledUnitary ( Qureg  qureg,
long long int  ctrlQubitsMask,
long long int  ctrlFlipMask,
int  targetQubit,
ComplexMatrix2  u 
)

Definition at line 997 of file QuEST_cpu_distributed.c.

998 {
999  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1000  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1001  Complex rot1, rot2;
1002 
1003  // rank's chunk is in upper half of block
1004  int rankIsUpper;
1005  int pairRank; // rank of corresponding chunk
1006 
1007  if (useLocalDataOnly){
1008  // all values required to update state vector lie in this rank
1009  statevec_multiControlledUnitaryLocal(qureg, targetQubit, ctrlQubitsMask, ctrlFlipMask, u);
1010  } else {
1011  // need to get corresponding chunk of state vector from other rank
1012  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1013  getRotAngleFromUnitaryMatrix(rankIsUpper, &rot1, &rot2, u);
1014  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1015 
1016  // get corresponding values from my pair
1017  exchangeStateVectors(qureg, pairRank);
1018 
1019  // this rank's values are either in the upper of lower half of the block. send values to multiControlledUnitaryDistributed
1020  // in the correct order
1021  if (rankIsUpper){
1022  statevec_multiControlledUnitaryDistributed(qureg,targetQubit,ctrlQubitsMask,ctrlFlipMask,rot1,rot2,
1023  qureg.stateVec, //upper
1024  qureg.pairStateVec, //lower
1025  qureg.stateVec); //output
1026  } else {
1027  statevec_multiControlledUnitaryDistributed(qureg,targetQubit,ctrlQubitsMask,ctrlFlipMask,rot1,rot2,
1028  qureg.pairStateVec, //upper
1029  qureg.stateVec, //lower
1030  qureg.stateVec); //output
1031  }
1032  }
1033 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), getRotAngleFromUnitaryMatrix(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_multiControlledUnitaryDistributed(), and statevec_multiControlledUnitaryLocal().

Referenced by multiControlledUnitary(), and multiStateControlledUnitary().

◆ statevec_multiQubitUnitary()

void statevec_multiQubitUnitary ( Qureg  qureg,
int *  targets,
int  numTargets,
ComplexMatrixN  u 
)

Definition at line 529 of file QuEST_common.c.

529  {
530 
531  long long int ctrlMask = 0;
532  statevec_multiControlledMultiQubitUnitary(qureg, ctrlMask, targets, numTargets, u);
533 }

References statevec_multiControlledMultiQubitUnitary().

Referenced by applyMatrixN(), and multiQubitUnitary().

◆ statevec_multiRotatePauli()

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 at line 411 of file QuEST_common.c.

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 }

References getQubitBitMask(), Complex::imag, PAULI_I, PAULI_X, PAULI_Y, qreal, Complex::real, statevec_compactUnitary(), and statevec_multiRotateZ().

Referenced by applyExponentiatedPauliHamil(), and multiRotatePauli().

◆ statevec_multiRotateZ()

void statevec_multiRotateZ ( Qureg  qureg,
long long int  mask,
qreal  angle 
)

Definition at line 3109 of file QuEST_cpu.c.

3110 {
3111  long long int index;
3112  long long int stateVecSize;
3113 
3114  long long int chunkSize=qureg.numAmpsPerChunk;
3115  long long int chunkId=qureg.chunkId;
3116 
3117  stateVecSize = qureg.numAmpsPerChunk;
3118  qreal *stateVecReal = qureg.stateVec.real;
3119  qreal *stateVecImag = qureg.stateVec.imag;
3120 
3121  qreal stateReal, stateImag;
3122  qreal cosAngle = cos(angle/2.0);
3123  qreal sinAngle = sin(angle/2.0);
3124 
3125  // = +-1, to flip sinAngle based on target qubit parity, to effect
3126  // exp(-angle/2 i fac_j)|j>
3127  int fac;
3128 
3129 # ifdef _OPENMP
3130 # pragma omp parallel \
3131  default (none) \
3132  shared (stateVecSize, stateVecReal, stateVecImag, mask, chunkId,chunkSize,cosAngle,sinAngle) \
3133  private (index, fac, stateReal, stateImag)
3134 # endif
3135  {
3136 # ifdef _OPENMP
3137 # pragma omp for schedule (static)
3138 # endif
3139  for (index=0; index<stateVecSize; index++) {
3140  stateReal = stateVecReal[index];
3141  stateImag = stateVecImag[index];
3142 
3143  // odd-parity target qubits get fac_j = -1
3144  fac = getBitMaskParity(mask & (index+chunkId*chunkSize))? -1 : 1;
3145  stateVecReal[index] = cosAngle*stateReal + fac * sinAngle*stateImag;
3146  stateVecImag[index] = - fac * sinAngle*stateReal + cosAngle*stateImag;
3147  }
3148  }
3149 }

References Qureg::chunkId, getBitMaskParity(), Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by multiRotateZ(), and statevec_multiRotatePauli().

◆ statevec_pauliX()

void statevec_pauliX ( Qureg  qureg,
int  targetQubit 
)

Definition at line 1034 of file QuEST_cpu_distributed.c.

1035 {
1036  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1037  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1038 
1039  // rank's chunk is in upper half of block
1040  int rankIsUpper;
1041  int pairRank; // rank of corresponding chunk
1042 
1043  if (useLocalDataOnly){
1044  // all values required to update state vector lie in this rank
1045  statevec_pauliXLocal(qureg, targetQubit);
1046  } else {
1047  // need to get corresponding chunk of state vector from other rank
1048  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1049  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1050  //printf("%d rank has pair rank: %d\n", qureg.rank, pairRank);
1051  // get corresponding values from my pair
1052  exchangeStateVectors(qureg, pairRank);
1053  // this rank's values are either in the upper of lower half of the block. pauliX just replaces
1054  // this rank's values with pair values
1056  qureg.pairStateVec, // in
1057  qureg.stateVec); // out
1058  }
1059 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_pauliXDistributed(), and statevec_pauliXLocal().

Referenced by pauliX(), and statevec_applyPauliProd().

◆ statevec_pauliY()

void statevec_pauliY ( Qureg  qureg,
int  targetQubit 
)

Definition at line 1090 of file QuEST_cpu_distributed.c.

1091 {
1092  int conjFac = 1;
1093 
1094  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1095  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1096  int rankIsUpper; // rank's chunk is in upper half of block
1097  int pairRank; // rank of corresponding chunk
1098 
1099  if (useLocalDataOnly){
1100  statevec_pauliYLocal(qureg, targetQubit, conjFac);
1101  } else {
1102  // need to get corresponding chunk of state vector from other rank
1103  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1104  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1105  // get corresponding values from my pair
1106  exchangeStateVectors(qureg, pairRank);
1107  // this rank's values are either in the upper of lower half of the block
1109  qureg.pairStateVec, // in
1110  qureg.stateVec, // out
1111  rankIsUpper, conjFac);
1112  }
1113 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_pauliYDistributed(), and statevec_pauliYLocal().

Referenced by pauliY(), and statevec_applyPauliProd().

◆ statevec_pauliYConj()

void statevec_pauliYConj ( Qureg  qureg,
int  targetQubit 
)

Definition at line 1115 of file QuEST_cpu_distributed.c.

1116 {
1117  int conjFac = -1;
1118 
1119  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1120  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1121  int rankIsUpper; // rank's chunk is in upper half of block
1122  int pairRank; // rank of corresponding chunk
1123 
1124  if (useLocalDataOnly){
1125  statevec_pauliYLocal(qureg, targetQubit, conjFac);
1126  } else {
1127  // need to get corresponding chunk of state vector from other rank
1128  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1129  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1130  // get corresponding values from my pair
1131  exchangeStateVectors(qureg, pairRank);
1132  // this rank's values are either in the upper of lower half of the block
1134  qureg.pairStateVec, // in
1135  qureg.stateVec, // out
1136  rankIsUpper, conjFac);
1137  }
1138 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_pauliYDistributed(), and statevec_pauliYLocal().

Referenced by pauliY().

◆ statevec_pauliZ()

void statevec_pauliZ ( Qureg  qureg,
int  targetQubit 
)

Definition at line 258 of file QuEST_common.c.

258  {
259  Complex term;
260  term.real = -1;
261  term.imag = 0;
262  statevec_phaseShiftByTerm(qureg, targetQubit, term);
263 }

References Complex::imag, Complex::real, and statevec_phaseShiftByTerm().

Referenced by pauliZ(), and statevec_applyPauliProd().

◆ statevec_phaseShift()

void statevec_phaseShift ( Qureg  qureg,
int  targetQubit,
qreal  angle 
)

Definition at line 251 of file QuEST_common.c.

251  {
252  Complex term;
253  term.real = cos(angle);
254  term.imag = sin(angle);
255  statevec_phaseShiftByTerm(qureg, targetQubit, term);
256 }

References Complex::imag, Complex::real, and statevec_phaseShiftByTerm().

Referenced by phaseShift().

◆ statevec_phaseShiftByTerm()

void statevec_phaseShiftByTerm ( Qureg  qureg,
int  targetQubit,
Complex  term 
)

Definition at line 2978 of file QuEST_cpu.c.

2979 {
2980  long long int index;
2981  long long int stateVecSize;
2982  int targetBit;
2983 
2984  long long int chunkSize=qureg.numAmpsPerChunk;
2985  long long int chunkId=qureg.chunkId;
2986 
2987  // dimension of the state vector
2988  stateVecSize = qureg.numAmpsPerChunk;
2989  qreal *stateVecReal = qureg.stateVec.real;
2990  qreal *stateVecImag = qureg.stateVec.imag;
2991 
2992  qreal stateRealLo, stateImagLo;
2993  qreal cosAngle = term.real;
2994  qreal sinAngle = term.imag;
2995 
2996 # ifdef _OPENMP
2997 # pragma omp parallel for \
2998  default (none) \
2999  shared (stateVecSize, stateVecReal,stateVecImag, cosAngle,sinAngle, \
3000  chunkId,chunkSize,targetQubit) \
3001  private (index,targetBit,stateRealLo,stateImagLo) \
3002  schedule (static)
3003 # endif
3004  for (index=0; index<stateVecSize; index++) {
3005 
3006  // update the coeff of the |1> state of the target qubit
3007  targetBit = extractBit (targetQubit, index+chunkId*chunkSize);
3008  if (targetBit) {
3009 
3010  stateRealLo = stateVecReal[index];
3011  stateImagLo = stateVecImag[index];
3012 
3013  stateVecReal[index] = cosAngle*stateRealLo - sinAngle*stateImagLo;
3014  stateVecImag[index] = sinAngle*stateRealLo + cosAngle*stateImagLo;
3015  }
3016  }
3017 }

References Qureg::chunkId, extractBit(), Complex::imag, Qureg::numAmpsPerChunk, qreal, Complex::real, and Qureg::stateVec.

Referenced by statevec_pauliZ(), statevec_phaseShift(), statevec_sGate(), statevec_sGateConj(), statevec_tGate(), and statevec_tGateConj().

◆ statevec_reportStateToScreen()

void statevec_reportStateToScreen ( Qureg  qureg,
QuESTEnv  env,
int  reportRank 
)

Print the current state vector of probability amplitudes for a set of qubits to standard out.

For debugging purposes. Each rank should print output serially. Only print output for systems <= 5 qubits

Definition at line 1366 of file QuEST_cpu.c.

1366  {
1367  long long int index;
1368  int rank;
1369  if (qureg.numQubitsInStateVec<=5){
1370  for (rank=0; rank<qureg.numChunks; rank++){
1371  if (qureg.chunkId==rank){
1372  if (reportRank) {
1373  printf("Reporting state from rank %d [\n", qureg.chunkId);
1374  printf("real, imag\n");
1375  } else if (rank==0) {
1376  printf("Reporting state [\n");
1377  printf("real, imag\n");
1378  }
1379 
1380  for(index=0; index<qureg.numAmpsPerChunk; index++){
1381  //printf(REAL_STRING_FORMAT ", " REAL_STRING_FORMAT "\n", qureg.pairStateVec.real[index], qureg.pairStateVec.imag[index]);
1382  printf(REAL_STRING_FORMAT ", " REAL_STRING_FORMAT "\n", qureg.stateVec.real[index], qureg.stateVec.imag[index]);
1383  }
1384  if (reportRank || rank==qureg.numChunks-1) printf("]\n");
1385  }
1386  syncQuESTEnv(env);
1387  }
1388  } else printf("Error: reportStateToScreen will not print output for systems of more than 5 qubits.\n");
1389 }

References Qureg::chunkId, copyStateFromGPU(), Qureg::numAmpsPerChunk, Qureg::numChunks, Qureg::numQubitsInStateVec, Qureg::stateVec, and syncQuESTEnv().

Referenced by reportStateToScreen().

◆ statevec_rotateAroundAxis()

void statevec_rotateAroundAxis ( Qureg  qureg,
int  rotQubit,
qreal  angle,
Vector  axis 
)

Definition at line 311 of file QuEST_common.c.

311  {
312 
313  Complex alpha, beta;
314  getComplexPairFromRotation(angle, axis, &alpha, &beta);
315  statevec_compactUnitary(qureg, rotQubit, alpha, beta);
316 }

References getComplexPairFromRotation(), and statevec_compactUnitary().

Referenced by rotateAroundAxis(), statevec_rotateX(), statevec_rotateY(), and statevec_rotateZ().

◆ statevec_rotateAroundAxisConj()

void statevec_rotateAroundAxisConj ( Qureg  qureg,
int  rotQubit,
qreal  angle,
Vector  axis 
)

Definition at line 318 of file QuEST_common.c.

318  {
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 }

References getComplexPairFromRotation(), Complex::imag, and statevec_compactUnitary().

Referenced by rotateAroundAxis().

◆ statevec_rotateX()

void statevec_rotateX ( Qureg  qureg,
int  rotQubit,
qreal  angle 
)

Definition at line 293 of file QuEST_common.c.

293  {
294 
295  Vector unitAxis = {1, 0, 0};
296  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
297 }

References statevec_rotateAroundAxis().

Referenced by rotateX().

◆ statevec_rotateY()

void statevec_rotateY ( Qureg  qureg,
int  rotQubit,
qreal  angle 
)

Definition at line 299 of file QuEST_common.c.

299  {
300 
301  Vector unitAxis = {0, 1, 0};
302  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
303 }

References statevec_rotateAroundAxis().

Referenced by rotateY().

◆ statevec_rotateZ()

void statevec_rotateZ ( Qureg  qureg,
int  rotQubit,
qreal  angle 
)

Definition at line 305 of file QuEST_common.c.

305  {
306 
307  Vector unitAxis = {0, 0, 1};
308  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
309 }

References statevec_rotateAroundAxis().

Referenced by rotateZ().

◆ statevec_setAmps()

void statevec_setAmps ( Qureg  qureg,
long long int  startInd,
qreal reals,
qreal imags,
long long int  numAmps 
)

Definition at line 1237 of file QuEST_cpu.c.

1237  {
1238 
1239  /* this is actually distributed, since the user's code runs on every node */
1240 
1241  // local start/end indices of the given amplitudes, assuming they fit in this chunk
1242  // these may be negative or above qureg.numAmpsPerChunk
1243  long long int localStartInd = startInd - qureg.chunkId*qureg.numAmpsPerChunk;
1244  long long int localEndInd = localStartInd + numAmps; // exclusive
1245 
1246  // add this to a local index to get corresponding elem in reals & imags
1247  long long int offset = qureg.chunkId*qureg.numAmpsPerChunk - startInd;
1248 
1249  // restrict these indices to fit into this chunk
1250  if (localStartInd < 0)
1251  localStartInd = 0;
1252  if (localEndInd > qureg.numAmpsPerChunk)
1253  localEndInd = qureg.numAmpsPerChunk;
1254  // they may now be out of order = no iterations
1255 
1256  // unpacking OpenMP vars
1257  long long int index;
1258  qreal* vecRe = qureg.stateVec.real;
1259  qreal* vecIm = qureg.stateVec.imag;
1260 
1261 # ifdef _OPENMP
1262 # pragma omp parallel \
1263  default (none) \
1264  shared (localStartInd,localEndInd, vecRe,vecIm, reals,imags, offset) \
1265  private (index)
1266 # endif
1267  {
1268 # ifdef _OPENMP
1269 # pragma omp for schedule (static)
1270 # endif
1271  // iterate these local inds - this might involve no iterations
1272  for (index=localStartInd; index < localEndInd; index++) {
1273  vecRe[index] = reals[index + offset];
1274  vecIm[index] = imags[index + offset];
1275  }
1276  }
1277 }

References Qureg::chunkId, Qureg::deviceStateVec, Qureg::numAmpsPerChunk, qreal, and Qureg::stateVec.

Referenced by initStateFromAmps(), setAmps(), and setDensityAmps().

◆ statevec_setWeightedQureg()

void statevec_setWeightedQureg ( Complex  fac1,
Qureg  qureg1,
Complex  fac2,
Qureg  qureg2,
Complex  facOut,
Qureg  out 
)

Definition at line 3619 of file QuEST_cpu.c.

3619  {
3620 
3621  long long int numAmps = qureg1.numAmpsPerChunk;
3622 
3623  qreal *vecRe1 = qureg1.stateVec.real;
3624  qreal *vecIm1 = qureg1.stateVec.imag;
3625  qreal *vecRe2 = qureg2.stateVec.real;
3626  qreal *vecIm2 = qureg2.stateVec.imag;
3627  qreal *vecReOut = out.stateVec.real;
3628  qreal *vecImOut = out.stateVec.imag;
3629 
3630  qreal facRe1 = fac1.real;
3631  qreal facIm1 = fac1.imag;
3632  qreal facRe2 = fac2.real;
3633  qreal facIm2 = fac2.imag;
3634  qreal facReOut = facOut.real;
3635  qreal facImOut = facOut.imag;
3636 
3637  qreal re1,im1, re2,im2, reOut,imOut;
3638  long long int index;
3639 
3640 # ifdef _OPENMP
3641 # pragma omp parallel \
3642  shared (vecRe1,vecIm1, vecRe2,vecIm2, vecReOut,vecImOut, facRe1,facIm1,facRe2,facIm2, numAmps) \
3643  private (index, re1,im1, re2,im2, reOut,imOut)
3644 # endif
3645  {
3646 # ifdef _OPENMP
3647 # pragma omp for schedule (static)
3648 # endif
3649  for (index=0LL; index<numAmps; index++) {
3650  re1 = vecRe1[index]; im1 = vecIm1[index];
3651  re2 = vecRe2[index]; im2 = vecIm2[index];
3652  reOut = vecReOut[index];
3653  imOut = vecImOut[index];
3654 
3655  vecReOut[index] = (facReOut*reOut - facImOut*imOut) + (facRe1*re1 - facIm1*im1) + (facRe2*re2 - facIm2*im2);
3656  vecImOut[index] = (facReOut*imOut + facImOut*reOut) + (facRe1*im1 + facIm1*re1) + (facRe2*im2 + facIm2*re2);
3657  }
3658  }
3659 }

References Complex::imag, Qureg::numAmpsPerChunk, qreal, Complex::real, and Qureg::stateVec.

Referenced by setWeightedQureg(), and statevec_applyPauliSum().

◆ statevec_sGate()

void statevec_sGate ( Qureg  qureg,
int  targetQubit 
)

Definition at line 265 of file QuEST_common.c.

265  {
266  Complex term;
267  term.real = 0;
268  term.imag = 1;
269  statevec_phaseShiftByTerm(qureg, targetQubit, term);
270 }

References Complex::imag, Complex::real, and statevec_phaseShiftByTerm().

Referenced by sGate().

◆ statevec_sGateConj()

void statevec_sGateConj ( Qureg  qureg,
int  targetQubit 
)

Definition at line 279 of file QuEST_common.c.

279  {
280  Complex term;
281  term.real = 0;
282  term.imag = -1;
283  statevec_phaseShiftByTerm(qureg, targetQubit, term);
284 }

References Complex::imag, Complex::real, and statevec_phaseShiftByTerm().

Referenced by sGate().

◆ statevec_sqrtSwapGate()

void statevec_sqrtSwapGate ( Qureg  qureg,
int  qb1,
int  qb2 
)

Definition at line 384 of file QuEST_common.c.

384  {
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 }

References ComplexMatrix4::imag, ComplexMatrix4::real, and statevec_twoQubitUnitary().

Referenced by sqrtSwapGate().

◆ statevec_sqrtSwapGateConj()

void statevec_sqrtSwapGateConj ( Qureg  qureg,
int  qb1,
int  qb2 
)

Definition at line 397 of file QuEST_common.c.

397  {
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 }

References ComplexMatrix4::imag, ComplexMatrix4::real, and statevec_twoQubitUnitary().

Referenced by sqrtSwapGate().

◆ statevec_swapQubitAmps()

void statevec_swapQubitAmps ( Qureg  qureg,
int  qb1,
int  qb2 
)

Definition at line 1354 of file QuEST_cpu_distributed.c.

1354  {
1355 
1356  // perform locally if possible
1357  int qbBig = (qb1 > qb2)? qb1 : qb2;
1358  if (halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, qbBig))
1359  return statevec_swapQubitAmpsLocal(qureg, qb1, qb2);
1360 
1361  // do nothing if this node contains no amplitudes to swap
1362  long long int oddParityGlobalInd = getGlobalIndOfOddParityInChunk(qureg, qb1, qb2);
1363  if (oddParityGlobalInd == -1)
1364  return;
1365 
1366  // determine and swap amps with pair node
1367  int pairRank = flipBit(flipBit(oddParityGlobalInd, qb1), qb2) / qureg.numAmpsPerChunk;
1368  exchangeStateVectors(qureg, pairRank);
1369  statevec_swapQubitAmpsDistributed(qureg, pairRank, qb1, qb2);
1370 }

References exchangeStateVectors(), flipBit(), getGlobalIndOfOddParityInChunk(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, qreal, statevec_swapQubitAmpsDistributed(), and statevec_swapQubitAmpsLocal().

Referenced by statevec_multiControlledMultiQubitUnitary(), statevec_multiControlledTwoQubitUnitary(), and swapGate().

◆ statevec_tGate()

void statevec_tGate ( Qureg  qureg,
int  targetQubit 
)

Definition at line 272 of file QuEST_common.c.

272  {
273  Complex term;
274  term.real = 1/sqrt(2);
275  term.imag = 1/sqrt(2);
276  statevec_phaseShiftByTerm(qureg, targetQubit, term);
277 }

References Complex::imag, Complex::real, and statevec_phaseShiftByTerm().

Referenced by tGate().

◆ statevec_tGateConj()

void statevec_tGateConj ( Qureg  qureg,
int  targetQubit 
)

Definition at line 286 of file QuEST_common.c.

286  {
287  Complex term;
288  term.real = 1/sqrt(2);
289  term.imag = -1/sqrt(2);
290  statevec_phaseShiftByTerm(qureg, targetQubit, term);
291 }

References Complex::imag, Complex::real, and statevec_phaseShiftByTerm().

Referenced by tGate().

◆ statevec_twoQubitUnitary()

void statevec_twoQubitUnitary ( Qureg  qureg,
int  targetQubit1,
int  targetQubit2,
ComplexMatrix4  u 
)

Definition at line 517 of file QuEST_common.c.

517  {
518 
519  long long int ctrlMask = 0;
520  statevec_multiControlledTwoQubitUnitary(qureg, ctrlMask, targetQubit1, targetQubit2, u);
521 }

References statevec_multiControlledTwoQubitUnitary().

Referenced by applyMatrix4(), statevec_sqrtSwapGate(), statevec_sqrtSwapGateConj(), and twoQubitUnitary().

◆ statevec_unitary()

void statevec_unitary ( Qureg  qureg,
int  targetQubit,
ComplexMatrix2  u 
)

Definition at line 881 of file QuEST_cpu_distributed.c.

882 {
883  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
884  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
885  Complex rot1, rot2;
886 
887  // rank's chunk is in upper half of block
888  int rankIsUpper;
889  int pairRank; // rank of corresponding chunk
890 
891  if (useLocalDataOnly){
892  // all values required to update state vector lie in this rank
893  statevec_unitaryLocal(qureg, targetQubit, u);
894  } else {
895  // need to get corresponding chunk of state vector from other rank
896  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
897  getRotAngleFromUnitaryMatrix(rankIsUpper, &rot1, &rot2, u);
898  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
899  // get corresponding values from my pair
900  exchangeStateVectors(qureg, pairRank);
901 
902  // this rank's values are either in the upper of lower half of the block.
903  // send values to compactUnitaryDistributed in the correct order
904  if (rankIsUpper){
905  statevec_unitaryDistributed(qureg,rot1,rot2,
906  qureg.stateVec, //upper
907  qureg.pairStateVec, //lower
908  qureg.stateVec); //output
909  } else {
910  statevec_unitaryDistributed(qureg,rot1,rot2,
911  qureg.pairStateVec, //upper
912  qureg.stateVec, //lower
913  qureg.stateVec); //output
914  }
915  }
916 
917 
918 }

References Qureg::chunkId, chunkIsUpper(), exchangeStateVectors(), getChunkPairId(), getRotAngleFromUnitaryMatrix(), halfMatrixBlockFitsInChunk(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_unitaryDistributed(), and statevec_unitaryLocal().

Referenced by applyMatrix2(), and unitary().

Represents a 3-vector of real numbers.
Definition: QuEST.h:148
#define macro_setConjugateMatrix(dest, src, dim)
Definition: QuEST_common.c:93
qreal real[4][4]
Definition: QuEST.h:127
void syncQuESTEnv(QuESTEnv env)
Guarantees that all code up to the given point has been executed on all nodes (if running in distribu...
void densmatr_mixKrausMap(Qureg qureg, int target, ComplexMatrix2 *ops, int numOps)
Definition: QuEST_common.c:600
void statevec_controlledNotLocal(Qureg qureg, int controlQubit, int targetQubit)
Definition: QuEST_cpu.c:2584
static void getRotAngle(int chunkIsUpper, Complex *rot1, Complex *rot2, Complex alpha, Complex beta)
Get rotation values for a given chunk.
void statevec_pauliYLocal(Qureg qureg, int targetQubit, int conjFac)
Definition: QuEST_cpu.c:2682
qreal densmatr_calcHilbertSchmidtDistanceSquaredLocal(Qureg a, Qureg b)
computes Tr((a-b) conjTrans(a-b)) = sum of abs values of (a-b)
Definition: QuEST_cpu.c:923
int rank
Definition: QuEST.h:244
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
int numChunks
The number of nodes between which the elements of this operator are split.
Definition: QuEST.h:185
qreal statevec_calcExpecPauliProd(Qureg qureg, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets, Qureg workspace)
Definition: QuEST_common.c:465
static int isChunkToSkipInFindPZero(int chunkId, long long int chunkSize, int measureQubit)
Find chunks to skip when calculating probability of qubit being zero.
ComplexArray pairStateVec
Temporary storage for a chunk of the state vector received from another process in the MPI version.
Definition: QuEST.h:224
@ PAULI_I
Definition: QuEST.h:96
qreal statevec_findProbabilityOfZeroDistributed(Qureg qureg)
Measure the probability of a specified qubit being in the zero state across all amplitudes held in th...
Definition: QuEST_cpu.c:3262
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
void densmatr_mixDepolarisingDistributed(Qureg qureg, int targetQubit, qreal depolLevel)
Definition: QuEST_cpu.c:224
void densmatr_mixTwoQubitDepolarisingQ1LocalQ2DistributedPart3(Qureg qureg, int targetQubit, int qubit2, qreal delta, qreal gamma)
Definition: QuEST_cpu.c:632
void statevec_twoQubitUnitary(Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Definition: QuEST_common.c:517
qreal z
Definition: QuEST.h:150
int numChunks
Number of chunks the state vector is broken up into – the number of MPI processes used.
Definition: QuEST.h:219
void statevec_swapQubitAmpsLocal(Qureg qureg, int qb1, int qb2)
It is ensured that all amplitudes needing to be swapped are on this node.
Definition: QuEST_cpu.c:3536
void statevec_applyPauliProd(Qureg workspace, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets)
Definition: QuEST_common.c:451
int getBitMaskParity(long long int mask)
Definition: QuEST_cpu.c:3100
void statevec_multiControlledUnitaryDistributed(Qureg qureg, int targetQubit, long long int ctrlQubitsMask, long long int ctrlFlipMask, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Apply a unitary operation to a single qubit in the state vector of probability amplitudes,...
Definition: QuEST_cpu.c:2447
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 statevec_controlledUnitaryDistributed(Qureg qureg, int controlQubit, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Rotate a single qubit in the state vector of probability amplitudes, given two complex numbers alpha ...
Definition: QuEST_cpu.c:2381
qreal statevec_calcProbOfOutcome(Qureg qureg, int measureQubit, int outcome)
void statevec_collapseToKnownProbOutcomeLocal(Qureg qureg, int measureQubit, int outcome, qreal totalProbability)
Update the state vector to be consistent with measuring measureQubit=0 if outcome=0 and measureQubit=...
Definition: QuEST_cpu.c:3380
void compressPairVectorForTwoQubitDepolarise(Qureg qureg, int targetQubit, int qubit2)
int chunkId
The position of the chunk of the operator held by this process in the full operator.
Definition: QuEST.h:187
void statevec_compactUnitaryLocal(Qureg qureg, int targetQubit, Complex alpha, Complex beta)
Definition: QuEST_cpu.c:1688
qreal densmatr_calcPurityLocal(Qureg qureg)
Definition: QuEST_cpu.c:861
Complex statevec_calcExpecDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:3738
Vector getUnitVector(Vector vec)
Definition: QuEST_common.c:78
Represents a 4x4 matrix of complex numbers.
Definition: QuEST.h:125
void statevec_multiControlledMultiQubitUnitaryLocal(Qureg qureg, long long int ctrlMask, int *targs, int numTargs, ComplexMatrixN u)
Definition: QuEST_cpu.c:1846
void statevec_initBlankState(Qureg qureg)
Definition: QuEST_cpu.c:1398
void getComplexPairFromRotation(qreal angle, Vector axis, Complex *alpha, Complex *beta)
Definition: QuEST_common.c:114
void statevec_multiControlledTwoQubitUnitaryLocal(Qureg qureg, long long int ctrlMask, int q1, int q2, ComplexMatrix4 u)
Definition: QuEST_cpu.c:1747
Represents a general 2^N by 2^N matrix of complex numbers.
Definition: QuEST.h:136
void statevec_pauliXDistributed(Qureg qureg, ComplexArray stateVecIn, ComplexArray stateVecOut)
Rotate a single qubit by {{0,1},{1,0}.
Definition: QuEST_cpu.c:2556
static int getChunkOuterBlockPairId(int chunkIsUpper, int chunkId, long long int chunkSize, int targetQubit, int numQubits)
void copyVecIntoMatrixPairState(Qureg matr, Qureg vec)
This copies/clones vec (a statevector) into every node's matr pairState.
#define qreal
#define macro_allocStackComplexMatrixN(matrix, numQubits)
Definition: QuEST_common.c:629
void exchangePairStateVectorHalves(Qureg qureg, int pairRank)
@ PAULI_X
Definition: QuEST.h:96
__forceinline__ __device__ long long int flipBit(const long long int number, const int bitInd)
Definition: QuEST_gpu.cu:95
void statevec_swapQubitAmps(Qureg qureg, int qb1, int qb2)
int numQubitsInStateVec
Number of qubits in the state-vector - this is double the number represented for mixed states.
Definition: QuEST.h:210
static int getChunkPairId(int chunkIsUpper, int chunkId, long long int chunkSize, int targetQubit)
get position of corresponding chunk, holding values required to update values in my chunk (with chunk...
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
void statevec_collapseToOutcomeDistributedSetZero(Qureg qureg)
Set all amplitudes in one chunk to 0.
Definition: QuEST_cpu.c:3501
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
qreal imag[2][2]
Definition: QuEST.h:117
qreal * imag
The imaginary values of the 2^numQubits complex elements.
Definition: QuEST.h:191
qreal x
Definition: QuEST.h:150
int generateMeasurementOutcome(qreal zeroProb, qreal *outcomeProb)
Definition: QuEST_common.c:155
void compressPairVectorForSingleQubitDepolarise(Qureg qureg, int targetQubit)
long long int numAmpsPerChunk
Number of probability amplitudes held in stateVec by this process In the non-MPI version,...
Definition: QuEST.h:213
void densmatr_mixTwoQubitDepolarisingLocal(Qureg qureg, int qubit1, int qubit2, qreal delta, qreal gamma)
Definition: QuEST_cpu.c:387
static void getRotAngleFromUnitaryMatrix(int chunkIsUpper, Complex *rot1, Complex *rot2, ComplexMatrix2 u)
Get rotation values for a given chunk given a unitary matrix.
void statevec_controlledPauliYLocal(Qureg qureg, int controlQubit, int targetQubit, int conjFac)
Definition: QuEST_cpu.c:2776
void densmatr_applyKrausSuperoperator(Qureg qureg, int target, ComplexMatrix4 superOp)
Definition: QuEST_common.c:576
void densmatr_oneQubitDegradeOffDiagonal(Qureg qureg, int targetQubit, qreal retain)
Definition: QuEST_cpu.c:48
void statevec_initBlankState(Qureg qureg)
Definition: QuEST_cpu.c:1398
void populateKrausSuperOperator2(ComplexMatrix4 *superOp, ComplexMatrix2 *ops, int numOps)
Definition: QuEST_common.c:563
void alternateNormZeroingSomeAmpBlocks(Qureg qureg, qreal norm, int normFirst, long long int startAmpInd, long long int numAmps, long long int blockSize)
Definition: QuEST_cpu.c:754
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
int numRanks
Definition: QuEST.h:245
void densmatr_mixTwoQubitDephasing(Qureg qureg, int qubit1, int qubit2, qreal dephase)
Definition: QuEST_cpu.c:84
void statevec_compactUnitaryDistributed(Qureg qureg, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Rotate a single qubit in the state vector of probability amplitudes, given two complex numbers alpha ...
Definition: QuEST_cpu.c:2001
qreal imag[4][4]
Definition: QuEST.h:128
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 ...
void exchangeStateVectors(Qureg qureg, int pairRank)
int numQubits
The number of qubits this operator can act on (informing its size)
Definition: QuEST.h:181
void statevec_multiControlledUnitaryLocal(Qureg qureg, int targetQubit, long long int ctrlQubitsMask, long long int ctrlFlipMask, ComplexMatrix2 u)
Definition: QuEST_cpu.c:2173
long long int getQubitBitMask(int *qubits, int numQubits)
Definition: QuEST_common.c:44
void normaliseSomeAmps(Qureg qureg, qreal norm, long long int startInd, long long int numAmps)
Definition: QuEST_cpu.c:744
void statevec_compactUnitary(Qureg qureg, int targetQubit, Complex alpha, Complex beta)
Represents a diagonal complex operator on the full Hilbert state of a Qureg.
Definition: QuEST.h:178
@ PAULI_Y
Definition: QuEST.h:96
void statevec_pauliYDistributed(Qureg qureg, ComplexArray stateVecIn, ComplexArray stateVecOut, int updateUpper, int conjFac)
Rotate a single qubit by +-{{0,-i},{i,0}.
Definition: QuEST_cpu.c:2739
void densmatr_mixDampingDistributed(Qureg qureg, int targetQubit, qreal damping)
Definition: QuEST_cpu.c:300
Complex densmatr_calcExpecDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:3781
void statevec_pauliXLocal(Qureg qureg, int targetQubit)
Definition: QuEST_cpu.c:2498
void statevec_controlledRotateAroundAxis(Qureg qureg, int controlQubit, int targetQubit, qreal angle, Vector axis)
Definition: QuEST_common.c:327
void densmatr_initPureStateLocal(Qureg targetQureg, Qureg copyQureg)
Definition: QuEST_cpu.c:1184
__forceinline__ __device__ int extractBit(const int locationOfBitFromRight, const long long int theEncodedNumber)
Definition: QuEST_gpu.cu:82
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:3619
void statevec_collapseToKnownProbOutcome(Qureg qureg, int measureQubit, int outcome, qreal outcomeProb)
void densmatr_mixDampingLocal(Qureg qureg, int targetQubit, qreal damping)
Definition: QuEST_cpu.c:174
qreal statevec_getImagAmp(Qureg qureg, long long int index)
qreal densmatr_calcInnerProductLocal(Qureg a, Qureg b)
computes Tr(conjTrans(a) b) = sum of (a_ij^* b_ij)
Definition: QuEST_cpu.c:958
static int getChunkIdFromIndex(Qureg qureg, long long int index)
void statevec_unitaryDistributed(Qureg qureg, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Apply a unitary operation to a single qubit given a subset of the state vector with upper and lower b...
Definition: QuEST_cpu.c:2056
void statevec_controlledCompactUnitaryDistributed(Qureg qureg, int controlQubit, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Rotate a single qubit in the state vector of probability amplitudes, given two complex numbers alpha ...
Definition: QuEST_cpu.c:2319
static int densityMatrixBlockFitsInChunk(long long int chunkSize, int numQubits, int targetQubit)
ComplexArray stateVec
Computational state amplitudes - a subset thereof in the MPI version.
Definition: QuEST.h:222
qreal real[2][2]
Definition: QuEST.h:116
void densmatr_mixDepolarisingLocal(Qureg qureg, int targetQubit, qreal depolLevel)
Definition: QuEST_cpu.c:125
void statevec_collapseToKnownProbOutcomeDistributedRenorm(Qureg qureg, int measureQubit, qreal totalProbability)
Renormalise parts of the state vector where measureQubit=0 or 1, based on the total probability of th...
Definition: QuEST_cpu.c:3462
static int halfMatrixBlockFitsInChunk(long long int chunkSize, int targetQubit)
return whether the current qubit rotation will use blocks that fit within a single chunk.
long long int numElemsPerChunk
The number of the 2^numQubits amplitudes stored on each distributed node.
Definition: QuEST.h:183
int isDensityMatrix
Whether this instance is a density-state representation.
Definition: QuEST.h:206
void statevec_hadamardLocal(Qureg qureg, int targetQubit)
Definition: QuEST_cpu.c:2872
int numQubits
Definition: QuEST.h:138
void densmatr_applyDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:3696
void statevec_controlledUnitaryLocal(Qureg qureg, int controlQubit, int targetQubit, ComplexMatrix2 u)
Definition: QuEST_cpu.c:2241
long long int getGlobalIndOfOddParityInChunk(Qureg qureg, int qb1, int qb2)
returns -1 if this node contains no amplitudes where qb1 and qb2 have opposite parity,...
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
void densmatr_mixTwoQubitDepolarisingLocalPart1(Qureg qureg, int qubit1, int qubit2, qreal delta)
Definition: QuEST_cpu.c:488
void copyDiagOpIntoMatrixPairState(Qureg qureg, DiagonalOp op)
void statevec_controlledNotDistributed(Qureg qureg, int controlQubit, ComplexArray stateVecIn, ComplexArray stateVecOut)
Rotate a single qubit by {{0,1},{1,0}.
Definition: QuEST_cpu.c:2646
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
qreal * real
The real values of the 2^numQubits complex elements.
Definition: QuEST.h:189
qreal real
Definition: QuEST.h:105
void statevec_swapQubitAmpsDistributed(Qureg qureg, int pairRank, int qb1, int qb2)
qureg.pairStateVec contains the entire set of amplitudes of the paired node which includes the set of...
Definition: QuEST_cpu.c:3579
void densmatr_applyMultiQubitKrausSuperoperator(Qureg qureg, int *targets, int numTargets, ComplexMatrixN superOp)
Definition: QuEST_common.c:590
qreal imag
Definition: QuEST.h:106
static int getChunkOuterBlockPairIdForPart3(int chunkIsUpperSmallerQubit, int chunkIsUpperBiggerQubit, int chunkId, long long int chunkSize, int smallerQubit, int biggerQubit, int numQubits)
void densmatr_mixTwoQubitDepolarisingDistributed(Qureg qureg, int targetQubit, int qubit2, qreal delta, qreal gamma)
Definition: QuEST_cpu.c:541
void statevec_unitaryLocal(Qureg qureg, int targetQubit, ComplexMatrix2 u)
Definition: QuEST_cpu.c:1932
qreal densmatr_findProbabilityOfZeroLocal(Qureg qureg, int measureQubit)
Definition: QuEST_cpu.c:3151
static int chunkIsUpperInOuterBlock(int chunkId, long long int chunkSize, int targetQubit, int numQubits)
fix – do with masking instead
Represents one complex number.
Definition: QuEST.h:103
void statevec_hadamardDistributed(Qureg qureg, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut, int updateUpper)
Rotate a single qubit by {{1,1},{1,-1}}/sqrt2.
Definition: QuEST_cpu.c:2932
static int maskContainsBit(const long long int mask, const int bitInd)
qreal densmatr_calcProbOfOutcome(Qureg qureg, int measureQubit, int outcome)
void applySymmetrizedTrotterCircuit(Qureg qureg, PauliHamil hamil, qreal time, int order)
Definition: QuEST_common.c:753
void statevec_controlledPauliYDistributed(Qureg qureg, int controlQubit, ComplexArray stateVecIn, ComplexArray stateVecOut, int conjFac)
Definition: QuEST_cpu.c:2830
void statevec_controlledCompactUnitaryLocal(Qureg qureg, int controlQubit, int targetQubit, Complex alpha, Complex beta)
Definition: QuEST_cpu.c:2101
static int chunkIsUpper(int chunkId, long long int chunkSize, int targetQubit)
Returns whether a given chunk in position chunkId is in the upper or lower half of a block.
void statevec_controlledCompactUnitary(Qureg qureg, int controlQubit, int targetQubit, Complex alpha, Complex beta)
qreal statevec_getRealAmp(Qureg qureg, long long int index)
Complex statevec_calcInnerProductLocal(Qureg bra, Qureg ket)
Definition: QuEST_cpu.c:1071
Represents a 2x2 matrix of complex numbers.
Definition: QuEST.h:114
void zeroSomeAmps(Qureg qureg, long long int startInd, long long int numAmps)
Definition: QuEST_cpu.c:734
qreal densmatr_calcFidelityLocal(Qureg qureg, Qureg pureState)
computes a few dens-columns-worth of (vec^*T) dens * vec
Definition: QuEST_cpu.c:990
qreal statevec_findProbabilityOfZeroLocal(Qureg qureg, int measureQubit)
Measure the total probability of a specified qubit being in the zero state across all amplitudes in t...
Definition: QuEST_cpu.c:3206