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

Go to the source code of this file.

Functions

void agnostic_applyQFT (Qureg qureg, int *qubits, int numQubits)
 
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_initDiagonalOpFromPauliHamil (DiagonalOp op, PauliHamil hamil)
 
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)
 
void densmatr_calcProbOfAllOutcomes (qreal *retProbs, Qureg qureg, int *qubits, int numQubits)
 
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 shiftSubregIndices (int *allInds, int *numIndsPerReg, int numRegs, int shift)
 
void statevec_applyDiagonalOp (Qureg qureg, DiagonalOp op)
 
void statevec_applyMultiVarPhaseFuncOverrides (Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int *numTermsPerReg, long long int *overrideInds, qreal *overridePhases, int numOverrides, int conj)
 
void statevec_applyParamNamedPhaseFuncOverrides (Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, qreal *params, int numParams, long long int *overrideInds, qreal *overridePhases, int numOverrides, int conj)
 
void statevec_applyPauliSum (Qureg inQureg, enum pauliOpType *allCodes, qreal *termCoeffs, int numSumTerms, Qureg outQureg)
 
void statevec_applyPhaseFuncOverrides (Qureg qureg, int *qubits, int numQubits, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int numTerms, long long int *overrideInds, qreal *overridePhases, int numOverrides, int conj)
 
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...
 
void statevec_calcProbOfAllOutcomes (qreal *retProbs, Qureg qureg, int *qubits, int numQubits)
 
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_multiControlledMultiQubitNot (Qureg qureg, int ctrlMask, int targMask)
 
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_multiControlledMultiRotatePauli (Qureg qureg, long long int ctrlMask, int *targetQubits, enum pauliOpType *targetPaulis, int numTargets, qreal angle, int applyConj)
 
void statevec_multiControlledMultiRotateZ (Qureg qureg, long long int ctrlMask, long long int targMask, qreal angle)
 
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_applyQFT()

void agnostic_applyQFT ( Qureg  qureg,
int *  qubits,
int  numQubits 
)

Definition at line 849 of file QuEST_common.c.

849  {
850 
851  int densShift = qureg.numQubitsRepresented;
852 
853  // start with top/left-most qubit, work down
854  for (int q=numQubits-1; q >= 0; q--) {
855 
856  // H
857  statevec_hadamard(qureg, qubits[q]);
858  if (qureg.isDensityMatrix)
859  statevec_hadamard(qureg, qubits[q] + densShift);
860  qasm_recordGate(qureg, GATE_HADAMARD, qubits[q]);
861 
862  if (q == 0)
863  break;
864 
865  // succession of C-phases, control on qubits[q], targeting each of
866  // qubits[q-1], qubits[q-1], ... qubits[0]. This can be expressed by
867  // a single invocation of applyNamedPhaseFunc product
868 
869  int numRegs = 2;
870  int numQubitsPerReg[2] = {q, 1};
871  int regs[100]; // [q+1];
872  for (int i=0; i<q+1; i++)
873  regs[i] = qubits[i]; // qubits[q] is in own register
874 
875  int numParams = 1;
876  qreal params[1] = { M_PI / (1 << q) };
877 
878  int conj = 0;
880  qureg, regs, numQubitsPerReg, numRegs,
881  UNSIGNED, SCALED_PRODUCT, params, numParams,
882  NULL, NULL, 0,
883  conj);
884  if (qureg.isDensityMatrix) {
885  conj = 1;
886  shiftSubregIndices(regs, numQubitsPerReg, numRegs, densShift);
888  qureg, regs, numQubitsPerReg, numRegs,
889  UNSIGNED, SCALED_PRODUCT, params, numParams,
890  NULL, NULL, 0,
891  conj);
892  shiftSubregIndices(regs, numQubitsPerReg, numRegs, - densShift);
893  }
895  qureg, regs, numQubitsPerReg, numRegs,
896  UNSIGNED, SCALED_PRODUCT, params, numParams,
897  NULL, NULL, 0);
898  }
899 
900  // final swaps
901  for (int i=0; i<(numQubits/2); i++) {
902 
903  int qb1 = qubits[i];
904  int qb2 = qubits[numQubits-i-1];
905 
906  statevec_swapQubitAmps(qureg, qb1, qb2);
907  if (qureg.isDensityMatrix)
908  statevec_swapQubitAmps(qureg, qb1 + densShift, qb2 + densShift);
909  qasm_recordControlledGate(qureg, GATE_SWAP, qb1, qb2);
910  }
911 }

References GATE_HADAMARD, GATE_SWAP, Qureg::isDensityMatrix, M_PI, Qureg::numQubitsRepresented, qasm_recordControlledGate(), qasm_recordGate(), qasm_recordNamedPhaseFunc(), qreal, SCALED_PRODUCT, shiftSubregIndices(), statevec_applyParamNamedPhaseFuncOverrides(), statevec_hadamard(), statevec_swapQubitAmps(), and UNSIGNED.

Referenced by applyFullQFT(), and applyQFT().

◆ agnostic_applyTrotterCircuit()

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

Definition at line 840 of file QuEST_common.c.

840  {
841 
842  if (time == 0)
843  return;
844 
845  for (int r=0; r<reps; r++)
846  applySymmetrizedTrotterCircuit(qureg, hamil, time/reps, order);
847 }

References applySymmetrizedTrotterCircuit().

Referenced by applyTrotterCircuit().

◆ agnostic_createDiagonalOp()

DiagonalOp agnostic_createDiagonalOp ( int  numQubits,
QuESTEnv  env 
)

Definition at line 1346 of file QuEST_cpu.c.

1346  {
1347 
1348  // the 2^numQubits values will be evenly split between the env.numRanks nodes
1349  DiagonalOp op;
1350  op.numQubits = numQubits;
1351  op.numElemsPerChunk = (1LL << numQubits) / env.numRanks;
1352  op.chunkId = env.rank;
1353  op.numChunks = env.numRanks;
1354 
1355  // allocate CPU memory (initialised to zero)
1356  op.real = (qreal*) calloc(op.numElemsPerChunk, sizeof(qreal));
1357  op.imag = (qreal*) calloc(op.numElemsPerChunk, sizeof(qreal));
1358 
1359  // check cpu memory allocation was successful
1360  if ( !op.real || !op.imag ) {
1361  printf("Could not allocate memory!\n");
1362  exit(EXIT_FAILURE);
1363  }
1364 
1365  return op;
1366 }

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

Referenced by createDiagonalOp(), and createDiagonalOpFromPauliHamilFile().

◆ agnostic_destroyDiagonalOp()

void agnostic_destroyDiagonalOp ( DiagonalOp  op)

Definition at line 1368 of file QuEST_cpu.c.

1368  {
1369  free(op.real);
1370  free(op.imag);
1371 }

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

Referenced by destroyDiagonalOp().

◆ agnostic_initDiagonalOpFromPauliHamil()

void agnostic_initDiagonalOpFromPauliHamil ( DiagonalOp  op,
PauliHamil  hamil 
)

Definition at line 1377 of file QuEST_cpu.c.

1377  {
1378 
1379  /* each node modifies its op sub-partition, evaluating the full hamil
1380  * for every element in the sub-partition
1381  */
1382 
1383  // unpack op
1384  long long int offset = op.chunkId * op.numElemsPerChunk;
1385  long long int numElems = op.numElemsPerChunk;
1386  qreal* opRe = op.real;
1387  qreal* opIm = op.imag;
1388 
1389  // unpack hamil
1390  int numTerms = hamil.numSumTerms;
1391  int numQubits = hamil.numQubits;
1392  qreal* coeffs = hamil.termCoeffs;
1393  enum pauliOpType* codes = hamil.pauliCodes;
1394 
1395  // private OpenMP vars
1396  long long int i, globalInd;
1397  qreal elem;
1398  int t, q, isOddNumOnes, sign;
1399 
1400 # ifdef _OPENMP
1401 # pragma omp parallel \
1402  default (none) \
1403  shared (offset,numElems, opRe,opIm, numTerms,numQubits,coeffs,codes) \
1404  private (i,globalInd, elem, isOddNumOnes,t,q,sign)
1405 # endif
1406  {
1407 # ifdef _OPENMP
1408 # pragma omp for schedule (static)
1409 # endif
1410  for (i=0; i<numElems; i++) {
1411 
1412  globalInd = i + offset;
1413  elem = 0;
1414 
1415  // add every Hamiltonian coefficient to this element, either + or -
1416  for (t=0; t<numTerms; t++) {
1417 
1418  // determine parity of ones (in globalInd basis state) of the current term's targets
1419  isOddNumOnes = 0;
1420  for (q=0; q<numQubits; q++)
1421  if (codes[q + t*numQubits] == PAULI_Z)
1422  if (extractBit(q, globalInd))
1423  isOddNumOnes = !isOddNumOnes;
1424 
1425  // add +- term coeff (avoiding thread divergence)
1426  sign = 1 - 2*isOddNumOnes; // (-1 if isOddNumOnes, else +1)
1427  elem += coeffs[t] * sign;
1428  }
1429 
1430  opRe[i] = elem;
1431  opIm[i] = 0;
1432  }
1433  }
1434 
1435  // we don't synch to GPU, because in GPU mode, the GPU populates and synchs to RAM
1436  // agnostic_syncDiagonalOp(op);
1437 }

References DiagonalOp::chunkId, extractBit(), DiagonalOp::imag, DiagonalOp::numElemsPerChunk, PauliHamil::numQubits, DiagonalOp::numQubits, PauliHamil::numSumTerms, PAULI_Z, PauliHamil::pauliCodes, qreal, DiagonalOp::real, and PauliHamil::termCoeffs.

Referenced by createDiagonalOpFromPauliHamilFile(), and initDiagonalOpFromPauliHamil().

◆ agnostic_setDiagonalOpElems()

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

Definition at line 4228 of file QuEST_cpu.c.

4228  {
4229 
4230  // local start/end indices of the given amplitudes, assuming they fit in this chunk
4231  // these may be negative or above qureg.numAmpsPerChunk
4232  long long int localStartInd = startInd - op.chunkId*op.numElemsPerChunk;
4233  long long int localEndInd = localStartInd + numElems; // exclusive
4234 
4235  // add this to a local index to get corresponding elem in reals & imags
4236  long long int offset = op.chunkId*op.numElemsPerChunk - startInd;
4237 
4238  // restrict these indices to fit into this chunk
4239  if (localStartInd < 0)
4240  localStartInd = 0;
4241  if (localEndInd > op.numElemsPerChunk)
4242  localEndInd = op.numElemsPerChunk;
4243  // they may now be out of order = no iterations
4244 
4245  // unpacking OpenMP vars
4246  long long int index;
4247  qreal* vecRe = op.real;
4248  qreal* vecIm = op.imag;
4249 
4250 # ifdef _OPENMP
4251 # pragma omp parallel \
4252  default (none) \
4253  shared (localStartInd,localEndInd, vecRe,vecIm, real,imag, offset) \
4254  private (index)
4255 # endif
4256  {
4257 # ifdef _OPENMP
4258 # pragma omp for schedule (static)
4259 # endif
4260  // iterate these local inds - this might involve no iterations
4261  for (index=localStartInd; index < localEndInd; index++) {
4262  vecRe[index] = real[index + offset];
4263  vecIm[index] = imag[index + offset];
4264  }
4265  }
4266 }

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 1373 of file QuEST_cpu.c.

1373  {
1374  // nothing to do on CPU
1375 }

References DiagonalOp::deviceOperator, DiagonalOp::imag, DiagonalOp::numElemsPerChunk, 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 1618 of file QuEST_cpu_distributed.c.

1618  {
1619 
1620  Complex localVal = densmatr_calcExpecDiagonalOpLocal(qureg, op);
1621  if (qureg.numChunks == 1)
1622  return localVal;
1623 
1624  qreal localRe = localVal.real;
1625  qreal localIm = localVal.imag;
1626  qreal globalRe, globalIm;
1627 
1628  MPI_Allreduce(&localRe, &globalRe, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1629  MPI_Allreduce(&localIm, &globalIm, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1630 
1631  Complex globalVal;
1632  globalVal.real = globalRe;
1633  globalVal.imag = globalIm;
1634  return globalVal;
1635 }

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 429 of file QuEST_cpu_distributed.c.

429  {
430 
431  // set qureg's pairState is to be the full pureState (on every node)
432  copyVecIntoMatrixPairState(qureg, pureState);
433 
434  // collect calcFidelityLocal by every machine
435  qreal localSum = densmatr_calcFidelityLocal(qureg, pureState);
436 
437  // sum each localSum
438  qreal globalSum;
439  MPI_Allreduce(&localSum, &globalSum, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
440 
441  return globalSum;
442 }

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 444 of file QuEST_cpu_distributed.c.

444  {
445 
447 
448  qreal globalSum;
449  MPI_Allreduce(&localSum, &globalSum, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
450 
451  qreal dist = sqrt(globalSum);
452  return dist;
453 }

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 455 of file QuEST_cpu_distributed.c.

455  {
456 
457  qreal localSum = densmatr_calcInnerProductLocal(a, b);
458 
459  qreal globalSum;
460  MPI_Allreduce(&localSum, &globalSum, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
461 
462  qreal dist = globalSum;
463  return dist;
464 }

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

Referenced by calcDensityInnerProduct().

◆ densmatr_calcProbOfAllOutcomes()

void densmatr_calcProbOfAllOutcomes ( qreal retProbs,
Qureg  qureg,
int *  qubits,
int  numQubits 
)

Definition at line 1349 of file QuEST_cpu_distributed.c.

1349  {
1350 
1351  // each node populates retProbs with contributions from the subset of amps in each
1352  densmatr_calcProbOfAllOutcomesLocal(retProbs, qureg, qubits, numQubits);
1353 
1354  // then, retProbs are summed element-wise
1355  MPI_Allreduce(MPI_IN_PLACE, retProbs, 1LL<<numQubits, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1356 }

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

Referenced by calcProbOfAllOutcomes().

◆ densmatr_calcProbOfOutcome()

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

Definition at line 1328 of file QuEST_cpu_distributed.c.

1328  {
1329 
1330  qreal zeroProb = densmatr_findProbabilityOfZeroLocal(qureg, measureQubit);
1331 
1332  qreal outcomeProb;
1333  MPI_Allreduce(&zeroProb, &outcomeProb, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1334  if (outcome == 1)
1335  outcomeProb = 1.0 - outcomeProb;
1336 
1337  return outcomeProb;
1338 }

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 1358 of file QuEST_cpu_distributed.c.

1358  {
1359 
1360  qreal localPurity = densmatr_calcPurityLocal(qureg);
1361 
1362  qreal globalPurity;
1363  MPI_Allreduce(&localPurity, &globalPurity, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1364 
1365  return globalPurity;
1366 }

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 791 of file QuEST_cpu.c.

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

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

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

◆ densmatr_initClassicalState()

void densmatr_initClassicalState ( Qureg  qureg,
long long int  stateInd 
)

Definition at line 1126 of file QuEST_cpu.c.

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

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 1165 of file QuEST_cpu.c.

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

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 466 of file QuEST_cpu_distributed.c.

466  {
467 
468  if (targetQureg.numChunks==1){
469  // local version
470  // save pointers to qureg's pair state
471  qreal* quregPairRePtr = targetQureg.pairStateVec.real;
472  qreal* quregPairImPtr = targetQureg.pairStateVec.imag;
473 
474  // populate qureg pair state with pure state (by repointing)
475  targetQureg.pairStateVec.real = copyQureg.stateVec.real;
476  targetQureg.pairStateVec.imag = copyQureg.stateVec.imag;
477 
478  // populate density matrix via it's pairState
479  densmatr_initPureStateLocal(targetQureg, copyQureg);
480 
481  // restore pointers
482  targetQureg.pairStateVec.real = quregPairRePtr;
483  targetQureg.pairStateVec.imag = quregPairImPtr;
484  } else {
485  // set qureg's pairState is to be the full pure state (on every node)
486  copyVecIntoMatrixPairState(targetQureg, copyQureg);
487 
488  // update every density matrix chunk using pairState
489  densmatr_initPureStateLocal(targetQureg, copyQureg);
490  }
491 }

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 372 of file QuEST_common.c.

372  {
373 
374  qreal zeroProb = densmatr_calcProbOfOutcome(qureg, measureQubit, 0);
375  int outcome = generateMeasurementOutcome(zeroProb, outcomeProb);
376  densmatr_collapseToKnownProbOutcome(qureg, measureQubit, outcome, *outcomeProb);
377  return outcome;
378 }

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 739 of file QuEST_cpu_distributed.c.

739  {
740  if (damping == 0)
741  return;
742 
743  int rankIsUpper; // rank is in the upper half of an outer block
744  int pairRank; // rank of corresponding chunk
745 
746  int useLocalDataOnly = densityMatrixBlockFitsInChunk(qureg.numAmpsPerChunk,
747  qureg.numQubitsRepresented, targetQubit);
748 
749  if (useLocalDataOnly){
750  densmatr_mixDampingLocal(qureg, targetQubit, damping);
751  } else {
752  // pack data to send to my pair process into the first half of pairStateVec
753  compressPairVectorForSingleQubitDepolarise(qureg, targetQubit);
754 
755  rankIsUpper = chunkIsUpperInOuterBlock(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit,
756  qureg.numQubitsRepresented);
757  pairRank = getChunkOuterBlockPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk,
758  targetQubit, qureg.numQubitsRepresented);
759 
760  exchangePairStateVectorHalves(qureg, pairRank);
761  densmatr_mixDampingDistributed(qureg, targetQubit, damping);
762  }
763 
764 }

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 901 of file QuEST_cpu.c.

901  {
902 
903  /* corresponding amplitudes live on the same node (same dimensions) */
904 
905  // unpack vars for OpenMP
906  qreal* combineVecRe = combineQureg.stateVec.real;
907  qreal* combineVecIm = combineQureg.stateVec.imag;
908  qreal* otherVecRe = otherQureg.stateVec.real;
909  qreal* otherVecIm = otherQureg.stateVec.imag;
910  long long int numAmps = combineQureg.numAmpsPerChunk;
911  long long int index;
912 
913 # ifdef _OPENMP
914 # pragma omp parallel \
915  default (none) \
916  shared (combineVecRe,combineVecIm,otherVecRe,otherVecIm, otherProb, numAmps) \
917  private (index)
918 # endif
919  {
920 # ifdef _OPENMP
921 # pragma omp for schedule (static)
922 # endif
923  for (index=0; index < numAmps; index++) {
924  combineVecRe[index] *= 1-otherProb;
925  combineVecIm[index] *= 1-otherProb;
926 
927  combineVecRe[index] += otherProb * otherVecRe[index];
928  combineVecIm[index] += otherProb * otherVecIm[index];
929  }
930  }
931 }

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

Referenced by mixDensityMatrix().

◆ densmatr_mixDephasing()

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

Definition at line 85 of file QuEST_cpu.c.

85  {
86  qreal retain=1-dephase;
87  densmatr_oneQubitDegradeOffDiagonal(qureg, targetQubit, retain);
88 }

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 712 of file QuEST_cpu_distributed.c.

712  {
713  if (depolLevel == 0)
714  return;
715 
716  int rankIsUpper; // rank is in the upper half of an outer block
717  int pairRank; // rank of corresponding chunk
718 
719  int useLocalDataOnly = densityMatrixBlockFitsInChunk(qureg.numAmpsPerChunk,
720  qureg.numQubitsRepresented, targetQubit);
721 
722  if (useLocalDataOnly){
723  densmatr_mixDepolarisingLocal(qureg, targetQubit, depolLevel);
724  } else {
725  // pack data to send to my pair process into the first half of pairStateVec
726  compressPairVectorForSingleQubitDepolarise(qureg, targetQubit);
727 
728  rankIsUpper = chunkIsUpperInOuterBlock(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit,
729  qureg.numQubitsRepresented);
730  pairRank = getChunkOuterBlockPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk,
731  targetQubit, qureg.numQubitsRepresented);
732 
733  exchangePairStateVectorHalves(qureg, pairRank);
734  densmatr_mixDepolarisingDistributed(qureg, targetQubit, depolLevel);
735  }
736 
737 }

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 644 of file QuEST_common.c.

644  {
645 
646  ComplexMatrix4 superOp;
647  populateKrausSuperOperator2(&superOp, ops, numOps);
648  densmatr_applyKrausSuperoperator(qureg, target, superOp);
649 }

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 701 of file QuEST_common.c.

701  {
702 
703  ComplexMatrixN superOp;
704 
705  /* superOp will contain 2^(4 numTargets) complex numbers.
706  * At double precision, superOp will cost additional memory:
707  * numTargs=1 -> 0.25 KiB
708  * numTargs=2 -> 4 KiB
709  * numTargs=3 -> 64 KiB
710  * numTargs=4 -> 1 MiB
711  * numTargs=5 -> 16 MiB.
712  * At quad precision (usually 10 B per number, but possibly 16 B due to alignment),
713  * this costs at most double.
714  *
715  * Hence, if superOp is kept in the stack, numTargs >= 4 would exceed Windows' 1 MB
716  * maximum stack-space allocation (numTargs >= 5 exceeding Linux' 8 MB). Therefore,
717  * for numTargets < 4, superOp will be kept in the stack, else in the heap
718  */
719 
720  // if NOT on Windows, allocate ComplexN on stack depending on size
721  #ifndef _WIN32
722  if (numTargets < 4) {
723  // everything must live in 'if' since this macro declares local vars
724  macro_allocStackComplexMatrixN(superOp, 2*numTargets);
725  populateKrausSuperOperatorN(&superOp, ops, numOps);
726  densmatr_applyMultiQubitKrausSuperoperator(qureg, targets, numTargets, superOp);
727  }
728  else {
729  superOp = createComplexMatrixN(2*numTargets);
730  populateKrausSuperOperatorN(&superOp, ops, numOps);
731  densmatr_applyMultiQubitKrausSuperoperator(qureg, targets, numTargets, superOp);
732  destroyComplexMatrixN(superOp);
733  }
734  // on Windows, we must always create in heap
735  #else
736  superOp = createComplexMatrixN(2*numTargets);
737  populateKrausSuperOperatorN(&superOp, ops, numOps);
738  densmatr_applyMultiQubitKrausSuperoperator(qureg, targets, numTargets, superOp);
739  destroyComplexMatrixN(superOp);
740  #endif
741 }

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 743 of file QuEST_common.c.

743  {
744 
745  // convert pauli probabilities into Kraus map
746  const int numOps = 4;
747  ComplexMatrix2 ops[4]; // [numOps];
748  for (int n=0; n < numOps; n++)
749  ops[n] = (ComplexMatrix2) {.real={{0}}, .imag={{0}}};
750 
751  qreal facs[4] = { // literal numOps=4 for valid initialisation
752  sqrt(1-(probX + probY + probZ)),
753  sqrt(probX),
754  sqrt(probY),
755  sqrt(probZ)
756  };
757  ops[0].real[0][0] = facs[0]; ops[0].real[1][1] = facs[0];
758  ops[1].real[0][1] = facs[1]; ops[1].real[1][0] = facs[1];
759  ops[2].imag[0][1] = -facs[2]; ops[2].imag[1][0] = facs[2];
760  ops[3].real[0][0] = facs[3]; ops[3].real[1][1] = -facs[3];
761 
762  densmatr_mixKrausMap(qureg, qubit, ops, numOps);
763 }

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 90 of file QuEST_cpu.c.

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

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 766 of file QuEST_cpu_distributed.c.

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

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 682 of file QuEST_common.c.

682  {
683 
684  // if NOT on Windows, allocate ComplexN on stack
685  #ifndef _WIN32
686  ComplexMatrixN superOp;
687  macro_allocStackComplexMatrixN(superOp, 4);
688  populateKrausSuperOperator4(&superOp, ops, numOps);
689  densmatr_applyTwoQubitKrausSuperoperator(qureg, target1, target2, superOp);
690 
691  // but on Windows, we MUST allocated dynamically
692  #else
694  populateKrausSuperOperator4(&superOp, ops, numOps);
695  densmatr_applyTwoQubitKrausSuperoperator(qureg, target1, target2, superOp);
696  destroyComplexMatrixN(superOp);
697 
698  #endif
699 }

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

Referenced by mixTwoQubitKrausMap().

◆ ensureIndsIncrease()

void ensureIndsIncrease ( int *  ind1,
int *  ind2 
)

Definition at line 70 of file QuEST_common.c.

70  {
71 
72  if (*ind1 > *ind2) {
73  int copy = *ind1;
74  *ind1 = *ind2;
75  *ind2 = copy;
76  }
77 }

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 142 of file QuEST_common.c.

142  {
143 
144  qreal r0c0Phase = atan2(u.imag[0][0], u.real[0][0]);
145  qreal r1c1Phase = atan2(u.imag[1][1], u.real[1][1]);
146  *globalPhase = (r0c0Phase + r1c1Phase)/2.0;
147 
148  qreal cosPhase = cos(*globalPhase);
149  qreal sinPhase = sin(*globalPhase);
150  alpha->real = u.real[0][0]*cosPhase + u.imag[0][0]*sinPhase;
151  alpha->imag = u.imag[0][0]*cosPhase - u.real[0][0]*sinPhase;
152  beta->real = u.real[1][0]*cosPhase + u.imag[1][0]*sinPhase;
153  beta->imag = u.imag[1][0]*cosPhase - u.real[1][0]*sinPhase;
154 }

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 120 of file QuEST_common.c.

120  {
121 
122  Vector unitAxis = getUnitVector(axis);
123  alpha->real = cos(angle/2.0);
124  alpha->imag = - sin(angle/2.0)*unitAxis.z;
125  beta->real = sin(angle/2.0)*unitAxis.y;
126  beta->imag = - sin(angle/2.0)*unitAxis.x;
127 }

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 105 of file QuEST_common.c.

105  {
106  ComplexMatrix2 conj;
107  macro_setConjugateMatrix(conj, src, 2);
108  return conj;
109 }

References macro_setConjugateMatrix.

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

◆ getConjugateMatrix4()

ComplexMatrix4 getConjugateMatrix4 ( ComplexMatrix4  src)

Definition at line 110 of file QuEST_common.c.

110  {
111  ComplexMatrix4 conj;
112  macro_setConjugateMatrix(conj, src, 4);
113  return conj;
114 }

References macro_setConjugateMatrix.

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

◆ getConjugateScalar()

Complex getConjugateScalar ( Complex  scalar)

Definition at line 91 of file QuEST_common.c.

91  {
92 
93  Complex conjScalar;
94  conjScalar.real = scalar.real;
95  conjScalar.imag = - scalar.imag;
96  return conjScalar;
97 }

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 60 of file QuEST_common.c.

60  {
61 
62  long long int mask=0;
63  for (int i=0; i<numControlQubits; i++)
64  if (controlState[i] == 0)
65  mask = mask | (1LL << controlQubits[i]);
66 
67  return mask;
68 }

Referenced by multiStateControlledUnitary().

◆ getQubitBitMask()

◆ getQuESTDefaultSeedKey()

void getQuESTDefaultSeedKey ( unsigned long int *  key)

Definition at line 195 of file QuEST_common.c.

195  {
196  // init MT random number generator with two keys -- time and pid
197  // for the MPI version, it is ok that all procs will get the same seed as random numbers will only be
198  // used by the master process
199 #if defined(_WIN32) && ! defined(__MINGW32__)
200 
201  unsigned long int pid = (unsigned long int) _getpid();
202  unsigned long int msecs = (unsigned long int) GetTickCount64();
203 
204  key[0] = msecs; key[1] = pid;
205 #else
206  struct timeval tv;
207  gettimeofday(&tv, NULL);
208 
209  double time_in_mill =
210  (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond
211 
212  unsigned long int pid = getpid();
213  unsigned long int msecs = (unsigned long int) time_in_mill;
214 
215  key[0] = msecs; key[1] = pid;
216 #endif
217 }

Referenced by seedQuESTDefault().

◆ getVectorMagnitude()

qreal getVectorMagnitude ( Vector  vec)

Definition at line 79 of file QuEST_common.c.

79  {
80 
81  return sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
82 }

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 130 of file QuEST_common.c.

130  {
131 
132  qreal alphaMag = sqrt(alpha.real*alpha.real + alpha.imag*alpha.imag);
133  *ry = 2.0 * acos(alphaMag);
134 
135  qreal alphaPhase = atan2(alpha.imag, alpha.real);
136  qreal betaPhase = atan2(beta.imag, beta.real);
137  *rz2 = - alphaPhase + betaPhase;
138  *rz1 = - alphaPhase - betaPhase;
139 }

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 185 of file QuEST_common.c.

185  {
186  unsigned long int hash = 5381;
187  int c;
188 
189  while ((c = *str++))
190  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
191 
192  return hash;
193 }

◆ setConjugateMatrixN()

void setConjugateMatrixN ( ComplexMatrixN  m)

Definition at line 115 of file QuEST_common.c.

115  {
116  int len = 1 << m.numQubits;
117  macro_setConjugateMatrix(m, m, len);
118 }

References macro_setConjugateMatrix, and ComplexMatrixN::numQubits.

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

◆ shiftIndices()

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

◆ shiftSubregIndices()

void shiftSubregIndices ( int *  allInds,
int *  numIndsPerReg,
int  numRegs,
int  shift 
)

Definition at line 161 of file QuEST_common.c.

161  {
162  int i=0;
163  for (int r=0; r<numRegs; r++)
164  for (int j=0; j<numIndsPerReg[r]; j++)
165  allInds[i++] += shift;
166 }

Referenced by agnostic_applyQFT(), applyMultiVarPhaseFunc(), applyMultiVarPhaseFuncOverrides(), applyNamedPhaseFunc(), applyNamedPhaseFuncOverrides(), applyParamNamedPhaseFunc(), and applyParamNamedPhaseFuncOverrides().

◆ statevec_applyDiagonalOp()

void statevec_applyDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 4047 of file QuEST_cpu.c.

4047  {
4048 
4049  // each node/chunk modifies only its values in an embarrassingly parallelisable way
4050  long long int numAmps = qureg.numAmpsPerChunk;
4051 
4052  qreal* stateRe = qureg.stateVec.real;
4053  qreal* stateIm = qureg.stateVec.imag;
4054  qreal* opRe = op.real;
4055  qreal* opIm = op.imag;
4056 
4057  qreal a,b,c,d;
4058  long long int index;
4059 
4060 # ifdef _OPENMP
4061 # pragma omp parallel \
4062  shared (stateRe,stateIm, opRe,opIm, numAmps) \
4063  private (index, a,b,c,d)
4064 # endif
4065  {
4066 # ifdef _OPENMP
4067 # pragma omp for schedule (static)
4068 # endif
4069  for (index=0LL; index<numAmps; index++) {
4070  a = stateRe[index];
4071  b = stateIm[index];
4072  c = opRe[index];
4073  d = opIm[index];
4074 
4075  // (a + b i)(c + d i) = (a c - b d) + i (a d + b c)
4076  stateRe[index] = a*c - b*d;
4077  stateIm[index] = a*d + b*c;
4078  }
4079  }
4080 }

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

Referenced by applyDiagonalOp().

◆ statevec_applyMultiVarPhaseFuncOverrides()

void statevec_applyMultiVarPhaseFuncOverrides ( Qureg  qureg,
int *  qubits,
int *  numQubitsPerReg,
int  numRegs,
enum bitEncoding  encoding,
qreal coeffs,
qreal exponents,
int *  numTermsPerReg,
long long int *  overrideInds,
qreal overridePhases,
int  numOverrides,
int  conj 
)

Definition at line 4345 of file QuEST_cpu.c.

4350 {
4351  // each node/chunk modifies only local values in an embarrassingly parallel way
4352 
4353  // note partitions of qubits, coeffs, exponents and overrideInds are stored flat
4354 
4355  // thread-shared vaes
4356  int chunkId = qureg.chunkId;
4357  long long int numAmps = qureg.numAmpsPerChunk;
4358  qreal* stateRe = qureg.stateVec.real;
4359  qreal* stateIm = qureg.stateVec.imag;
4360 
4361  // thread-private vars
4362  long long int index, globalAmpInd;
4363  int r, q, i, t, found, flatInd;
4364  qreal phase, c, s, re, im;
4365 
4366  // each thread has a private static array of length >= numRegs (private var-length is illegal)
4367  long long int phaseInds[MAX_NUM_REGS_APPLY_ARBITRARY_PHASE];
4368 
4369 # ifdef _OPENMP
4370 # pragma omp parallel \
4371  default (none) \
4372  shared (chunkId,numAmps, stateRe,stateIm, qubits,numQubitsPerReg,numRegs,encoding, coeffs,exponents,numTermsPerReg, overrideInds,overridePhases,numOverrides, conj) \
4373  private (index,globalAmpInd, r,q,i,t,flatInd, found, phaseInds,phase, c,s,re,im)
4374 # endif
4375  {
4376 # ifdef _OPENMP
4377 # pragma omp for schedule (static)
4378 # endif
4379  for (index=0LL; index<numAmps; index++) {
4380 
4381  // determine global amplitude index
4382  globalAmpInd = chunkId * numAmps + index;
4383 
4384  // determine phase indices
4385  flatInd = 0;
4386  for (r=0; r<numRegs; r++) {
4387  phaseInds[r] = 0LL;
4388 
4389  if (encoding == UNSIGNED) {
4390  for (q=0; q<numQubitsPerReg[r]; q++)
4391  phaseInds[r] += (1LL << q) * extractBit(qubits[flatInd++], globalAmpInd); // qubits[flatInd] ~ qubits[r][q]
4392  }
4393  else if (encoding == TWOS_COMPLEMENT) {
4394  for (q=0; q<numQubitsPerReg[r]-1; q++)
4395  phaseInds[r] += (1LL << q) * extractBit(qubits[flatInd++], globalAmpInd);
4396  // use final qubit to indicate sign
4397  if (extractBit(qubits[flatInd++], globalAmpInd) == 1)
4398  phaseInds[r] -= (1LL << (numQubitsPerReg[r]-1));
4399  }
4400  }
4401 
4402  // determine if this phase index has an overriden value (i < numOverrides)
4403  for (i=0; i<numOverrides; i++) {
4404  found = 1;
4405  for (r=0; r<numRegs; r++) {
4406  if (phaseInds[r] != overrideInds[i*numRegs+r]) {
4407  found = 0;
4408  break;
4409  }
4410  }
4411  if (found)
4412  break;
4413  }
4414 
4415  // compute the phase (unless overriden)
4416  phase = 0;
4417  if (i < numOverrides)
4418  phase = overridePhases[i];
4419  else {
4420  flatInd = 0;
4421  for (r=0; r<numRegs; r++) {
4422  for (t=0; t<numTermsPerReg[r]; t++) {
4423  phase += coeffs[flatInd] * pow(phaseInds[r], exponents[flatInd]);
4424  flatInd++;
4425  }
4426  }
4427  }
4428 
4429  // negate phase to conjugate operator
4430  if (conj)
4431  phase *= -1;
4432 
4433  // modify amp to amp * exp(i phase)
4434  c = cos(phase);
4435  s = sin(phase);
4436  re = stateRe[index];
4437  im = stateIm[index];
4438 
4439  // = {re[amp] cos(phase) - im[amp] sin(phase)} + i {re[amp] sin(phase) + im[amp] cos(phase)}
4440  stateRe[index] = re*c - im*s;
4441  stateIm[index] = re*s + im*c;
4442  }
4443  }
4444 }

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

Referenced by applyMultiVarPhaseFunc(), and applyMultiVarPhaseFuncOverrides().

◆ statevec_applyParamNamedPhaseFuncOverrides()

void statevec_applyParamNamedPhaseFuncOverrides ( Qureg  qureg,
int *  qubits,
int *  numQubitsPerReg,
int  numRegs,
enum bitEncoding  encoding,
enum phaseFunc  functionNameCode,
qreal params,
int  numParams,
long long int *  overrideInds,
qreal overridePhases,
int  numOverrides,
int  conj 
)

Definition at line 4446 of file QuEST_cpu.c.

4452  {
4453  // each node/chunk modifies only local values in an embarrassingly parallel way
4454 
4455  // note partitions of qubits, overrideInds are stored flat
4456 
4457  // thread-shared vaes
4458  int chunkId = qureg.chunkId;
4459  long long int numAmps = qureg.numAmpsPerChunk;
4460  qreal* stateRe = qureg.stateVec.real;
4461  qreal* stateIm = qureg.stateVec.imag;
4462 
4463  // thread-private vars
4464  long long int index, globalAmpInd;
4465  int r, q, i, found, flatInd;
4466  qreal phase, norm, prod, dist, c, s, re, im;
4467 
4468  // each thread has a private static array of length >= numRegs (private var-length is illegal)
4469  long long int phaseInds[MAX_NUM_REGS_APPLY_ARBITRARY_PHASE];
4470 
4471 # ifdef _OPENMP
4472 # pragma omp parallel \
4473  default (none) \
4474  shared (chunkId,numAmps, stateRe,stateIm, qubits,numQubitsPerReg,numRegs,encoding, phaseFuncName,params,numParams, overrideInds,overridePhases,numOverrides, conj) \
4475  private (index,globalAmpInd, r,q,i,flatInd, found, phaseInds,phase,norm,prod,dist, c,s,re,im)
4476 # endif
4477  {
4478 # ifdef _OPENMP
4479 # pragma omp for schedule (static)
4480 # endif
4481  for (index=0LL; index<numAmps; index++) {
4482 
4483  // determine global amplitude index
4484  globalAmpInd = chunkId * numAmps + index;
4485 
4486  // determine phase indices
4487  flatInd = 0;
4488  for (r=0; r<numRegs; r++) {
4489  phaseInds[r] = 0LL;
4490 
4491  if (encoding == UNSIGNED) {
4492  for (q=0; q<numQubitsPerReg[r]; q++)
4493  phaseInds[r] += (1LL << q) * extractBit(qubits[flatInd++], globalAmpInd); // qubits[flatInd] ~ qubits[r][q]
4494  }
4495  else if (encoding == TWOS_COMPLEMENT) {
4496  for (q=0; q<numQubitsPerReg[r]-1; q++)
4497  phaseInds[r] += (1LL << q) * extractBit(qubits[flatInd++], globalAmpInd);
4498  // use final qubit to indicate sign
4499  if (extractBit(qubits[flatInd++], globalAmpInd) == 1)
4500  phaseInds[r] -= (1LL << (numQubitsPerReg[r]-1));
4501  }
4502  }
4503 
4504  // determine if this phase index has an overriden value (i < numOverrides)
4505  for (i=0; i<numOverrides; i++) {
4506  found = 1;
4507  for (r=0; r<numRegs; r++) {
4508  if (phaseInds[r] != overrideInds[i*numRegs+r]) {
4509  found = 0;
4510  break;
4511  }
4512  }
4513  if (found)
4514  break;
4515  }
4516 
4517  // compute the phase (unless overriden)
4518  phase = 0;
4519  if (i < numOverrides)
4520  phase = overridePhases[i];
4521  else {
4522  // compute norm related phases
4523  if (phaseFuncName == NORM || phaseFuncName == INVERSE_NORM ||
4524  phaseFuncName == SCALED_NORM || phaseFuncName == SCALED_INVERSE_NORM ||
4525  phaseFuncName == SCALED_INVERSE_SHIFTED_NORM) {
4526 
4527  norm = 0;
4528  if (phaseFuncName == SCALED_INVERSE_SHIFTED_NORM) {
4529  for (r=0; r<numRegs; r++)
4530  norm += (phaseInds[r] - params[2+r])*(phaseInds[r] - params[2+r]);
4531  }
4532  else
4533  for (r=0; r<numRegs; r++)
4534  norm += phaseInds[r]*phaseInds[r];
4535  norm = sqrt(norm);
4536 
4537  if (phaseFuncName == NORM)
4538  phase = norm;
4539  else if (phaseFuncName == INVERSE_NORM)
4540  phase = (norm == 0.)? params[0] : 1/norm; // smallest non-zero norm is 1
4541  else if (phaseFuncName == SCALED_NORM)
4542  phase = params[0] * norm;
4543  else if (phaseFuncName == SCALED_INVERSE_NORM || phaseFuncName == SCALED_INVERSE_SHIFTED_NORM)
4544  phase = (norm <= REAL_EPS)? params[1] : params[0] / norm; // unless shifted closer to zero
4545  }
4546  // compute product related phases
4547  else if (phaseFuncName == PRODUCT || phaseFuncName == INVERSE_PRODUCT ||
4548  phaseFuncName == SCALED_PRODUCT || phaseFuncName == SCALED_INVERSE_PRODUCT) {
4549 
4550  prod = 1;
4551  for (r=0; r<numRegs; r++)
4552  prod *= phaseInds[r];
4553 
4554  if (phaseFuncName == PRODUCT)
4555  phase = prod;
4556  else if (phaseFuncName == INVERSE_PRODUCT)
4557  phase = (prod == 0.)? params[0] : 1/prod; // smallest non-zero product norm is +- 1
4558  else if (phaseFuncName == SCALED_PRODUCT)
4559  phase = params[0] * prod;
4560  else if (phaseFuncName == SCALED_INVERSE_PRODUCT)
4561  phase = (prod == 0.)? params[1] : params[0] / prod;
4562  }
4563  // compute Euclidean distance related phases
4564  else if (phaseFuncName == DISTANCE || phaseFuncName == INVERSE_DISTANCE ||
4565  phaseFuncName == SCALED_DISTANCE || phaseFuncName == SCALED_INVERSE_DISTANCE ||
4566  phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE) {
4567 
4568  dist = 0;
4569  if (phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE) {
4570  for (r=0; r<numRegs; r+=2)
4571  dist += (phaseInds[r] - phaseInds[r+1] - params[2+r/2])*(phaseInds[r] - phaseInds[r+1] - params[2+r/2]);
4572  }
4573  else
4574  for (r=0; r<numRegs; r+=2)
4575  dist += (phaseInds[r+1] - phaseInds[r])*(phaseInds[r+1] - phaseInds[r]);
4576  dist = sqrt(dist);
4577 
4578  if (phaseFuncName == DISTANCE)
4579  phase = dist;
4580  else if (phaseFuncName == INVERSE_DISTANCE)
4581  phase = (dist == 0.)? params[0] : 1/dist; // smallest non-zero dist is 1
4582  else if (phaseFuncName == SCALED_DISTANCE)
4583  phase = params[0] * dist;
4584  else if (phaseFuncName == SCALED_INVERSE_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE)
4585  phase = (dist <= REAL_EPS)? params[1] : params[0] / dist; // unless shifted closer to 0
4586  }
4587  }
4588 
4589  // negate phase to conjugate operator
4590  if (conj)
4591  phase *= -1;
4592 
4593  // modify amp to amp * exp(i phase)
4594  c = cos(phase);
4595  s = sin(phase);
4596  re = stateRe[index];
4597  im = stateIm[index];
4598 
4599  // = {re[amp] cos(phase) - im[amp] sin(phase)} + i {re[amp] sin(phase) + im[amp] cos(phase)}
4600  stateRe[index] = re*c - im*s;
4601  stateIm[index] = re*s + im*c;
4602  }
4603  }
4604 }

References Qureg::chunkId, DISTANCE, extractBit(), INVERSE_DISTANCE, INVERSE_NORM, INVERSE_PRODUCT, MAX_NUM_REGS_APPLY_ARBITRARY_PHASE, NORM, Qureg::numAmpsPerChunk, PRODUCT, qreal, SCALED_DISTANCE, SCALED_INVERSE_DISTANCE, SCALED_INVERSE_NORM, SCALED_INVERSE_PRODUCT, SCALED_INVERSE_SHIFTED_DISTANCE, SCALED_INVERSE_SHIFTED_NORM, SCALED_NORM, SCALED_PRODUCT, Qureg::stateVec, TWOS_COMPLEMENT, and UNSIGNED.

Referenced by agnostic_applyQFT(), applyNamedPhaseFunc(), applyNamedPhaseFuncOverrides(), applyParamNamedPhaseFunc(), and applyParamNamedPhaseFuncOverrides().

◆ statevec_applyPauliSum()

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

Definition at line 538 of file QuEST_common.c.

538  {
539 
540  int numQb = inQureg.numQubitsRepresented;
541  int targs[100]; // [numQb];
542  for (int q=0; q < numQb; q++)
543  targs[q] = q;
544 
545  statevec_initBlankState(outQureg);
546 
547  for (int t=0; t < numSumTerms; t++) {
548  Complex coef = (Complex) {.real=termCoeffs[t], .imag=0};
549  Complex iden = (Complex) {.real=1, .imag=0};
550  Complex zero = (Complex) {.real=0, .imag=0};
551 
552  // outQureg += coef paulis(inQureg)
553  statevec_applyPauliProd(inQureg, targs, &allCodes[t*numQb], numQb);
554  statevec_setWeightedQureg(coef, inQureg, iden, outQureg, zero, outQureg);
555 
556  // undero paulis(inQureg), exploiting XX=YY=ZZ=I
557  statevec_applyPauliProd(inQureg, targs, &allCodes[t*numQb], numQb);
558  }
559 }

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

Referenced by applyPauliHamil(), and applyPauliSum().

◆ statevec_applyPhaseFuncOverrides()

void statevec_applyPhaseFuncOverrides ( Qureg  qureg,
int *  qubits,
int  numQubits,
enum bitEncoding  encoding,
qreal coeffs,
qreal exponents,
int  numTerms,
long long int *  overrideInds,
qreal overridePhases,
int  numOverrides,
int  conj 
)

Definition at line 4268 of file QuEST_cpu.c.

4273 {
4274  // each node/chunk modifies only local values in an embarrassingly parallel way
4275 
4276  // thread shared vars
4277  int chunkId = qureg.chunkId;
4278  long long int numAmps = qureg.numAmpsPerChunk;
4279  qreal* stateRe = qureg.stateVec.real;
4280  qreal* stateIm = qureg.stateVec.imag;
4281 
4282  // thread private vars
4283  long long int index, globalAmpInd, phaseInd;
4284  int i, t, q;
4285  qreal phase, c, s, re, im;
4286 
4287 # ifdef _OPENMP
4288 # pragma omp parallel \
4289  default (none) \
4290  shared (chunkId,numAmps, stateRe,stateIm, qubits,numQubits,encoding, coeffs,exponents,numTerms, overrideInds,overridePhases,numOverrides, conj) \
4291  private (index, globalAmpInd, phaseInd, i,t,q, phase, c,s,re,im)
4292 # endif
4293  {
4294 # ifdef _OPENMP
4295 # pragma omp for schedule (static)
4296 # endif
4297  for (index=0LL; index<numAmps; index++) {
4298 
4299  // determine global amplitude index
4300  globalAmpInd = chunkId * numAmps + index;
4301 
4302  // determine phase index of {qubits}
4303  phaseInd = 0LL;
4304  if (encoding == UNSIGNED) {
4305  for (q=0; q<numQubits; q++) // use significance order specified by {qubits}
4306  phaseInd += (1LL << q) * extractBit(qubits[q], globalAmpInd);
4307  }
4308  else if (encoding == TWOS_COMPLEMENT) {
4309  for (q=0; q<numQubits-1; q++) // use final qubit to indicate sign
4310  phaseInd += (1LL << q) * extractBit(qubits[q], globalAmpInd);
4311  if (extractBit(qubits[numQubits-1], globalAmpInd) == 1)
4312  phaseInd -= (1LL << (numQubits-1));
4313  }
4314 
4315  // determine if this phase index has an overriden value (i < numOverrides)
4316  for (i=0; i<numOverrides; i++)
4317  if (phaseInd == overrideInds[i])
4318  break;
4319 
4320  // determine phase from {coeffs}, {exponents} (unless overriden)
4321  phase = 0;
4322  if (i < numOverrides)
4323  phase = overridePhases[i];
4324  else
4325  for (t=0; t<numTerms; t++)
4326  phase += coeffs[t] * pow(phaseInd, exponents[t]);
4327 
4328  // negate phase to conjugate operator
4329  if (conj)
4330  phase *= -1;
4331 
4332  // modify amp to amp * exp(i phase)
4333  c = cos(phase);
4334  s = sin(phase);
4335  re = stateRe[index];
4336  im = stateIm[index];
4337 
4338  // = {re[amp] cos(phase) - im[amp] sin(phase)} + i {re[amp] sin(phase) + im[amp] cos(phase)}
4339  stateRe[index] = re*c - im*s;
4340  stateIm[index] = re*s + im*c;
4341  }
4342  }
4343 }

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

Referenced by applyPhaseFunc(), and applyPhaseFuncOverrides().

◆ statevec_calcExpecDiagonalOp()

Complex statevec_calcExpecDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 1600 of file QuEST_cpu_distributed.c.

1600  {
1601 
1602  Complex localExpec = statevec_calcExpecDiagonalOpLocal(qureg, op);
1603  if (qureg.numChunks == 1)
1604  return localExpec;
1605 
1606  qreal localReal = localExpec.real;
1607  qreal localImag = localExpec.imag;
1608  qreal globalReal, globalImag;
1609  MPI_Allreduce(&localReal, &globalReal, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1610  MPI_Allreduce(&localImag, &globalImag, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1611 
1612  Complex globalExpec;
1613  globalExpec.real = globalReal;
1614  globalExpec.imag = globalImag;
1615  return globalExpec;
1616 }

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 509 of file QuEST_common.c.

509  {
510 
511  statevec_cloneQureg(workspace, qureg);
512  statevec_applyPauliProd(workspace, targetQubits, pauliCodes, numTargets);
513 
514  // compute the expected value
515  qreal value;
516  if (qureg.isDensityMatrix)
517  value = densmatr_calcTotalProb(workspace); // Trace(ops qureg)
518  else
519  value = statevec_calcInnerProduct(workspace, qureg).real; // <qureg|ops|qureg>
520 
521  return value;
522 }

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 524 of file QuEST_common.c.

524  {
525 
526  int numQb = qureg.numQubitsRepresented;
527  int targs[100]; // [numQb];
528  for (int q=0; q < numQb; q++)
529  targs[q] = q;
530 
531  qreal value = 0;
532  for (int t=0; t < numSumTerms; t++)
533  value += termCoeffs[t] * statevec_calcExpecPauliProd(qureg, targs, &allCodes[t*numQb], numQb, workspace);
534 
535  return value;
536 }

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

Referenced by calcExpecPauliHamil(), and calcExpecPauliSum().

◆ statevec_calcFidelity()

qreal statevec_calcFidelity ( Qureg  qureg,
Qureg  pureState 
)

Definition at line 380 of file QuEST_common.c.

380  {
381 
382  Complex innerProd = statevec_calcInnerProduct(qureg, pureState);
383  qreal innerProdMag = innerProd.real*innerProd.real + innerProd.imag*innerProd.imag;
384  return innerProdMag;
385 }

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_calcProbOfAllOutcomes()

void statevec_calcProbOfAllOutcomes ( qreal retProbs,
Qureg  qureg,
int *  qubits,
int  numQubits 
)

Definition at line 1340 of file QuEST_cpu_distributed.c.

1340  {
1341 
1342  // each node populates retProbs with contributions from the subset of amps in each
1343  statevec_calcProbOfAllOutcomesLocal(retProbs, qureg, qubits, numQubits);
1344 
1345  // then, retProbs are summed element-wise
1346  MPI_Allreduce(MPI_IN_PLACE, retProbs, 1LL<<numQubits, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1347 }

References Qureg::numAmpsPerChunk, qreal, and statevec_calcProbOfAllOutcomesLocal().

Referenced by calcProbOfAllOutcomes().

◆ statevec_calcProbOfOutcome()

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

Definition at line 1312 of file QuEST_cpu_distributed.c.

1313 {
1314  qreal stateProb=0, totalStateProb=0;
1315  int skipValuesWithinRank = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, measureQubit);
1316  if (skipValuesWithinRank) {
1317  stateProb = statevec_findProbabilityOfZeroLocal(qureg, measureQubit);
1318  } else {
1319  if (!isChunkToSkipInFindPZero(qureg.chunkId, qureg.numAmpsPerChunk, measureQubit)){
1320  stateProb = statevec_findProbabilityOfZeroDistributed(qureg);
1321  } else stateProb = 0;
1322  }
1323  MPI_Allreduce(&stateProb, &totalStateProb, 1, MPI_QuEST_REAL, MPI_SUM, MPI_COMM_WORLD);
1324  if (outcome==1) totalStateProb = 1.0 - totalStateProb;
1325  return totalStateProb;
1326 }

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 1572 of file QuEST_cpu.c.

1572  {
1573 
1574  // registers are equal sized, so nodes hold the same state-vector partitions
1575  long long int stateVecSize;
1576  long long int index;
1577 
1578  // dimension of the state vector
1579  stateVecSize = targetQureg.numAmpsPerChunk;
1580 
1581  // Can't use qureg->stateVec as a private OMP var
1582  qreal *targetStateVecReal = targetQureg.stateVec.real;
1583  qreal *targetStateVecImag = targetQureg.stateVec.imag;
1584  qreal *copyStateVecReal = copyQureg.stateVec.real;
1585  qreal *copyStateVecImag = copyQureg.stateVec.imag;
1586 
1587  // initialise the state to |0000..0000>
1588 # ifdef _OPENMP
1589 # pragma omp parallel \
1590  default (none) \
1591  shared (stateVecSize, targetStateVecReal, targetStateVecImag, copyStateVecReal, copyStateVecImag) \
1592  private (index)
1593 # endif
1594  {
1595 # ifdef _OPENMP
1596 # pragma omp for schedule (static)
1597 # endif
1598  for (index=0; index<stateVecSize; index++) {
1599  targetStateVecReal[index] = copyStateVecReal[index];
1600  targetStateVecImag[index] = copyStateVecImag[index];
1601  }
1602  }
1603 }

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 1368 of file QuEST_cpu_distributed.c.

1369 {
1370  int skipValuesWithinRank = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, measureQubit);
1371  if (skipValuesWithinRank) {
1372  statevec_collapseToKnownProbOutcomeLocal(qureg, measureQubit, outcome, totalStateProb);
1373  } else {
1374  if (!isChunkToSkipInFindPZero(qureg.chunkId, qureg.numAmpsPerChunk, measureQubit)){
1375  // chunk has amps for q=0
1376  if (outcome==0) statevec_collapseToKnownProbOutcomeDistributedRenorm(qureg, measureQubit,
1377  totalStateProb);
1379  } else {
1380  // chunk has amps for q=1
1381  if (outcome==1) statevec_collapseToKnownProbOutcomeDistributedRenorm(qureg, measureQubit,
1382  totalStateProb);
1384  }
1385  }
1386 }

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

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

◆ statevec_compactUnitary()

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

Definition at line 858 of file QuEST_cpu_distributed.c.

859 {
860  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
861  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
862  Complex rot1, rot2;
863 
864  // rank's chunk is in upper half of block
865  int rankIsUpper;
866  int pairRank; // rank of corresponding chunk
867 
868  if (useLocalDataOnly){
869  // all values required to update state vector lie in this rank
870  statevec_compactUnitaryLocal(qureg, targetQubit, alpha, beta);
871  } else {
872  // need to get corresponding chunk of state vector from other rank
873  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
874  getRotAngle(rankIsUpper, &rot1, &rot2, alpha, beta);
875  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
876  // get corresponding values from my pair
877  exchangeStateVectors(qureg, pairRank);
878 
879  // this rank's values are either in the upper of lower half of the block.
880  // send values to compactUnitaryDistributed in the correct order
881  if (rankIsUpper){
882  statevec_compactUnitaryDistributed(qureg,rot1,rot2,
883  qureg.stateVec, //upper
884  qureg.pairStateVec, //lower
885  qureg.stateVec); //output
886  } else {
887  statevec_compactUnitaryDistributed(qureg,rot1,rot2,
888  qureg.pairStateVec, //upper
889  qureg.stateVec, //lower
890  qureg.stateVec); //output
891  }
892  }
893 }

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 1741 of file QuEST_cpu.c.

1741  {
1742  qreal diff;
1743  long long int chunkSize = mq1.numAmpsPerChunk;
1744 
1745  for (long long int i=0; i<chunkSize; i++){
1746  diff = absReal(mq1.stateVec.real[i] - mq2.stateVec.real[i]);
1747  if (diff>precision) return 0;
1748  diff = absReal(mq1.stateVec.imag[i] - mq2.stateVec.imag[i]);
1749  if (diff>precision) return 0;
1750  }
1751  return 1;
1752 }

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 934 of file QuEST_cpu_distributed.c.

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

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 579 of file QuEST_common.c.

579  {
580 
581  long long int ctrlMask = 1LL << ctrl;
582  statevec_multiControlledMultiQubitUnitary(qureg, ctrlMask, targets, numTargets, u);
583 }

References statevec_multiControlledMultiQubitUnitary().

Referenced by controlledMultiQubitUnitary().

◆ statevec_controlledNot()

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

Definition at line 1075 of file QuEST_cpu_distributed.c.

1076 {
1077  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1078  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1079  int rankIsUpper; // rank's chunk is in upper half of block
1080  int pairRank; // rank of corresponding chunk
1081 
1082  if (useLocalDataOnly){
1083  // all values required to update state vector lie in this rank
1084  statevec_controlledNotLocal(qureg, controlQubit, targetQubit);
1085  } else {
1086  // need to get corresponding chunk of state vector from other rank
1087  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1088  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1089  // get corresponding values from my pair
1090  exchangeStateVectors(qureg, pairRank);
1091  statevec_controlledNotDistributed(qureg,controlQubit,
1092  qureg.pairStateVec, //in
1093  qureg.stateVec); //out
1094  }
1095 }

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 1192 of file QuEST_cpu_distributed.c.

1193 {
1194  int conjFac = 1;
1195 
1196  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1197  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1198  int rankIsUpper; // rank's chunk is in upper half of block
1199  int pairRank; // rank of corresponding chunk
1200 
1201  if (useLocalDataOnly){
1202  // all values required to update state vector lie in this rank
1203  statevec_controlledPauliYLocal(qureg, controlQubit, targetQubit, conjFac);
1204  } else {
1205  // need to get corresponding chunk of state vector from other rank
1206  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1207  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1208  // get corresponding values from my pair
1209  exchangeStateVectors(qureg, pairRank);
1210  // this rank's values are either in the upper of lower half of the block
1211  if (rankIsUpper){
1212  statevec_controlledPauliYDistributed(qureg,controlQubit,
1213  qureg.pairStateVec, //in
1214  qureg.stateVec,
1215  conjFac); //out
1216  } else {
1217  statevec_controlledPauliYDistributed(qureg,controlQubit,
1218  qureg.pairStateVec, //in
1219  qureg.stateVec,
1220  - conjFac); //out
1221  }
1222  }
1223 }

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 1225 of file QuEST_cpu_distributed.c.

1226 {
1227  int conjFac = -1;
1228 
1229  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1230  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1231  int rankIsUpper; // rank's chunk is in upper half of block
1232  int pairRank; // rank of corresponding chunk
1233 
1234  if (useLocalDataOnly){
1235  // all values required to update state vector lie in this rank
1236  statevec_controlledPauliYLocal(qureg, controlQubit, targetQubit, conjFac);
1237  } else {
1238  // need to get corresponding chunk of state vector from other rank
1239  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1240  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1241  // get corresponding values from my pair
1242  exchangeStateVectors(qureg, pairRank);
1243  // this rank's values are either in the upper of lower half of the block
1244  if (rankIsUpper){
1245  statevec_controlledPauliYDistributed(qureg,controlQubit,
1246  qureg.pairStateVec, //in
1247  qureg.stateVec,
1248  conjFac); //out
1249  } else {
1250  statevec_controlledPauliYDistributed(qureg,controlQubit,
1251  qureg.pairStateVec, //in
1252  qureg.stateVec,
1253  - conjFac); //out
1254  }
1255  }
1256 }

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 3687 of file QuEST_cpu.c.

3688 {
3689  long long int index;
3690  long long int stateVecSize;
3691  int bit1, bit2;
3692 
3693  long long int chunkSize=qureg.numAmpsPerChunk;
3694  long long int chunkId=qureg.chunkId;
3695 
3696  // dimension of the state vector
3697  stateVecSize = qureg.numAmpsPerChunk;
3698  qreal *stateVecReal = qureg.stateVec.real;
3699  qreal *stateVecImag = qureg.stateVec.imag;
3700 
3701 # ifdef _OPENMP
3702 # pragma omp parallel for \
3703  default (none) \
3704  shared (stateVecSize, stateVecReal,stateVecImag, chunkId,chunkSize,idQubit1,idQubit2 ) \
3705  private (index,bit1,bit2) \
3706  schedule (static)
3707 # endif
3708  for (index=0; index<stateVecSize; index++) {
3709  bit1 = extractBit (idQubit1, index+chunkId*chunkSize);
3710  bit2 = extractBit (idQubit2, index+chunkId*chunkSize);
3711  if (bit1 && bit2) {
3712  stateVecReal [index] = - stateVecReal [index];
3713  stateVecImag [index] = - stateVecImag [index];
3714  }
3715  }
3716 }

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 3226 of file QuEST_cpu.c.

3227 {
3228  long long int index;
3229  long long int stateVecSize;
3230  int bit1, bit2;
3231 
3232  long long int chunkSize=qureg.numAmpsPerChunk;
3233  long long int chunkId=qureg.chunkId;
3234 
3235  // dimension of the state vector
3236  stateVecSize = qureg.numAmpsPerChunk;
3237  qreal *stateVecReal = qureg.stateVec.real;
3238  qreal *stateVecImag = qureg.stateVec.imag;
3239 
3240  qreal stateRealLo, stateImagLo;
3241  qreal cosAngle = cos(angle);
3242  qreal sinAngle = sin(angle);
3243 
3244 # ifdef _OPENMP
3245 # pragma omp parallel for \
3246  default (none) \
3247  shared (stateVecSize, stateVecReal,stateVecImag, chunkId,chunkSize, \
3248  idQubit1,idQubit2,cosAngle,sinAngle ) \
3249  private (index,bit1,bit2,stateRealLo,stateImagLo) \
3250  schedule (static)
3251 # endif
3252  for (index=0; index<stateVecSize; index++) {
3253  bit1 = extractBit (idQubit1, index+chunkId*chunkSize);
3254  bit2 = extractBit (idQubit2, index+chunkId*chunkSize);
3255  if (bit1 && bit2) {
3256 
3257  stateRealLo = stateVecReal[index];
3258  stateImagLo = stateVecImag[index];
3259 
3260  stateVecReal[index] = cosAngle*stateRealLo - sinAngle*stateImagLo;
3261  stateVecImag[index] = sinAngle*stateRealLo + cosAngle*stateImagLo;
3262  }
3263  }
3264 }

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 330 of file QuEST_common.c.

330  {
331 
332  Complex alpha, beta;
333  getComplexPairFromRotation(angle, axis, &alpha, &beta);
334  statevec_controlledCompactUnitary(qureg, controlQubit, targetQubit, alpha, beta);
335 }

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 337 of file QuEST_common.c.

337  {
338 
339  Complex alpha, beta;
340  getComplexPairFromRotation(angle, axis, &alpha, &beta);
341  alpha.imag *= -1;
342  beta.imag *= -1;
343  statevec_controlledCompactUnitary(qureg, controlQubit, targetQubit, alpha, beta);
344 }

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 346 of file QuEST_common.c.

346  {
347 
348  Vector unitAxis = {1, 0, 0};
349  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
350 }

References statevec_controlledRotateAroundAxis().

Referenced by controlledRotateX().

◆ statevec_controlledRotateY()

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

Definition at line 352 of file QuEST_common.c.

352  {
353 
354  Vector unitAxis = {0, 1, 0};
355  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
356 }

References statevec_controlledRotateAroundAxis().

Referenced by controlledRotateY().

◆ statevec_controlledRotateZ()

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

Definition at line 358 of file QuEST_common.c.

358  {
359 
360  Vector unitAxis = {0, 0, 1};
361  statevec_controlledRotateAroundAxis(qureg, controlQubit, targetQubit, angle, unitAxis);
362 }

References statevec_controlledRotateAroundAxis().

Referenced by controlledRotateZ().

◆ statevec_controlledTwoQubitUnitary()

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

Definition at line 567 of file QuEST_common.c.

567  {
568 
569  long long int ctrlMask = 1LL << controlQubit;
570  statevec_multiControlledTwoQubitUnitary(qureg, ctrlMask, targetQubit1, targetQubit2, u);
571 }

References statevec_multiControlledTwoQubitUnitary().

Referenced by controlledTwoQubitUnitary().

◆ statevec_controlledUnitary()

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

Definition at line 972 of file QuEST_cpu_distributed.c.

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

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 1290 of file QuEST_cpu.c.

1291 {
1292  long long int numAmps = 1LL << numQubits;
1293  long long int numAmpsPerRank = numAmps/env.numRanks;
1294 
1295  if (numAmpsPerRank > SIZE_MAX) {
1296  printf("Could not allocate memory (cannot fit numAmps into size_t)!");
1297  exit (EXIT_FAILURE);
1298  }
1299 
1300  size_t arrSize = (size_t) (numAmpsPerRank * sizeof(*(qureg->stateVec.real)));
1301  qureg->stateVec.real = malloc(arrSize);
1302  qureg->stateVec.imag = malloc(arrSize);
1303  if (env.numRanks>1){
1304  qureg->pairStateVec.real = malloc(arrSize);
1305  qureg->pairStateVec.imag = malloc(arrSize);
1306  }
1307 
1308  if ( (!(qureg->stateVec.real) || !(qureg->stateVec.imag))
1309  && numAmpsPerRank ) {
1310  printf("Could not allocate memory!");
1311  exit (EXIT_FAILURE);
1312  }
1313 
1314  if ( env.numRanks>1 && (!(qureg->pairStateVec.real) || !(qureg->pairStateVec.imag))
1315  && numAmpsPerRank ) {
1316  printf("Could not allocate memory!");
1317  exit (EXIT_FAILURE);
1318  }
1319 
1320  qureg->numQubitsInStateVec = numQubits;
1321  qureg->numAmpsTotal = numAmps;
1322  qureg->numAmpsPerChunk = numAmpsPerRank;
1323  qureg->chunkId = env.rank;
1324  qureg->numChunks = env.numRanks;
1325  qureg->isDensityMatrix = 0;
1326 }

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 1328 of file QuEST_cpu.c.

1328  {
1329 
1330  qureg.numQubitsInStateVec = 0;
1331  qureg.numAmpsTotal = 0;
1332  qureg.numAmpsPerChunk = 0;
1333 
1334  free(qureg.stateVec.real);
1335  free(qureg.stateVec.imag);
1336  if (env.numRanks>1){
1337  free(qureg.pairStateVec.real);
1338  free(qureg.pairStateVec.imag);
1339  }
1340  qureg.stateVec.real = NULL;
1341  qureg.stateVec.imag = NULL;
1342  qureg.pairStateVec.real = NULL;
1343  qureg.pairStateVec.imag = NULL;
1344 }

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 222 of file QuEST_cpu_distributed.c.

222  {
223  int chunkId = getChunkIdFromIndex(qureg, index);
224  qreal el;
225  if (qureg.chunkId==chunkId){
226  el = qureg.stateVec.imag[index-chunkId*qureg.numAmpsPerChunk];
227  }
228  MPI_Bcast(&el, 1, MPI_QuEST_REAL, chunkId, MPI_COMM_WORLD);
229  return el;
230 }

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 248 of file QuEST_common.c.

248  {
249  qreal real = statevec_getRealAmp(qureg, index);
250  qreal imag = statevec_getImagAmp(qureg, index);
251  return real*real + imag*imag;
252 }

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

Referenced by getProbAmp().

◆ statevec_getRealAmp()

qreal statevec_getRealAmp ( Qureg  qureg,
long long int  index 
)

Definition at line 212 of file QuEST_cpu_distributed.c.

212  {
213  int chunkId = getChunkIdFromIndex(qureg, index);
214  qreal el;
215  if (qureg.chunkId==chunkId){
216  el = qureg.stateVec.real[index-chunkId*qureg.numAmpsPerChunk];
217  }
218  MPI_Bcast(&el, 1, MPI_QuEST_REAL, chunkId, MPI_COMM_WORLD);
219  return el;
220 }

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 1258 of file QuEST_cpu_distributed.c.

1259 {
1260  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1261  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1262 
1263  // rank's chunk is in upper half of block
1264  int rankIsUpper;
1265  int pairRank; // rank of corresponding chunk
1266 
1267  if (useLocalDataOnly){
1268  // all values required to update state vector lie in this rank
1269  statevec_hadamardLocal(qureg, targetQubit);
1270  } else {
1271  // need to get corresponding chunk of state vector from other rank
1272  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1273  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1274  //printf("%d rank has pair rank: %d\n", qureg.rank, pairRank);
1275  // get corresponding values from my pair
1276  exchangeStateVectors(qureg, pairRank);
1277  // this rank's values are either in the upper of lower half of the block. send values to hadamardDistributed
1278  // in the correct order
1279  if (rankIsUpper){
1281  qureg.stateVec, //upper
1282  qureg.pairStateVec, //lower
1283  qureg.stateVec, rankIsUpper); //output
1284  } else {
1286  qureg.pairStateVec, //upper
1287  qureg.stateVec, //lower
1288  qureg.stateVec, rankIsUpper); //output
1289  }
1290  }
1291 }

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

Referenced by agnostic_applyQFT(), and hadamard().

◆ statevec_initBlankState()

void statevec_initBlankState ( Qureg  qureg)

Definition at line 1464 of file QuEST_cpu.c.

1465 {
1466  long long int stateVecSize;
1467  long long int index;
1468 
1469  // dimension of the state vector
1470  stateVecSize = qureg.numAmpsPerChunk;
1471 
1472  // Can't use qureg->stateVec as a private OMP var
1473  qreal *stateVecReal = qureg.stateVec.real;
1474  qreal *stateVecImag = qureg.stateVec.imag;
1475 
1476  // initialise the state-vector to all-zeroes
1477 # ifdef _OPENMP
1478 # pragma omp parallel \
1479  default (none) \
1480  shared (stateVecSize, stateVecReal, stateVecImag) \
1481  private (index)
1482 # endif
1483  {
1484 # ifdef _OPENMP
1485 # pragma omp for schedule (static)
1486 # endif
1487  for (index=0; index<stateVecSize; index++) {
1488  stateVecReal[index] = 0.0;
1489  stateVecImag[index] = 0.0;
1490  }
1491  }
1492 }

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 1536 of file QuEST_cpu.c.

1537 {
1538  long long int stateVecSize;
1539  long long int index;
1540 
1541  // dimension of the state vector
1542  stateVecSize = qureg.numAmpsPerChunk;
1543 
1544  // Can't use qureg->stateVec as a private OMP var
1545  qreal *stateVecReal = qureg.stateVec.real;
1546  qreal *stateVecImag = qureg.stateVec.imag;
1547 
1548  // initialise the state to vector to all zeros
1549 # ifdef _OPENMP
1550 # pragma omp parallel \
1551  default (none) \
1552  shared (stateVecSize, stateVecReal, stateVecImag) \
1553  private (index)
1554 # endif
1555  {
1556 # ifdef _OPENMP
1557 # pragma omp for schedule (static)
1558 # endif
1559  for (index=0; index<stateVecSize; index++) {
1560  stateVecReal[index] = 0.0;
1561  stateVecImag[index] = 0.0;
1562  }
1563  }
1564 
1565  // give the specified classical state prob 1
1566  if (qureg.chunkId == stateInd/stateVecSize){
1567  stateVecReal[stateInd % stateVecSize] = 1.0;
1568  stateVecImag[stateInd % stateVecSize] = 0.0;
1569  }
1570 }

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 1657 of file QuEST_cpu.c.

1658 {
1659  long long int chunkSize;
1660  long long int index;
1661  long long int indexOffset;
1662 
1663  // dimension of the state vector
1664  chunkSize = qureg.numAmpsPerChunk;
1665 
1666  // Can't use qureg->stateVec as a private OMP var
1667  qreal *stateVecReal = qureg.stateVec.real;
1668  qreal *stateVecImag = qureg.stateVec.imag;
1669 
1670  indexOffset = chunkSize * qureg.chunkId;
1671 
1672  // initialise the state to |0000..0000>
1673 # ifdef _OPENMP
1674 # pragma omp parallel \
1675  default (none) \
1676  shared (chunkSize, stateVecReal, stateVecImag, indexOffset) \
1677  private (index)
1678 # endif
1679  {
1680 # ifdef _OPENMP
1681 # pragma omp for schedule (static)
1682 # endif
1683  for (index=0; index<chunkSize; index++) {
1684  stateVecReal[index] = ((indexOffset + index)*2.0)/10.0;
1685  stateVecImag[index] = ((indexOffset + index)*2.0+1.0)/10.0;
1686  }
1687  }
1688 }

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

Referenced by initDebugState().

◆ statevec_initPlusState()

void statevec_initPlusState ( Qureg  qureg)

Definition at line 1504 of file QuEST_cpu.c.

1505 {
1506  long long int chunkSize, stateVecSize;
1507  long long int index;
1508 
1509  // dimension of the state vector
1510  chunkSize = qureg.numAmpsPerChunk;
1511  stateVecSize = chunkSize*qureg.numChunks;
1512  qreal normFactor = 1.0/sqrt((qreal)stateVecSize);
1513 
1514  // Can't use qureg->stateVec as a private OMP var
1515  qreal *stateVecReal = qureg.stateVec.real;
1516  qreal *stateVecImag = qureg.stateVec.imag;
1517 
1518  // initialise the state to |+++..+++> = 1/normFactor {1, 1, 1, ...}
1519 # ifdef _OPENMP
1520 # pragma omp parallel \
1521  default (none) \
1522  shared (chunkSize, stateVecReal, stateVecImag, normFactor) \
1523  private (index)
1524 # endif
1525  {
1526 # ifdef _OPENMP
1527 # pragma omp for schedule (static)
1528 # endif
1529  for (index=0; index<chunkSize; index++) {
1530  stateVecReal[index] = normFactor;
1531  stateVecImag[index] = 0.0;
1532  }
1533  }
1534 }

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 1691 of file QuEST_cpu.c.

1691  {
1692  long long int chunkSize, stateVecSize;
1693  long long int indexInChunk, totalIndex;
1694 
1695  chunkSize = qureg->numAmpsPerChunk;
1696  stateVecSize = chunkSize*qureg->numChunks;
1697 
1698  qreal *stateVecReal = qureg->stateVec.real;
1699  qreal *stateVecImag = qureg->stateVec.imag;
1700 
1701  FILE *fp;
1702  char line[200];
1703 
1704  for (int rank=0; rank<(qureg->numChunks); rank++){
1705  if (rank==qureg->chunkId){
1706  fp = fopen(filename, "r");
1707 
1708  // indicate file open failure
1709  if (fp == NULL)
1710  return 0;
1711 
1712  indexInChunk = 0; totalIndex = 0;
1713  while (fgets(line, sizeof(char)*200, fp) != NULL && totalIndex<stateVecSize){
1714  if (line[0]!='#'){
1715  int chunkId = (int) (totalIndex/chunkSize);
1716  if (chunkId==qureg->chunkId){
1717  # if QuEST_PREC==1
1718  sscanf(line, "%f, %f", &(stateVecReal[indexInChunk]),
1719  &(stateVecImag[indexInChunk]));
1720  # elif QuEST_PREC==2
1721  sscanf(line, "%lf, %lf", &(stateVecReal[indexInChunk]),
1722  &(stateVecImag[indexInChunk]));
1723  # elif QuEST_PREC==4
1724  sscanf(line, "%Lf, %Lf", &(stateVecReal[indexInChunk]),
1725  &(stateVecImag[indexInChunk]));
1726  # endif
1727  indexInChunk += 1;
1728  }
1729  totalIndex += 1;
1730  }
1731  }
1732  fclose(fp);
1733  }
1734  syncQuESTEnv(env);
1735  }
1736 
1737  // indicate success
1738  return 1;
1739 }

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]outcomeof qubit 'qubitId'

Definition at line 1611 of file QuEST_cpu.c.

1612 {
1613  long long int chunkSize, stateVecSize;
1614  long long int index;
1615  int bit;
1616  long long int chunkId=qureg->chunkId;
1617 
1618  // dimension of the state vector
1619  chunkSize = qureg->numAmpsPerChunk;
1620  stateVecSize = chunkSize*qureg->numChunks;
1621  qreal normFactor = 1.0/sqrt((qreal)stateVecSize/2.0);
1622 
1623  // Can't use qureg->stateVec as a private OMP var
1624  qreal *stateVecReal = qureg->stateVec.real;
1625  qreal *stateVecImag = qureg->stateVec.imag;
1626 
1627  // initialise the state to |0000..0000>
1628 # ifdef _OPENMP
1629 # pragma omp parallel \
1630  default (none) \
1631  shared (chunkSize, stateVecReal, stateVecImag, normFactor, qubitId, outcome, chunkId) \
1632  private (index, bit)
1633 # endif
1634  {
1635 # ifdef _OPENMP
1636 # pragma omp for schedule (static)
1637 # endif
1638  for (index=0; index<chunkSize; index++) {
1639  bit = extractBit(qubitId, index+chunkId*chunkSize);
1640  if (bit==outcome) {
1641  stateVecReal[index] = normFactor;
1642  stateVecImag[index] = 0.0;
1643  } else {
1644  stateVecReal[index] = 0.0;
1645  stateVecImag[index] = 0.0;
1646  }
1647  }
1648  }
1649 }

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 1494 of file QuEST_cpu.c.

1495 {
1496  statevec_initBlankState(qureg);
1497  if (qureg.chunkId==0){
1498  // zero state |0000..0000> has probability 1
1499  qureg.stateVec.real[0] = 1.0;
1500  qureg.stateVec.imag[0] = 0.0;
1501  }
1502 }

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 364 of file QuEST_common.c.

364  {
365 
366  qreal zeroProb = statevec_calcProbOfOutcome(qureg, measureQubit, 0);
367  int outcome = generateMeasurementOutcome(zeroProb, outcomeProb);
368  statevec_collapseToKnownProbOutcome(qureg, measureQubit, outcome, *outcomeProb);
369  return outcome;
370 }

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

Referenced by measure(), and measureWithStats().

◆ statevec_multiControlledMultiQubitNot()

void statevec_multiControlledMultiQubitNot ( Qureg  qureg,
int  ctrlMask,
int  targMask 
)

Definition at line 1097 of file QuEST_cpu_distributed.c.

1098 {
1099  /* operation is the same regardless of control and target ordering, hence
1100  * we accept only bitMasks (for convenience of caller, when shifting qubits
1101  * for density matrices)
1102  */
1103 
1104  // global index of the first basis state in this node
1105  long long int firstInd = qureg.chunkId * qureg.numAmpsPerChunk;
1106 
1107  /* optimisation: if this node doesn't contain any amplitudes for which {ctrls}={1}
1108  * (and hence, neither does the pair node), then these pair nodes have nothing to modify
1109  * nor any need to communicate, and can halt. No ctrls are contained in the node
1110  * if the distance from the first index, to the next index where {ctrls}=1, is
1111  * greater than the total contained amplitudes. This is a worthwhile optimisation,
1112  * since although we must still wait for the slowest node, we have potentially reduced
1113  * the network traffic and might avoid saturation.
1114  */
1115  if ((firstInd|ctrlMask) - firstInd >= qureg.numAmpsPerChunk)
1116  return;
1117 
1118  /* nodes communicate pairwise, and (ignoring ctrls) swap all their amplitudes with mate.
1119  * hence we find |pairState> = X_{targs}|firstStateInNode>, determine which node contains
1120  * |pairState>, and swap state-vector with it (unless it happens to be this node).
1121  */
1122 
1123  // global index of the corresponding NOT'd first basis state
1124  long long int pairInd = firstInd ^ targMask;
1125  int pairRank = pairInd / qureg.numAmpsPerChunk;
1126  int useLocalDataOnly = (pairRank == qureg.chunkId);
1127 
1128  if (useLocalDataOnly) {
1129  // swaps amplitudes locally, setting |a>=X|b>, and |b>=X|a>
1130  statevec_multiControlledMultiQubitNotLocal(qureg, ctrlMask, targMask);
1131  } else {
1132  // swaps amplitudes with pair node
1133  exchangeStateVectors(qureg, pairRank);
1134  // modifies only |a>=X|b> (pair node handles the converse)
1136  qureg, ctrlMask, targMask,
1137  qureg.pairStateVec, // in
1138  qureg.stateVec); // out
1139  }
1140 }

References Qureg::chunkId, exchangeStateVectors(), Qureg::numAmpsPerChunk, Qureg::pairStateVec, qreal, Qureg::stateVec, statevec_multiControlledMultiQubitNotDistributed(), and statevec_multiControlledMultiQubitNotLocal().

Referenced by multiControlledMultiQubitNot(), and multiQubitNot().

◆ 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 1514 of file QuEST_cpu_distributed.c.

1514  {
1515 
1516  // bit mask of target qubits (for quick collision checking)
1517  long long int targMask = getQubitBitMask(targs, numTargs);
1518 
1519  // find lowest qubit available for swapping (isn't in targs)
1520  int freeQb=0;
1521  while (maskContainsBit(targMask, freeQb))
1522  freeQb++;
1523 
1524  // assign indices of where each target will be swapped to (else itself)
1525  int swapTargs[numTargs];
1526  for (int t=0; t<numTargs; t++) {
1527  if (halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targs[t]))
1528  swapTargs[t] = targs[t];
1529  else {
1530  // mark swap
1531  swapTargs[t] = freeQb;
1532 
1533  // update ctrlMask if swapped-out qubit was a control
1534  if (maskContainsBit(ctrlMask, swapTargs[t]))
1535  ctrlMask = flipBit(flipBit(ctrlMask, swapTargs[t]), targs[t]); // swap targ and ctrl
1536 
1537  // locate next available on-chunk qubit
1538  freeQb++;
1539  while (maskContainsBit(targMask, freeQb))
1540  freeQb++;
1541  }
1542  }
1543 
1544  // perform swaps as necessary
1545  for (int t=0; t<numTargs; t++)
1546  if (swapTargs[t] != targs[t])
1547  statevec_swapQubitAmps(qureg, targs[t], swapTargs[t]);
1548 
1549  // all target qubits have now been swapped into local memory
1550  statevec_multiControlledMultiQubitUnitaryLocal(qureg, ctrlMask, swapTargs, numTargs, u);
1551 
1552  // undo swaps
1553  for (int t=0; t<numTargs; t++)
1554  if (swapTargs[t] != targs[t])
1555  statevec_swapQubitAmps(qureg, targs[t], swapTargs[t]);
1556 }

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_multiControlledMultiRotatePauli()

void statevec_multiControlledMultiRotatePauli ( Qureg  qureg,
long long int  ctrlMask,
int *  targetQubits,
enum pauliOpType targetPaulis,
int  numTargets,
qreal  angle,
int  applyConj 
)

Definition at line 453 of file QuEST_common.c.

456  {
457  qreal fac = 1/sqrt(2);
458  qreal sgn = (applyConj)? 1 : -1;
459  ComplexMatrix2 uRx = {.real={{fac,0},{0,fac}}, .imag={{0,sgn*fac},{sgn*fac,0}}}; // Rx(pi/2)* rotates Z -> Y
460  ComplexMatrix2 uRy = {.real={{fac,fac},{-fac,fac}}, .imag={{0,0},{0,0}}}; // Ry(-pi/2) rotates Z -> X
461 
462  // this function is controlled on the all-one state, so no ctrl flips
463  long long int ctrlFlipMask = 0;
464 
465  // mask may be modified to remove superfluous Identity ops
466  long long int targMask = getQubitBitMask(targetQubits, numTargets);
467 
468  // rotate basis so that exp(Z) will effect exp(Y) and exp(X)
469  for (int t=0; t < numTargets; t++) {
470  if (targetPaulis[t] == PAULI_I)
471  targMask -= 1LL << targetQubits[t]; // remove target from mask
472  if (targetPaulis[t] == PAULI_X)
473  statevec_multiControlledUnitary(qureg, ctrlMask, ctrlFlipMask, targetQubits[t], uRy);
474  if (targetPaulis[t] == PAULI_Y)
475  statevec_multiControlledUnitary(qureg, ctrlMask, ctrlFlipMask, targetQubits[t], uRx);
476  // (targetPaulis[t] == 3) is Z basis
477  }
478 
479  // does nothing if there are no qubits to 'rotate'
480  if (targMask != 0)
481  statevec_multiControlledMultiRotateZ(qureg, ctrlMask, targMask, (applyConj)? -angle : angle);
482 
483  // undo X and Y basis rotations
484  uRx.imag[0][1] *= -1; uRx.imag[1][0] *= -1;
485  uRy.real[0][1] *= -1; uRy.real[1][0] *= -1;
486  for (int t=0; t < numTargets; t++) {
487  if (targetPaulis[t] == PAULI_X)
488  statevec_multiControlledUnitary(qureg, ctrlMask, ctrlFlipMask, targetQubits[t], uRy);
489  if (targetPaulis[t] == PAULI_Y)
490  statevec_multiControlledUnitary(qureg, ctrlMask, ctrlFlipMask, targetQubits[t], uRx);
491  }
492 }

References getQubitBitMask(), ComplexMatrix2::imag, PAULI_I, PAULI_X, PAULI_Y, qreal, ComplexMatrix2::real, statevec_multiControlledMultiRotateZ(), and statevec_multiControlledUnitary().

Referenced by multiControlledMultiRotatePauli().

◆ statevec_multiControlledMultiRotateZ()

void statevec_multiControlledMultiRotateZ ( Qureg  qureg,
long long int  ctrlMask,
long long int  targMask,
qreal  angle 
)

Definition at line 3358 of file QuEST_cpu.c.

3359 {
3360  long long int offset = qureg.chunkId * qureg.numAmpsPerChunk;
3361 
3362  long long int stateVecSize = qureg.numAmpsPerChunk;
3363  qreal *stateVecReal = qureg.stateVec.real;
3364  qreal *stateVecImag = qureg.stateVec.imag;
3365 
3366  qreal stateReal, stateImag;
3367  qreal cosAngle = cos(angle/2.0);
3368  qreal sinAngle = sin(angle/2.0);
3369 
3370  // = +-1, to flip sinAngle based on target qubit parity, to effect
3371  // exp(-angle/2 i fac_j)|j>
3372  int fac;
3373  long long int index, globalIndex;
3374 
3375 # ifdef _OPENMP
3376 # pragma omp parallel \
3377  default (none) \
3378  shared (offset, stateVecSize, stateVecReal,stateVecImag, ctrlMask,targMask, cosAngle,sinAngle) \
3379  private (index,globalIndex, fac, stateReal,stateImag)
3380 # endif
3381  {
3382 # ifdef _OPENMP
3383 # pragma omp for schedule (static)
3384 # endif
3385  for (index=0; index<stateVecSize; index++) {
3386  stateReal = stateVecReal[index];
3387  stateImag = stateVecImag[index];
3388 
3389  // states with not-all-one control qubits are unmodified
3390  globalIndex = index + offset;
3391  if (ctrlMask && ((ctrlMask & globalIndex) != ctrlMask))
3392  continue;
3393 
3394  // odd-parity target qubits get fac_j = -1 (avoid thread divergence)
3395  fac = 1-2*getBitMaskParity(targMask & globalIndex);
3396  stateVecReal[index] = cosAngle*stateReal + fac * sinAngle*stateImag;
3397  stateVecImag[index] = - fac * sinAngle*stateReal + cosAngle*stateImag;
3398  }
3399  }
3400 }

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

Referenced by multiControlledMultiRotateZ(), and statevec_multiControlledMultiRotatePauli().

◆ statevec_multiControlledPhaseFlip()

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

Definition at line 3718 of file QuEST_cpu.c.

3719 {
3720  long long int index;
3721  long long int stateVecSize;
3722 
3723  long long int chunkSize=qureg.numAmpsPerChunk;
3724  long long int chunkId=qureg.chunkId;
3725 
3726  long long int mask = getQubitBitMask(controlQubits, numControlQubits);
3727 
3728  stateVecSize = qureg.numAmpsPerChunk;
3729  qreal *stateVecReal = qureg.stateVec.real;
3730  qreal *stateVecImag = qureg.stateVec.imag;
3731 
3732 # ifdef _OPENMP
3733 # pragma omp parallel \
3734  default (none) \
3735  shared (stateVecSize, stateVecReal,stateVecImag, mask, chunkId,chunkSize ) \
3736  private (index)
3737 # endif
3738  {
3739 # ifdef _OPENMP
3740 # pragma omp for schedule (static)
3741 # endif
3742  for (index=0; index<stateVecSize; index++) {
3743  if (mask == (mask & (index+chunkId*chunkSize)) ){
3744  stateVecReal [index] = - stateVecReal [index];
3745  stateVecImag [index] = - stateVecImag [index];
3746  }
3747  }
3748  }
3749 }

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 3266 of file QuEST_cpu.c.

3267 {
3268  long long int index;
3269  long long int stateVecSize;
3270 
3271  long long int chunkSize=qureg.numAmpsPerChunk;
3272  long long int chunkId=qureg.chunkId;
3273 
3274  long long int mask = getQubitBitMask(controlQubits, numControlQubits);
3275 
3276  stateVecSize = qureg.numAmpsPerChunk;
3277  qreal *stateVecReal = qureg.stateVec.real;
3278  qreal *stateVecImag = qureg.stateVec.imag;
3279 
3280  qreal stateRealLo, stateImagLo;
3281  qreal cosAngle = cos(angle);
3282  qreal sinAngle = sin(angle);
3283 
3284 # ifdef _OPENMP
3285 # pragma omp parallel \
3286  default (none) \
3287  shared (stateVecSize, stateVecReal, stateVecImag, mask, chunkId,chunkSize,cosAngle,sinAngle) \
3288  private (index, stateRealLo, stateImagLo)
3289 # endif
3290  {
3291 # ifdef _OPENMP
3292 # pragma omp for schedule (static)
3293 # endif
3294  for (index=0; index<stateVecSize; index++) {
3295  if (mask == (mask & (index+chunkId*chunkSize)) ){
3296 
3297  stateRealLo = stateVecReal[index];
3298  stateImagLo = stateVecImag[index];
3299 
3300  stateVecReal[index] = cosAngle*stateRealLo - sinAngle*stateImagLo;
3301  stateVecImag[index] = sinAngle*stateRealLo + cosAngle*stateImagLo;
3302  }
3303  }
3304  }
3305 }

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.

the double swap (q1,q2 to 0,1) may be possible simultaneously by a bespoke swap routine.

Definition at line 1458 of file QuEST_cpu_distributed.c.

1458  {
1459  int q1FitsInNode = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, q1);
1460  int q2FitsInNode = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, q2);
1461 
1462  if (q1FitsInNode && q2FitsInNode) {
1463  statevec_multiControlledTwoQubitUnitaryLocal(qureg, ctrlMask, q1, q2, u);
1464 
1465  } else if (q1FitsInNode) {
1466  int qSwap = (q1 > 0)? q1-1 : q1+1;
1467 
1468  // ensure ctrl == qSwap, ensure ctrlMask updates under the swap
1469  if (maskContainsBit(ctrlMask, qSwap))
1470  ctrlMask = flipBit(flipBit(ctrlMask, q2), qSwap);
1471 
1472  statevec_swapQubitAmps(qureg, q2, qSwap);
1473  statevec_multiControlledTwoQubitUnitaryLocal(qureg, ctrlMask, q1, qSwap, u);
1474  statevec_swapQubitAmps(qureg, q2, qSwap);
1475 
1476  } else if (q2FitsInNode) {
1477  int qSwap = (q2 > 0)? q2-1 : q2+1;
1478 
1479  // ensure ctrl == qSwap, ensure ctrlMask updates under the swap
1480  if (maskContainsBit(ctrlMask, qSwap))
1481  ctrlMask = flipBit(flipBit(ctrlMask, q1), qSwap);
1482 
1483  statevec_swapQubitAmps(qureg, q1, qSwap);
1484  statevec_multiControlledTwoQubitUnitaryLocal(qureg, ctrlMask, qSwap, q2, u);
1485  statevec_swapQubitAmps(qureg, q1, qSwap);
1486 
1487  } else {
1488  // we know with certainty that both q1 and q2 >= 2
1489  int swap1 = 0;
1490  int swap2 = 1;
1491 
1492  // if ctrl == swap1 or swap2, ensure ctrlMask updates under the swap
1493  if (maskContainsBit(ctrlMask, swap1))
1494  ctrlMask = flipBit(flipBit(ctrlMask, swap1), q1);
1495  if (maskContainsBit(ctrlMask, swap2))
1496  ctrlMask = flipBit(flipBit(ctrlMask, swap2), q2);
1497 
1498  statevec_swapQubitAmps(qureg, q1, swap1);
1499  statevec_swapQubitAmps(qureg, q2, swap2);
1500  statevec_multiControlledTwoQubitUnitaryLocal(qureg, ctrlMask, swap1, swap2, u);
1501  statevec_swapQubitAmps(qureg, q1, swap1);
1502  statevec_swapQubitAmps(qureg, q2, swap2);
1503  }
1504 }

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 1011 of file QuEST_cpu_distributed.c.

1012 {
1013  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1014  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1015  Complex rot1, rot2;
1016 
1017  // rank's chunk is in upper half of block
1018  int rankIsUpper;
1019  int pairRank; // rank of corresponding chunk
1020 
1021  if (useLocalDataOnly){
1022  // all values required to update state vector lie in this rank
1023  statevec_multiControlledUnitaryLocal(qureg, targetQubit, ctrlQubitsMask, ctrlFlipMask, u);
1024  } else {
1025  // need to get corresponding chunk of state vector from other rank
1026  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1027  getRotAngleFromUnitaryMatrix(rankIsUpper, &rot1, &rot2, u);
1028  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1029 
1030  // get corresponding values from my pair
1031  exchangeStateVectors(qureg, pairRank);
1032 
1033  // this rank's values are either in the upper of lower half of the block. send values to multiControlledUnitaryDistributed
1034  // in the correct order
1035  if (rankIsUpper){
1036  statevec_multiControlledUnitaryDistributed(qureg,targetQubit,ctrlQubitsMask,ctrlFlipMask,rot1,rot2,
1037  qureg.stateVec, //upper
1038  qureg.pairStateVec, //lower
1039  qureg.stateVec); //output
1040  } else {
1041  statevec_multiControlledUnitaryDistributed(qureg,targetQubit,ctrlQubitsMask,ctrlFlipMask,rot1,rot2,
1042  qureg.pairStateVec, //upper
1043  qureg.stateVec, //lower
1044  qureg.stateVec); //output
1045  }
1046  }
1047 }

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

Referenced by multiControlledUnitary(), multiStateControlledUnitary(), and statevec_multiControlledMultiRotatePauli().

◆ statevec_multiQubitUnitary()

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

Definition at line 573 of file QuEST_common.c.

573  {
574 
575  long long int ctrlMask = 0;
576  statevec_multiControlledMultiQubitUnitary(qureg, ctrlMask, targets, numTargets, u);
577 }

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 414 of file QuEST_common.c.

417  {
418  qreal fac = 1/sqrt(2);
419  Complex uRxAlpha = {.real = fac, .imag = 0}; // Rx(pi/2)* rotates Z -> Y
420  Complex uRxBeta = {.real = 0, .imag = (applyConj)? fac : -fac};
421  Complex uRyAlpha = {.real = fac, .imag = 0}; // Ry(-pi/2) rotates Z -> X
422  Complex uRyBeta = {.real = -fac, .imag = 0};
423 
424  // mask may be modified to remove superfluous Identity ops
425  long long int mask = getQubitBitMask(targetQubits, numTargets);
426 
427  // rotate basis so that exp(Z) will effect exp(Y) and exp(X)
428  for (int t=0; t < numTargets; t++) {
429  if (targetPaulis[t] == PAULI_I)
430  mask -= 1LL << targetQubits[t]; // remove target from mask
431  if (targetPaulis[t] == PAULI_X)
432  statevec_compactUnitary(qureg, targetQubits[t], uRyAlpha, uRyBeta);
433  if (targetPaulis[t] == PAULI_Y)
434  statevec_compactUnitary(qureg, targetQubits[t], uRxAlpha, uRxBeta);
435  // (targetPaulis[t] == 3) is Z basis
436  }
437 
438  // does nothing if there are no qubits to 'rotate'
439  if (mask != 0)
440  statevec_multiRotateZ(qureg, mask, (applyConj)? -angle : angle);
441 
442  // undo X and Y basis rotations
443  uRxBeta.imag *= -1;
444  uRyBeta.real *= -1;
445  for (int t=0; t < numTargets; t++) {
446  if (targetPaulis[t] == PAULI_X)
447  statevec_compactUnitary(qureg, targetQubits[t], uRyAlpha, uRyBeta);
448  if (targetPaulis[t] == PAULI_Y)
449  statevec_compactUnitary(qureg, targetQubits[t], uRxAlpha, uRxBeta);
450  }
451 }

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 3316 of file QuEST_cpu.c.

3317 {
3318  long long int index;
3319  long long int stateVecSize;
3320 
3321  long long int chunkSize=qureg.numAmpsPerChunk;
3322  long long int chunkId=qureg.chunkId;
3323 
3324  stateVecSize = qureg.numAmpsPerChunk;
3325  qreal *stateVecReal = qureg.stateVec.real;
3326  qreal *stateVecImag = qureg.stateVec.imag;
3327 
3328  qreal stateReal, stateImag;
3329  qreal cosAngle = cos(angle/2.0);
3330  qreal sinAngle = sin(angle/2.0);
3331 
3332  // = +-1, to flip sinAngle based on target qubit parity, to effect
3333  // exp(-angle/2 i fac_j)|j>
3334  int fac;
3335 
3336 # ifdef _OPENMP
3337 # pragma omp parallel \
3338  default (none) \
3339  shared (stateVecSize, stateVecReal, stateVecImag, mask, chunkId,chunkSize,cosAngle,sinAngle) \
3340  private (index, fac, stateReal, stateImag)
3341 # endif
3342  {
3343 # ifdef _OPENMP
3344 # pragma omp for schedule (static)
3345 # endif
3346  for (index=0; index<stateVecSize; index++) {
3347  stateReal = stateVecReal[index];
3348  stateImag = stateVecImag[index];
3349 
3350  // odd-parity target qubits get fac_j = -1
3351  fac = getBitMaskParity(mask & (index+chunkId*chunkSize))? -1 : 1;
3352  stateVecReal[index] = cosAngle*stateReal + fac * sinAngle*stateImag;
3353  stateVecImag[index] = - fac * sinAngle*stateReal + cosAngle*stateImag;
3354  }
3355  }
3356 }

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 1048 of file QuEST_cpu_distributed.c.

1049 {
1050  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1051  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1052 
1053  // rank's chunk is in upper half of block
1054  int rankIsUpper;
1055  int pairRank; // rank of corresponding chunk
1056 
1057  if (useLocalDataOnly){
1058  // all values required to update state vector lie in this rank
1059  statevec_pauliXLocal(qureg, targetQubit);
1060  } else {
1061  // need to get corresponding chunk of state vector from other rank
1062  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1063  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1064  //printf("%d rank has pair rank: %d\n", qureg.rank, pairRank);
1065  // get corresponding values from my pair
1066  exchangeStateVectors(qureg, pairRank);
1067  // this rank's values are either in the upper of lower half of the block. pauliX just replaces
1068  // this rank's values with pair values
1070  qureg.pairStateVec, // in
1071  qureg.stateVec); // out
1072  }
1073 }

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 1142 of file QuEST_cpu_distributed.c.

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

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 1167 of file QuEST_cpu_distributed.c.

1168 {
1169  int conjFac = -1;
1170 
1171  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
1172  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
1173  int rankIsUpper; // rank's chunk is in upper half of block
1174  int pairRank; // rank of corresponding chunk
1175 
1176  if (useLocalDataOnly){
1177  statevec_pauliYLocal(qureg, targetQubit, conjFac);
1178  } else {
1179  // need to get corresponding chunk of state vector from other rank
1180  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1181  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
1182  // get corresponding values from my pair
1183  exchangeStateVectors(qureg, pairRank);
1184  // this rank's values are either in the upper of lower half of the block
1186  qureg.pairStateVec, // in
1187  qureg.stateVec, // out
1188  rankIsUpper, conjFac);
1189  }
1190 }

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 261 of file QuEST_common.c.

261  {
262  Complex term;
263  term.real = -1;
264  term.imag = 0;
265  statevec_phaseShiftByTerm(qureg, targetQubit, term);
266 }

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 254 of file QuEST_common.c.

254  {
255  Complex term;
256  term.real = cos(angle);
257  term.imag = sin(angle);
258  statevec_phaseShiftByTerm(qureg, targetQubit, term);
259 }

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 3185 of file QuEST_cpu.c.

3186 {
3187  long long int index;
3188  long long int stateVecSize;
3189  int targetBit;
3190 
3191  long long int chunkSize=qureg.numAmpsPerChunk;
3192  long long int chunkId=qureg.chunkId;
3193 
3194  // dimension of the state vector
3195  stateVecSize = qureg.numAmpsPerChunk;
3196  qreal *stateVecReal = qureg.stateVec.real;
3197  qreal *stateVecImag = qureg.stateVec.imag;
3198 
3199  qreal stateRealLo, stateImagLo;
3200  qreal cosAngle = term.real;
3201  qreal sinAngle = term.imag;
3202 
3203 # ifdef _OPENMP
3204 # pragma omp parallel for \
3205  default (none) \
3206  shared (stateVecSize, stateVecReal,stateVecImag, cosAngle,sinAngle, \
3207  chunkId,chunkSize,targetQubit) \
3208  private (index,targetBit,stateRealLo,stateImagLo) \
3209  schedule (static)
3210 # endif
3211  for (index=0; index<stateVecSize; index++) {
3212 
3213  // update the coeff of the |1> state of the target qubit
3214  targetBit = extractBit (targetQubit, index+chunkId*chunkSize);
3215  if (targetBit) {
3216 
3217  stateRealLo = stateVecReal[index];
3218  stateImagLo = stateVecImag[index];
3219 
3220  stateVecReal[index] = cosAngle*stateRealLo - sinAngle*stateImagLo;
3221  stateVecImag[index] = sinAngle*stateRealLo + cosAngle*stateImagLo;
3222  }
3223  }
3224 }

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 1439 of file QuEST_cpu.c.

1439  {
1440  long long int index;
1441  int rank;
1442  if (qureg.numQubitsInStateVec<=5){
1443  for (rank=0; rank<qureg.numChunks; rank++){
1444  if (qureg.chunkId==rank){
1445  if (reportRank) {
1446  printf("Reporting state from rank %d [\n", qureg.chunkId);
1447  printf("real, imag\n");
1448  } else if (rank==0) {
1449  printf("Reporting state [\n");
1450  printf("real, imag\n");
1451  }
1452 
1453  for(index=0; index<qureg.numAmpsPerChunk; index++){
1454  //printf(REAL_STRING_FORMAT ", " REAL_STRING_FORMAT "\n", qureg.pairStateVec.real[index], qureg.pairStateVec.imag[index]);
1455  printf(REAL_STRING_FORMAT ", " REAL_STRING_FORMAT "\n", qureg.stateVec.real[index], qureg.stateVec.imag[index]);
1456  }
1457  if (reportRank || rank==qureg.numChunks-1) printf("]\n");
1458  }
1459  syncQuESTEnv(env);
1460  }
1461  } else printf("Error: reportStateToScreen will not print output for systems of more than 5 qubits.\n");
1462 }

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 314 of file QuEST_common.c.

314  {
315 
316  Complex alpha, beta;
317  getComplexPairFromRotation(angle, axis, &alpha, &beta);
318  statevec_compactUnitary(qureg, rotQubit, alpha, beta);
319 }

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 321 of file QuEST_common.c.

321  {
322 
323  Complex alpha, beta;
324  getComplexPairFromRotation(angle, axis, &alpha, &beta);
325  alpha.imag *= -1;
326  beta.imag *= -1;
327  statevec_compactUnitary(qureg, rotQubit, alpha, beta);
328 }

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

Referenced by rotateAroundAxis().

◆ statevec_rotateX()

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

Definition at line 296 of file QuEST_common.c.

296  {
297 
298  Vector unitAxis = {1, 0, 0};
299  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
300 }

References statevec_rotateAroundAxis().

Referenced by rotateX().

◆ statevec_rotateY()

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

Definition at line 302 of file QuEST_common.c.

302  {
303 
304  Vector unitAxis = {0, 1, 0};
305  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
306 }

References statevec_rotateAroundAxis().

Referenced by rotateY().

◆ statevec_rotateZ()

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

Definition at line 308 of file QuEST_common.c.

308  {
309 
310  Vector unitAxis = {0, 0, 1};
311  statevec_rotateAroundAxis(qureg, rotQubit, angle, unitAxis);
312 }

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 1248 of file QuEST_cpu.c.

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

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 4005 of file QuEST_cpu.c.

4005  {
4006 
4007  long long int numAmps = qureg1.numAmpsPerChunk;
4008 
4009  qreal *vecRe1 = qureg1.stateVec.real;
4010  qreal *vecIm1 = qureg1.stateVec.imag;
4011  qreal *vecRe2 = qureg2.stateVec.real;
4012  qreal *vecIm2 = qureg2.stateVec.imag;
4013  qreal *vecReOut = out.stateVec.real;
4014  qreal *vecImOut = out.stateVec.imag;
4015 
4016  qreal facRe1 = fac1.real;
4017  qreal facIm1 = fac1.imag;
4018  qreal facRe2 = fac2.real;
4019  qreal facIm2 = fac2.imag;
4020  qreal facReOut = facOut.real;
4021  qreal facImOut = facOut.imag;
4022 
4023  qreal re1,im1, re2,im2, reOut,imOut;
4024  long long int index;
4025 
4026 # ifdef _OPENMP
4027 # pragma omp parallel \
4028  shared (vecRe1,vecIm1, vecRe2,vecIm2, vecReOut,vecImOut, facRe1,facIm1,facRe2,facIm2, numAmps) \
4029  private (index, re1,im1, re2,im2, reOut,imOut)
4030 # endif
4031  {
4032 # ifdef _OPENMP
4033 # pragma omp for schedule (static)
4034 # endif
4035  for (index=0LL; index<numAmps; index++) {
4036  re1 = vecRe1[index]; im1 = vecIm1[index];
4037  re2 = vecRe2[index]; im2 = vecIm2[index];
4038  reOut = vecReOut[index];
4039  imOut = vecImOut[index];
4040 
4041  vecReOut[index] = (facReOut*reOut - facImOut*imOut) + (facRe1*re1 - facIm1*im1) + (facRe2*re2 - facIm2*im2);
4042  vecImOut[index] = (facReOut*imOut + facImOut*reOut) + (facRe1*im1 + facIm1*re1) + (facRe2*im2 + facIm2*re2);
4043  }
4044  }
4045 }

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 268 of file QuEST_common.c.

268  {
269  Complex term;
270  term.real = 0;
271  term.imag = 1;
272  statevec_phaseShiftByTerm(qureg, targetQubit, term);
273 }

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

Referenced by sGate().

◆ statevec_sGateConj()

void statevec_sGateConj ( Qureg  qureg,
int  targetQubit 
)

Definition at line 282 of file QuEST_common.c.

282  {
283  Complex term;
284  term.real = 0;
285  term.imag = -1;
286  statevec_phaseShiftByTerm(qureg, targetQubit, term);
287 }

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 387 of file QuEST_common.c.

387  {
388 
389  ComplexMatrix4 u = (ComplexMatrix4) {.real={{0}}, .imag={{0}}};
390  u.real[0][0]=1;
391  u.real[3][3]=1;
392  u.real[1][1] = .5; u.imag[1][1] = .5;
393  u.real[1][2] = .5; u.imag[1][2] =-.5;
394  u.real[2][1] = .5; u.imag[2][1] =-.5;
395  u.real[2][2] = .5; u.imag[2][2] = .5;
396 
397  statevec_twoQubitUnitary(qureg, qb1, qb2, u);
398 }

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 400 of file QuEST_common.c.

400  {
401 
402  ComplexMatrix4 u = (ComplexMatrix4) {.real={{0}}, .imag={{0}}};
403  u.real[0][0]=1;
404  u.real[3][3]=1;
405  u.real[1][1] = .5; u.imag[1][1] =-.5;
406  u.real[1][2] = .5; u.imag[1][2] = .5;
407  u.real[2][1] = .5; u.imag[2][1] = .5;
408  u.real[2][2] = .5; u.imag[2][2] =-.5;
409 
410  statevec_twoQubitUnitary(qureg, qb1, qb2, u);
411 }

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 1431 of file QuEST_cpu_distributed.c.

1431  {
1432 
1433  // perform locally if possible
1434  int qbBig = (qb1 > qb2)? qb1 : qb2;
1435  if (halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, qbBig))
1436  return statevec_swapQubitAmpsLocal(qureg, qb1, qb2);
1437 
1438  // do nothing if this node contains no amplitudes to swap
1439  long long int oddParityGlobalInd = getGlobalIndOfOddParityInChunk(qureg, qb1, qb2);
1440  if (oddParityGlobalInd == -1)
1441  return;
1442 
1443  // determine and swap amps with pair node
1444  int pairRank = flipBit(flipBit(oddParityGlobalInd, qb1), qb2) / qureg.numAmpsPerChunk;
1445  exchangeStateVectors(qureg, pairRank);
1446  statevec_swapQubitAmpsDistributed(qureg, pairRank, qb1, qb2);
1447 }

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

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

◆ statevec_tGate()

void statevec_tGate ( Qureg  qureg,
int  targetQubit 
)

Definition at line 275 of file QuEST_common.c.

275  {
276  Complex term;
277  term.real = 1/sqrt(2);
278  term.imag = 1/sqrt(2);
279  statevec_phaseShiftByTerm(qureg, targetQubit, term);
280 }

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

Referenced by tGate().

◆ statevec_tGateConj()

void statevec_tGateConj ( Qureg  qureg,
int  targetQubit 
)

Definition at line 289 of file QuEST_common.c.

289  {
290  Complex term;
291  term.real = 1/sqrt(2);
292  term.imag = -1/sqrt(2);
293  statevec_phaseShiftByTerm(qureg, targetQubit, term);
294 }

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 561 of file QuEST_common.c.

561  {
562 
563  long long int ctrlMask = 0;
564  statevec_multiControlledTwoQubitUnitary(qureg, ctrlMask, targetQubit1, targetQubit2, u);
565 }

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 895 of file QuEST_cpu_distributed.c.

896 {
897  // flag to require memory exchange. 1: an entire block fits on one rank, 0: at most half a block fits on one rank
898  int useLocalDataOnly = halfMatrixBlockFitsInChunk(qureg.numAmpsPerChunk, targetQubit);
899  Complex rot1, rot2;
900 
901  // rank's chunk is in upper half of block
902  int rankIsUpper;
903  int pairRank; // rank of corresponding chunk
904 
905  if (useLocalDataOnly){
906  // all values required to update state vector lie in this rank
907  statevec_unitaryLocal(qureg, targetQubit, u);
908  } else {
909  // need to get corresponding chunk of state vector from other rank
910  rankIsUpper = chunkIsUpper(qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
911  getRotAngleFromUnitaryMatrix(rankIsUpper, &rot1, &rot2, u);
912  pairRank = getChunkPairId(rankIsUpper, qureg.chunkId, qureg.numAmpsPerChunk, targetQubit);
913  // get corresponding values from my pair
914  exchangeStateVectors(qureg, pairRank);
915 
916  // this rank's values are either in the upper of lower half of the block.
917  // send values to compactUnitaryDistributed in the correct order
918  if (rankIsUpper){
919  statevec_unitaryDistributed(qureg,rot1,rot2,
920  qureg.stateVec, //upper
921  qureg.pairStateVec, //lower
922  qureg.stateVec); //output
923  } else {
924  statevec_unitaryDistributed(qureg,rot1,rot2,
925  qureg.pairStateVec, //upper
926  qureg.stateVec, //lower
927  qureg.stateVec); //output
928  }
929  }
930 
931 
932 }

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().

@ INVERSE_PRODUCT
Definition: QuEST.h:233
Represents a 3-vector of real numbers.
Definition: QuEST.h:198
pauliOpType
Codes for specifying Pauli operators.
Definition: QuEST.h:96
#define macro_setConjugateMatrix(dest, src, dim)
Definition: QuEST_common.c:99
qreal real[4][4]
Definition: QuEST.h:177
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:644
void statevec_controlledNotLocal(Qureg qureg, int controlQubit, int targetQubit)
Definition: QuEST_cpu.c:2679
static void getRotAngle(int chunkIsUpper, Complex *rot1, Complex *rot2, Complex alpha, Complex beta)
Get rotation values for a given chunk.
@ PAULI_Z
Definition: QuEST.h:96
void statevec_pauliYLocal(Qureg qureg, int targetQubit, int conjFac)
Definition: QuEST_cpu.c:2887
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:934
@ DISTANCE
Definition: QuEST.h:234
int rank
Definition: QuEST.h:364
void populateKrausSuperOperator4(ComplexMatrixN *superOp, ComplexMatrix4 *ops, int numOps)
Definition: QuEST_common.c:611
void populateKrausSuperOperatorN(ComplexMatrixN *superOp, ComplexMatrixN *ops, int numOps)
Definition: QuEST_common.c:615
void destroyComplexMatrixN(ComplexMatrixN m)
Destroy a ComplexMatrixN instance created with createComplexMatrixN()
Definition: QuEST.c:1369
int numChunks
The number of nodes between which the elements of this operator are split.
Definition: QuEST.h:304
qreal statevec_calcExpecPauliProd(Qureg qureg, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets, Qureg workspace)
Definition: QuEST_common.c:509
void densmatr_calcProbOfAllOutcomesLocal(qreal *outcomeProbs, Qureg qureg, int *qubits, int numQubits)
Definition: QuEST_cpu.c:3616
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:343
@ 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:3513
ComplexMatrixN createComplexMatrixN(int numQubits)
Allocate dynamic memory for a square complex matrix of any size, which can be passed to functions lik...
Definition: QuEST.c:1348
void densmatr_mixDepolarisingDistributed(Qureg qureg, int targetQubit, qreal depolLevel)
Definition: QuEST_cpu.c:230
void densmatr_mixTwoQubitDepolarisingQ1LocalQ2DistributedPart3(Qureg qureg, int targetQubit, int qubit2, qreal delta, qreal gamma)
Definition: QuEST_cpu.c:638
void statevec_twoQubitUnitary(Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Definition: QuEST_common.c:561
qreal z
Definition: QuEST.h:200
int numChunks
Number of chunks the state vector is broken up into – the number of MPI processes used.
Definition: QuEST.h:338
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:3922
void statevec_applyPauliProd(Qureg workspace, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets)
Definition: QuEST_common.c:495
@ TWOS_COMPLEMENT
Definition: QuEST.h:269
int getBitMaskParity(long long int mask)
Definition: QuEST_cpu.c:3307
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:2542
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:3316
void statevec_multiControlledMultiQubitNotLocal(Qureg qureg, int ctrlMask, int targMask)
Definition: QuEST_cpu.c:2778
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:2476
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:3767
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:306
@ NORM
Definition: QuEST.h:232
void statevec_compactUnitaryLocal(Qureg qureg, int targetQubit, Complex alpha, Complex beta)
Definition: QuEST_cpu.c:1754
qreal densmatr_calcPurityLocal(Qureg qureg)
Definition: QuEST_cpu.c:872
@ GATE_HADAMARD
Definition: QuEST_qasm.h:26
Complex statevec_calcExpecDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:4124
Vector getUnitVector(Vector vec)
Definition: QuEST_common.c:84
Represents a 4x4 matrix of complex numbers.
Definition: QuEST.h:175
@ SCALED_INVERSE_DISTANCE
Definition: QuEST.h:234
@ UNSIGNED
Definition: QuEST.h:269
void statevec_multiControlledMultiQubitUnitaryLocal(Qureg qureg, long long int ctrlMask, int *targs, int numTargs, ComplexMatrixN u)
Definition: QuEST_cpu.c:1912
void statevec_initBlankState(Qureg qureg)
Definition: QuEST_cpu.c:1464
void getComplexPairFromRotation(qreal angle, Vector axis, Complex *alpha, Complex *beta)
Definition: QuEST_common.c:120
void statevec_multiControlledTwoQubitUnitaryLocal(Qureg qureg, long long int ctrlMask, int q1, int q2, ComplexMatrix4 u)
Definition: QuEST_cpu.c:1813
Represents a general 2^N by 2^N matrix of complex numbers.
Definition: QuEST.h:186
@ INVERSE_DISTANCE
Definition: QuEST.h:234
void statevec_pauliXDistributed(Qureg qureg, ComplexArray stateVecIn, ComplexArray stateVecOut)
Rotate a single qubit by {{0,1},{1,0}.
Definition: QuEST_cpu.c:2651
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:675
void statevec_calcProbOfAllOutcomesLocal(qreal *outcomeProbs, Qureg qureg, int *qubits, int numQubits)
Definition: QuEST_cpu.c:3549
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)
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:329
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:791
void statevec_collapseToOutcomeDistributedSetZero(Qureg qureg)
Definition: QuEST_cpu.c:3887
int chunkId
The position of the chunk of the state vector held by this process in the full state vector.
Definition: QuEST.h:336
void qasm_recordControlledGate(Qureg qureg, TargetGate gate, int controlQubit, int targetQubit)
Definition: QuEST_qasm.c:239
qreal y
Definition: QuEST.h:200
qreal imag[2][2]
Definition: QuEST.h:140
void statevec_applyParamNamedPhaseFuncOverrides(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, qreal *params, int numParams, long long int *overrideInds, qreal *overridePhases, int numOverrides, int conj)
Definition: QuEST_cpu.c:4446
qreal * imag
The imaginary values of the 2^numQubits complex elements.
Definition: QuEST.h:310
void statevec_multiControlledMultiRotateZ(Qureg qureg, long long int ctrlMask, long long int targMask, qreal angle)
Definition: QuEST_cpu.c:3358
qreal x
Definition: QuEST.h:200
int generateMeasurementOutcome(qreal zeroProb, qreal *outcomeProb)
Definition: QuEST_common.c:168
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:332
void densmatr_mixTwoQubitDepolarisingLocal(Qureg qureg, int qubit1, int qubit2, qreal delta, qreal gamma)
Definition: QuEST_cpu.c:393
qreal * termCoeffs
The real coefficient of each Pauli product. This is an array of length PauliHamil....
Definition: QuEST.h:283
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:2982
void densmatr_applyKrausSuperoperator(Qureg qureg, int target, ComplexMatrix4 superOp)
Definition: QuEST_common.c:620
void densmatr_oneQubitDegradeOffDiagonal(Qureg qureg, int targetQubit, qreal retain)
Definition: QuEST_cpu.c:54
enum pauliOpType * pauliCodes
The Pauli operators acting on each qubit, flattened over every operator.
Definition: QuEST.h:281
void statevec_initBlankState(Qureg qureg)
Definition: QuEST_cpu.c:1464
void populateKrausSuperOperator2(ComplexMatrix4 *superOp, ComplexMatrix2 *ops, int numOps)
Definition: QuEST_common.c:607
@ SCALED_PRODUCT
Definition: QuEST.h:233
#define MAX_NUM_REGS_APPLY_ARBITRARY_PHASE
void alternateNormZeroingSomeAmpBlocks(Qureg qureg, qreal norm, int normFirst, long long int startAmpInd, long long int numAmps, long long int blockSize)
Definition: QuEST_cpu.c:760
void statevec_cloneQureg(Qureg targetQureg, Qureg copyQureg)
works for both statevectors and density matrices
Definition: QuEST_cpu.c:1572
void statevec_rotateAroundAxis(Qureg qureg, int rotQubit, qreal angle, Vector axis)
Definition: QuEST_common.c:314
int numRanks
Definition: QuEST.h:365
void densmatr_mixTwoQubitDephasing(Qureg qureg, int qubit1, int qubit2, qreal dephase)
Definition: QuEST_cpu.c:90
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:2095
qreal imag[4][4]
Definition: QuEST.h:178
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:300
int numSumTerms
The number of terms in the weighted sum, or the number of Pauli products.
Definition: QuEST.h:285
void statevec_multiControlledUnitaryLocal(Qureg qureg, int targetQubit, long long int ctrlQubitsMask, long long int ctrlFlipMask, ComplexMatrix2 u)
Definition: QuEST_cpu.c:2268
long long int getQubitBitMask(int *qubits, int numQubits)
Definition: QuEST_common.c:50
void normaliseSomeAmps(Qureg qureg, qreal norm, long long int startInd, long long int numAmps)
Definition: QuEST_cpu.c:750
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:297
@ 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:2945
@ SCALED_INVERSE_SHIFTED_NORM
Definition: QuEST.h:232
void densmatr_mixDampingDistributed(Qureg qureg, int targetQubit, qreal damping)
Definition: QuEST_cpu.c:306
Complex densmatr_calcExpecDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:4167
void statevec_pauliXLocal(Qureg qureg, int targetQubit)
Definition: QuEST_cpu.c:2593
void statevec_controlledRotateAroundAxis(Qureg qureg, int controlQubit, int targetQubit, qreal angle, Vector axis)
Definition: QuEST_common.c:330
void densmatr_initPureStateLocal(Qureg targetQureg, Qureg copyQureg)
Definition: QuEST_cpu.c:1195
__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:4005
void statevec_collapseToKnownProbOutcome(Qureg qureg, int measureQubit, int outcome, qreal outcomeProb)
void densmatr_mixDampingLocal(Qureg qureg, int targetQubit, qreal damping)
Definition: QuEST_cpu.c:180
void shiftSubregIndices(int *allInds, int *numIndsPerReg, int numRegs, int shift)
Definition: QuEST_common.c:161
qreal statevec_getImagAmp(Qureg qureg, long long int index)
@ INVERSE_NORM
Definition: QuEST.h:232
qreal densmatr_calcInnerProductLocal(Qureg a, Qureg b)
computes Tr(conjTrans(a) b) = sum of (a_ij^* b_ij)
Definition: QuEST_cpu.c:969
static int getChunkIdFromIndex(Qureg qureg, long long int index)
void statevec_multiControlledMultiQubitNotDistributed(Qureg qureg, int ctrlMask, int targMask, ComplexArray stateVecIn, ComplexArray stateVecOut)
Definition: QuEST_cpu.c:2834
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:2151
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:2414
@ PRODUCT
Definition: QuEST.h:233
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:341
qreal real[2][2]
Definition: QuEST.h:139
void densmatr_mixDepolarisingLocal(Qureg qureg, int targetQubit, qreal depolLevel)
Definition: QuEST_cpu.c:131
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:3849
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:302
int isDensityMatrix
Whether this instance is a density-state representation.
Definition: QuEST.h:325
void statevec_hadamard(Qureg qureg, int targetQubit)
void statevec_hadamardLocal(Qureg qureg, int targetQubit)
Definition: QuEST_cpu.c:3078
int numQubits
Definition: QuEST.h:188
void densmatr_applyDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:4082
void statevec_controlledUnitaryLocal(Qureg qureg, int controlQubit, int targetQubit, ComplexMatrix2 u)
Definition: QuEST_cpu.c:2336
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 statevec_multiControlledUnitary(Qureg qureg, long long int ctrlQubitsMask, long long int ctrlFlipMask, int targetQubit, ComplexMatrix2 u)
void densmatr_applyTwoQubitKrausSuperoperator(Qureg qureg, int target1, int target2, ComplexMatrixN superOp)
Definition: QuEST_common.c:626
void statevec_phaseShiftByTerm(Qureg qureg, int targetQubit, Complex term)
Definition: QuEST_cpu.c:3185
void densmatr_mixTwoQubitDepolarisingLocalPart1(Qureg qureg, int qubit1, int qubit2, qreal delta)
Definition: QuEST_cpu.c:494
void copyDiagOpIntoMatrixPairState(Qureg qureg, DiagonalOp op)
int numQubits
The number of qubits informing the Hilbert dimension of the Hamiltonian.
Definition: QuEST.h:287
void statevec_controlledNotDistributed(Qureg qureg, int controlQubit, ComplexArray stateVecIn, ComplexArray stateVecOut)
Rotate a single qubit by {{0,1},{1,0}.
Definition: QuEST_cpu.c:2742
int numQubitsRepresented
The number of qubits represented in either the state-vector or density matrix.
Definition: QuEST.h:327
long long int numAmpsTotal
Total number of amplitudes, which are possibly distributed among machines.
Definition: QuEST.h:334
@ SCALED_DISTANCE
Definition: QuEST.h:234
@ GATE_SWAP
Definition: QuEST_qasm.h:33
qreal * real
The real values of the 2^numQubits complex elements.
Definition: QuEST.h:308
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:3965
void densmatr_applyMultiQubitKrausSuperoperator(Qureg qureg, int *targets, int numTargets, ComplexMatrixN superOp)
Definition: QuEST_common.c:634
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:547
void statevec_unitaryLocal(Qureg qureg, int targetQubit, ComplexMatrix2 u)
Definition: QuEST_cpu.c:2026
qreal densmatr_findProbabilityOfZeroLocal(Qureg qureg, int measureQubit)
Definition: QuEST_cpu.c:3402
static int chunkIsUpperInOuterBlock(int chunkId, long long int chunkSize, int targetQubit, int numQubits)
fix – do with masking instead
@ SCALED_INVERSE_SHIFTED_DISTANCE
Definition: QuEST.h:234
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:3139
@ SCALED_NORM
Definition: QuEST.h:232
@ SCALED_INVERSE_PRODUCT
Definition: QuEST.h:233
static int maskContainsBit(const long long int mask, const int bitInd)
void qasm_recordGate(Qureg qureg, TargetGate gate, int targetQubit)
Definition: QuEST_qasm.c:179
qreal densmatr_calcProbOfOutcome(Qureg qureg, int measureQubit, int outcome)
#define M_PI
Definition: QuEST_common.c:41
void applySymmetrizedTrotterCircuit(Qureg qureg, PauliHamil hamil, qreal time, int order)
Definition: QuEST_common.c:820
void statevec_controlledPauliYDistributed(Qureg qureg, int controlQubit, ComplexArray stateVecIn, ComplexArray stateVecOut, int conjFac)
Definition: QuEST_cpu.c:3036
void statevec_controlledCompactUnitaryLocal(Qureg qureg, int controlQubit, int targetQubit, Complex alpha, Complex beta)
Definition: QuEST_cpu.c:2196
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 qasm_recordNamedPhaseFunc(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc funcName, qreal *params, int numParams, long long int *overrideInds, qreal *overridePhases, int numOverrides)
Definition: QuEST_qasm.c:726
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:1082
Represents a 2x2 matrix of complex numbers.
Definition: QuEST.h:137
void zeroSomeAmps(Qureg qureg, long long int startInd, long long int numAmps)
Definition: QuEST_cpu.c:740
@ SCALED_INVERSE_NORM
Definition: QuEST.h:232
qreal densmatr_calcFidelityLocal(Qureg qureg, Qureg pureState)
computes a few dens-columns-worth of (vec^*T) dens * vec
Definition: QuEST_cpu.c:1001
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:3457