QuEST_cpu_distributed.c File Reference
#include "QuEST.h"
#include "QuEST_internal.h"
#include "QuEST_precision.h"
#include "QuEST_validation.h"
#include "mt19937ar.h"
#include "QuEST_cpu_internal.h"
#include <unistd.h>
#include <mpi.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <sys/types.h>

Go to the source code of this file.

Macros

#define _BSD_SOURCE
 

Functions

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. More...
 
static int chunkIsUpperInOuterBlock (int chunkId, long long int chunkSize, int targetQubit, int numQubits)
 fix – do with masking instead More...
 
void compressPairVectorForSingleQubitDepolarise (Qureg qureg, int targetQubit)
 
void compressPairVectorForTwoQubitDepolarise (Qureg qureg, int targetQubit, int qubit2)
 
void copyDiagOpIntoMatrixPairState (Qureg qureg, DiagonalOp op)
 
void copyVecIntoMatrixPairState (Qureg matr, Qureg vec)
 This copies/clones vec (a statevector) into every node's matr pairState. More...
 
QuESTEnv createQuESTEnv (void)
 Create the QuEST execution environment. More...
 
static int densityMatrixBlockFitsInChunk (long long int chunkSize, int numQubits, int targetQubit)
 
void densmatr_applyDiagonalOp (Qureg qureg, DiagonalOp op)
 
Complex densmatr_calcExpecDiagonalOp (Qureg qureg, DiagonalOp op)
 
qreal densmatr_calcFidelity (Qureg qureg, Qureg pureState)
 
qreal densmatr_calcHilbertSchmidtDistance (Qureg a, Qureg b)
 
qreal densmatr_calcInnerProduct (Qureg a, Qureg b)
 
qreal densmatr_calcProbOfOutcome (Qureg qureg, int measureQubit, int outcome)
 
qreal densmatr_calcPurity (Qureg qureg)
 
qreal densmatr_calcTotalProb (Qureg qureg)
 
void densmatr_initPureState (Qureg targetQureg, Qureg copyQureg)
 
void densmatr_mixDamping (Qureg qureg, int targetQubit, qreal damping)
 
void densmatr_mixDepolarising (Qureg qureg, int targetQubit, qreal depolLevel)
 
void densmatr_mixTwoQubitDepolarising (Qureg qureg, int qubit1, int qubit2, qreal depolLevel)
 
void destroyQuESTEnv (QuESTEnv env)
 Destroy the QuEST environment. More...
 
void exchangePairStateVectorHalves (Qureg qureg, int pairRank)
 
void exchangeStateVectors (Qureg qureg, int pairRank)
 
static int getChunkIdFromIndex (Qureg qureg, long long int index)
 
static int getChunkOuterBlockPairId (int chunkIsUpper, int chunkId, long long int chunkSize, int targetQubit, int numQubits)
 
static int getChunkOuterBlockPairIdForPart3 (int chunkIsUpperSmallerQubit, int chunkIsUpperBiggerQubit, int chunkId, long long int chunkSize, int smallerQubit, int biggerQubit, int numQubits)
 
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 chunkId) when rotating targetQubit. More...
 
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, otherwise returns the global index of one of such contained amplitudes (not necessarily the first) More...
 
static void getRotAngle (int chunkIsUpper, Complex *rot1, Complex *rot2, Complex alpha, Complex beta)
 Get rotation values for a given chunk. More...
 
static void getRotAngleFromUnitaryMatrix (int chunkIsUpper, Complex *rot1, Complex *rot2, ComplexMatrix2 u)
 Get rotation values for a given chunk given a unitary matrix. More...
 
static int halfMatrixBlockFitsInChunk (long long int chunkSize, int targetQubit)
 return whether the current qubit rotation will use blocks that fit within a single chunk. More...
 
static int isChunkToSkipInFindPZero (int chunkId, long long int chunkSize, int measureQubit)
 Find chunks to skip when calculating probability of qubit being zero. More...
 
void reportQuESTEnv (QuESTEnv env)
 Report information about the QuEST environment. More...
 
void seedQuESTDefault ()
 Seed the Mersenne Twister used for random number generation in the QuEST environment with an example defualt seed. More...
 
Complex statevec_calcExpecDiagonalOp (Qureg qureg, DiagonalOp op)
 
Complex statevec_calcInnerProduct (Qureg bra, Qureg ket)
 
qreal statevec_calcProbOfOutcome (Qureg qureg, int measureQubit, int outcome)
 
qreal statevec_calcTotalProb (Qureg qureg)
 
void statevec_collapseToKnownProbOutcome (Qureg qureg, int measureQubit, int outcome, qreal totalStateProb)
 
void statevec_compactUnitary (Qureg qureg, int targetQubit, Complex alpha, Complex beta)
 
void statevec_controlledCompactUnitary (Qureg qureg, int controlQubit, int targetQubit, Complex alpha, Complex beta)
 
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_controlledUnitary (Qureg qureg, int controlQubit, int targetQubit, ComplexMatrix2 u)
 
qreal statevec_getImagAmp (Qureg qureg, long long int index)
 
qreal statevec_getRealAmp (Qureg qureg, long long int index)
 
void statevec_hadamard (Qureg qureg, int targetQubit)
 
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_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. More...
 
void statevec_multiControlledUnitary (Qureg qureg, long long int ctrlQubitsMask, long long int ctrlFlipMask, int targetQubit, ComplexMatrix2 u)
 
void statevec_pauliX (Qureg qureg, int targetQubit)
 
void statevec_pauliY (Qureg qureg, int targetQubit)
 
void statevec_pauliYConj (Qureg qureg, int targetQubit)
 
void statevec_swapQubitAmps (Qureg qureg, int qb1, int qb2)
 
void statevec_unitary (Qureg qureg, int targetQubit, ComplexMatrix2 u)
 
void syncQuESTEnv (QuESTEnv env)
 Guarantees that all code up to the given point has been executed on all nodes (if running in distributed mode) More...
 
int syncQuESTSuccess (int successCode)
 Performs a logical AND on all successCodes held by all processes. More...
 

Detailed Description

An implementation of the backend in ../QuEST_ops.h for an MPI environment. Mostly pure-state wrappers for the local/distributed functions implemented in QuEST_cpu

Author
Ania Brown
Tyson Jones
Balint Koczor

Definition in file QuEST_cpu_distributed.c.

Macro Definition Documentation

◆ _BSD_SOURCE

#define _BSD_SOURCE

Definition at line 20 of file QuEST_cpu_distributed.c.

Function Documentation

◆ chunkIsUpper()

static int chunkIsUpper ( int  chunkId,
long long int  chunkSize,
int  targetQubit 
)
static

Returns whether a given chunk in position chunkId is in the upper or lower half of a block.

Parameters
[in]chunkIdid of chunk in state vector
[in]chunkSizenumber of amps in chunk
[in]targetQubitqubit being rotated
Returns
1: chunk is in upper half of block, 0: chunk is in lower half of block fix – is this the same as isChunkToSkip?

Definition at line 227 of file QuEST_cpu_distributed.c.

228 {
229  long long int sizeHalfBlock = 1LL << (targetQubit);
230  long long int sizeBlock = sizeHalfBlock*2;
231  long long int posInBlock = (chunkId*chunkSize) % sizeBlock;
232  return posInBlock<sizeHalfBlock;
233 }

Referenced by getChunkOuterBlockPairId(), getChunkPairId(), getRotAngle(), getRotAngleFromUnitaryMatrix(), statevec_compactUnitary(), statevec_controlledCompactUnitary(), statevec_controlledNot(), statevec_controlledPauliY(), statevec_controlledPauliYConj(), statevec_controlledUnitary(), statevec_hadamard(), statevec_multiControlledUnitary(), statevec_pauliX(), statevec_pauliY(), statevec_pauliYConj(), and statevec_unitary().

◆ chunkIsUpperInOuterBlock()

static int chunkIsUpperInOuterBlock ( int  chunkId,
long long int  chunkSize,
int  targetQubit,
int  numQubits 
)
static

fix – do with masking instead

Definition at line 236 of file QuEST_cpu_distributed.c.

237 {
238  long long int sizeOuterHalfBlock = 1LL << (targetQubit+numQubits);
239  long long int sizeOuterBlock = sizeOuterHalfBlock*2;
240  long long int posInBlock = (chunkId*chunkSize) % sizeOuterBlock;
241  return posInBlock<sizeOuterHalfBlock;
242 }

Referenced by densmatr_mixDamping(), densmatr_mixDepolarising(), and densmatr_mixTwoQubitDepolarising().

◆ compressPairVectorForSingleQubitDepolarise()

void compressPairVectorForSingleQubitDepolarise ( Qureg  qureg,
int  targetQubit 
)

Definition at line 543 of file QuEST_cpu_distributed.c.

543  {
544  long long int sizeInnerBlock, sizeInnerHalfBlock;
545  long long int sizeOuterColumn, sizeOuterHalfColumn;
546  long long int thisInnerBlock, // current block
547  thisOuterColumn, // current column in density matrix
548  thisIndex, // current index in (density matrix representation) state vector
549  thisIndexInOuterColumn,
550  thisIndexInInnerBlock;
551 
552  int outerBit;
553 
554  long long int thisTask;
555  long long int numTasks=qureg.numAmpsPerChunk>>1;
556 
557  // set dimensions
558  sizeInnerHalfBlock = 1LL << targetQubit;
559  sizeInnerBlock = 2LL * sizeInnerHalfBlock;
560  sizeOuterHalfColumn = 1LL << qureg.numQubitsRepresented;
561  sizeOuterColumn = 2LL * sizeOuterHalfColumn;
562 
563 # ifdef _OPENMP
564 # pragma omp parallel \
565  default (none) \
566  shared (sizeInnerBlock,sizeInnerHalfBlock,sizeOuterColumn,sizeOuterHalfColumn, \
567  qureg,numTasks,targetQubit) \
568  private (thisTask,thisInnerBlock,thisOuterColumn,thisIndex,thisIndexInOuterColumn, \
569  thisIndexInInnerBlock,outerBit)
570 # endif
571  {
572 # ifdef _OPENMP
573 # pragma omp for schedule (static)
574 # endif
575  // thisTask iterates over half the elements in this process' chunk of the density matrix
576  // treat this as iterating over all columns, then iterating over half the values
577  // within one column.
578  // If this function has been called, this process' chunk contains half an
579  // outer block or less
580  for (thisTask=0; thisTask<numTasks; thisTask++) {
581  // we want to process all columns in the density matrix,
582  // updating the values for half of each column (one half of each inner block)
583  thisOuterColumn = thisTask / sizeOuterHalfColumn;
584  thisIndexInOuterColumn = thisTask&(sizeOuterHalfColumn-1); // thisTask % sizeOuterHalfColumn
585  thisInnerBlock = thisIndexInOuterColumn/sizeInnerHalfBlock;
586  // get index in state vector corresponding to upper inner block
587  thisIndexInInnerBlock = thisTask&(sizeInnerHalfBlock-1); // thisTask % sizeInnerHalfBlock
588  thisIndex = thisOuterColumn*sizeOuterColumn + thisInnerBlock*sizeInnerBlock
589  + thisIndexInInnerBlock;
590  // check if we are in the upper or lower half of an outer block
591  outerBit = extractBit(targetQubit, (thisIndex+qureg.numAmpsPerChunk*qureg.chunkId)>>qureg.numQubitsRepresented);
592  // if we are in the lower half of an outer block, shift to be in the lower half
593  // of the inner block as well (we want to dephase |0><0| and |1><1| only)
594  thisIndex += outerBit*(sizeInnerHalfBlock);
595 
596  // NOTE: at this point thisIndex should be the index of the element we want to
597  // dephase in the chunk of the state vector on this process, in the
598  // density matrix representation.
599  // thisTask is the index of the pair element in pairStateVec
600  // we will populate the second half of pairStateVec with this process'
601  // data to send
602 
603  qureg.pairStateVec.real[thisTask+numTasks] = qureg.stateVec.real[thisIndex];
604  qureg.pairStateVec.imag[thisTask+numTasks] = qureg.stateVec.imag[thisIndex];
605 
606  }
607  }
608 }

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

Referenced by densmatr_mixDamping(), and densmatr_mixDepolarising().

◆ compressPairVectorForTwoQubitDepolarise()

void compressPairVectorForTwoQubitDepolarise ( Qureg  qureg,
int  targetQubit,
int  qubit2 
)

Definition at line 610 of file QuEST_cpu_distributed.c.

611  {
612 
613  long long int sizeInnerBlockQ1, sizeInnerHalfBlockQ1;
614  long long int sizeInnerBlockQ2, sizeInnerHalfBlockQ2, sizeInnerQuarterBlockQ2;
615  long long int sizeOuterColumn, sizeOuterQuarterColumn;
616  long long int
617  thisInnerBlockQ2,
618  thisOuterColumn, // current column in density matrix
619  thisIndex, // current index in (density matrix representation) state vector
620  thisIndexInOuterColumn,
621  thisIndexInInnerBlockQ1,
622  thisIndexInInnerBlockQ2,
623  thisInnerBlockQ1InInnerBlockQ2;
624  int outerBitQ1, outerBitQ2;
625 
626  long long int thisTask;
627  long long int numTasks=qureg.numAmpsPerChunk>>2;
628 
629  // set dimensions
630  sizeInnerHalfBlockQ1 = 1LL << targetQubit;
631  sizeInnerHalfBlockQ2 = 1LL << qubit2;
632  sizeInnerQuarterBlockQ2 = sizeInnerHalfBlockQ2 >> 1;
633  sizeInnerBlockQ2 = sizeInnerHalfBlockQ2 << 1;
634  sizeInnerBlockQ1 = 2LL * sizeInnerHalfBlockQ1;
635  sizeOuterColumn = 1LL << qureg.numQubitsRepresented;
636  sizeOuterQuarterColumn = sizeOuterColumn >> 2;
637 
638 # ifdef _OPENMP
639 # pragma omp parallel \
640  default (none) \
641  shared (sizeInnerBlockQ1,sizeInnerHalfBlockQ1,sizeInnerQuarterBlockQ2,sizeInnerHalfBlockQ2,sizeInnerBlockQ2, \
642  sizeOuterColumn,sizeOuterQuarterColumn,qureg,numTasks,targetQubit,qubit2) \
643  private (thisTask,thisInnerBlockQ2,thisOuterColumn,thisIndex,thisIndexInOuterColumn, \
644  thisIndexInInnerBlockQ1,thisIndexInInnerBlockQ2,thisInnerBlockQ1InInnerBlockQ2,outerBitQ1,outerBitQ2)
645 # endif
646  {
647 # ifdef _OPENMP
648 # pragma omp for schedule (static)
649 # endif
650  // thisTask iterates over half the elements in this process' chunk of the density matrix
651  // treat this as iterating over all columns, then iterating over half the values
652  // within one column.
653  // If this function has been called, this process' chunk contains half an
654  // outer block or less
655  for (thisTask=0; thisTask<numTasks; thisTask++) {
656  // we want to process all columns in the density matrix,
657  // updating the values for half of each column (one half of each inner block)
658  thisOuterColumn = thisTask / sizeOuterQuarterColumn;
659  // thisTask % sizeOuterQuarterColumn
660  thisIndexInOuterColumn = thisTask&(sizeOuterQuarterColumn-1);
661  thisInnerBlockQ2 = thisIndexInOuterColumn / sizeInnerQuarterBlockQ2;
662  // thisTask % sizeInnerQuarterBlockQ2;
663  thisIndexInInnerBlockQ2 = thisTask&(sizeInnerQuarterBlockQ2-1);
664  thisInnerBlockQ1InInnerBlockQ2 = thisIndexInInnerBlockQ2 / sizeInnerHalfBlockQ1;
665  // thisTask % sizeInnerHalfBlockQ1;
666  thisIndexInInnerBlockQ1 = thisTask&(sizeInnerHalfBlockQ1-1);
667 
668  // get index in state vector corresponding to upper inner block
669  thisIndex = thisOuterColumn*sizeOuterColumn + thisInnerBlockQ2*sizeInnerBlockQ2
670  + thisInnerBlockQ1InInnerBlockQ2*sizeInnerBlockQ1 + thisIndexInInnerBlockQ1;
671 
672  // check if we are in the upper or lower half of an outer block for Q1
673  outerBitQ1 = extractBit(targetQubit, (thisIndex+qureg.numAmpsPerChunk*qureg.chunkId)>>qureg.numQubitsRepresented);
674  // if we are in the lower half of an outer block, shift to be in the lower half
675  // of the inner block as well (we want to dephase |0><0| and |1><1| only)
676  thisIndex += outerBitQ1*(sizeInnerHalfBlockQ1);
677 
678  // check if we are in the upper or lower half of an outer block for Q2
679  outerBitQ2 = extractBit(qubit2, (thisIndex+qureg.numAmpsPerChunk*qureg.chunkId)>>qureg.numQubitsRepresented);
680  // if we are in the lower half of an outer block, shift to be in the lower half
681  // of the inner block as well (we want to dephase |0><0| and |1><1| only)
682  thisIndex += outerBitQ2*(sizeInnerQuarterBlockQ2<<1);
683 
684  // NOTE: at this point thisIndex should be the index of the element we want to
685  // dephase in the chunk of the state vector on this process, in the
686  // density matrix representation.
687  // thisTask is the index of the pair element in pairStateVec
688 
689  // state[thisIndex] = (1-depolLevel)*state[thisIndex] + depolLevel*(state[thisIndex]
690  // + pair[thisTask])/2
691  qureg.pairStateVec.real[thisTask+numTasks*2] = qureg.stateVec.real[thisIndex];
692  qureg.pairStateVec.imag[thisTask+numTasks*2] = qureg.stateVec.imag[thisIndex];
693  }
694  }
695 }

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

Referenced by densmatr_mixTwoQubitDepolarising().

◆ copyDiagOpIntoMatrixPairState()

void copyDiagOpIntoMatrixPairState ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 1482 of file QuEST_cpu_distributed.c.

1482  {
1483 
1484  /* since, for every elem in 2^N op, there is a column in 2^N x 2^N qureg,
1485  * we know immediately (by each node containing at least 1 element of op)
1486  * that every node contains at least 1 column. Hence, we know that pairStateVec
1487  * of qureg can fit the entirety of op.
1488  */
1489 
1490  // load up our local contribution
1491  long long int localOffset = qureg.chunkId * op.numElemsPerChunk;
1492  memcpy(&qureg.pairStateVec.real[localOffset], op.real, op.numElemsPerChunk * sizeof(qreal));
1493  memcpy(&qureg.pairStateVec.imag[localOffset], op.imag, op.numElemsPerChunk * sizeof(qreal));
1494 
1495  // work out how many messages are needed to send op chunks (2GB limit)
1496  long long int maxMsgSize = MPI_MAX_AMPS_IN_MSG;
1497  if (op.numElemsPerChunk < maxMsgSize)
1498  maxMsgSize = op.numElemsPerChunk;
1499  int numMsgs = op.numElemsPerChunk / maxMsgSize; // since MPI_MAX... = 2^n, division is exact
1500 
1501  // each node has a turn at broadcasting its contribution of op
1502  for (int broadcaster=0; broadcaster < qureg.numChunks; broadcaster++) {
1503  long long int broadOffset = broadcaster * op.numElemsPerChunk;
1504 
1505  // (while keeping each message smaller than MPI max)
1506  for (int i=0; i<numMsgs; i++) {
1507  MPI_Bcast(
1508  &qureg.pairStateVec.real[broadOffset + i*maxMsgSize],
1509  maxMsgSize, MPI_QuEST_REAL, broadcaster, MPI_COMM_WORLD);
1510  MPI_Bcast(
1511  &qureg.pairStateVec.imag[broadOffset + i*maxMsgSize],
1512  maxMsgSize, MPI_QuEST_REAL, broadcaster, MPI_COMM_WORLD);
1513  }
1514  }
1515 }

References Qureg::chunkId, DiagonalOp::imag, Qureg::numChunks, DiagonalOp::numElemsPerChunk, Qureg::pairStateVec, qreal, and DiagonalOp::real.

Referenced by densmatr_applyDiagonalOp().

◆ copyVecIntoMatrixPairState()

void copyVecIntoMatrixPairState ( Qureg  matr,
Qureg  vec 
)

This copies/clones vec (a statevector) into every node's matr pairState.

(where matr is a density matrix or equal number of qubits as vec)

Definition at line 371 of file QuEST_cpu_distributed.c.

371  {
372 
373  // Remember that for every amplitude that `vec` stores on the node,
374  // `matr` stores an entire column. Ergo there are always an integer
375  // number (in fact, a power of 2) number of `matr`s columns on each node.
376  // Since the total size of `vec` (between all nodes) is one column
377  // and each node stores (possibly) multiple columns (vec.numAmpsPerChunk as many),
378  // `vec` can be fit entirely inside a single node's matr.pairStateVec (with excess!)
379 
380  // copy this node's vec segment into this node's matr pairState (in the right spot)
381  long long int numLocalAmps = vec.numAmpsPerChunk;
382  long long int myOffset = vec.chunkId * numLocalAmps;
383  memcpy(&matr.pairStateVec.real[myOffset], vec.stateVec.real, numLocalAmps * sizeof(qreal));
384  memcpy(&matr.pairStateVec.imag[myOffset], vec.stateVec.imag, numLocalAmps * sizeof(qreal));
385 
386  // we now want to share this node's vec segment with other node, so that
387  // vec is cloned in every node's matr.pairStateVec
388 
389  // work out how many messages needed to send vec chunks (2GB limit)
390  long long int maxMsgSize = MPI_MAX_AMPS_IN_MSG;
391  if (numLocalAmps < maxMsgSize)
392  maxMsgSize = numLocalAmps;
393  // safely assume MPI_MAX... = 2^n, so division always exact:
394  int numMsgs = numLocalAmps / maxMsgSize;
395 
396  // every node gets a turn at being the broadcaster
397  for (int broadcaster=0; broadcaster < vec.numChunks; broadcaster++) {
398 
399  long long int otherOffset = broadcaster * numLocalAmps;
400 
401  // every node sends a slice of qureg's pairState to every other
402  for (int i=0; i< numMsgs; i++) {
403 
404  // by sending that slice in further slices (due to bandwidth limit)
405  MPI_Bcast(
406  &matr.pairStateVec.real[otherOffset + i*maxMsgSize],
407  maxMsgSize, MPI_QuEST_REAL, broadcaster, MPI_COMM_WORLD);
408  MPI_Bcast(
409  &matr.pairStateVec.imag[otherOffset + i*maxMsgSize],
410  maxMsgSize, MPI_QuEST_REAL, broadcaster, MPI_COMM_WORLD);
411  }
412  }
413 }

References Qureg::chunkId, Qureg::numAmpsPerChunk, Qureg::numChunks, Qureg::pairStateVec, qreal, and Qureg::stateVec.

Referenced by densmatr_calcFidelity(), and densmatr_initPureState().

◆ densityMatrixBlockFitsInChunk()

static int densityMatrixBlockFitsInChunk ( long long int  chunkSize,
int  numQubits,
int  targetQubit 
)
static

Definition at line 363 of file QuEST_cpu_distributed.c.

363  {
364  long long int sizeOuterHalfBlock = 1LL << (targetQubit+numQubits);
365  if (chunkSize > sizeOuterHalfBlock) return 1;
366  else return 0;
367 }

Referenced by densmatr_mixDamping(), densmatr_mixDepolarising(), and densmatr_mixTwoQubitDepolarising().

◆ densmatr_applyDiagonalOp()

void densmatr_applyDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 1517 of file QuEST_cpu_distributed.c.

1517  {
1518 
1519  copyDiagOpIntoMatrixPairState(qureg, op);
1520  densmatr_applyDiagonalOpLocal(qureg, op);
1521 }

References copyDiagOpIntoMatrixPairState(), and densmatr_applyDiagonalOpLocal().

◆ densmatr_calcExpecDiagonalOp()

Complex densmatr_calcExpecDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 1541 of file QuEST_cpu_distributed.c.

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

References densmatr_calcExpecDiagonalOpLocal(), Complex::imag, Qureg::numChunks, qreal, and Complex::real.

◆ densmatr_calcFidelity()

qreal densmatr_calcFidelity ( Qureg  qureg,
Qureg  pureState 
)

Definition at line 415 of file QuEST_cpu_distributed.c.

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

References copyVecIntoMatrixPairState(), densmatr_calcFidelityLocal(), and qreal.

◆ densmatr_calcHilbertSchmidtDistance()

qreal densmatr_calcHilbertSchmidtDistance ( Qureg  a,
Qureg  b 
)

Definition at line 430 of file QuEST_cpu_distributed.c.

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

References densmatr_calcHilbertSchmidtDistanceSquaredLocal(), and qreal.

◆ densmatr_calcInnerProduct()

qreal densmatr_calcInnerProduct ( Qureg  a,
Qureg  b 
)

Definition at line 441 of file QuEST_cpu_distributed.c.

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

References densmatr_calcInnerProductLocal(), and qreal.

◆ densmatr_calcProbOfOutcome()

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

Definition at line 1276 of file QuEST_cpu_distributed.c.

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

References densmatr_findProbabilityOfZeroLocal(), and qreal.

◆ densmatr_calcPurity()

qreal densmatr_calcPurity ( Qureg  qureg)

Definition at line 1288 of file QuEST_cpu_distributed.c.

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

References densmatr_calcPurityLocal(), and qreal.

◆ 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, Qureg::numAmpsPerChunk, Qureg::numChunks, Qureg::numQubitsRepresented, qreal, and Qureg::stateVec.

◆ densmatr_initPureState()

void densmatr_initPureState ( Qureg  targetQureg,
Qureg  copyQureg 
)

Definition at line 452 of file QuEST_cpu_distributed.c.

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

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

◆ densmatr_mixDamping()

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

Definition at line 725 of file QuEST_cpu_distributed.c.

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

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

◆ densmatr_mixDepolarising()

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

Definition at line 698 of file QuEST_cpu_distributed.c.

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

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

◆ densmatr_mixTwoQubitDepolarising()

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

Definition at line 752 of file QuEST_cpu_distributed.c.

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

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

◆ exchangePairStateVectorHalves()

void exchangePairStateVectorHalves ( Qureg  qureg,
int  pairRank 
)

Definition at line 509 of file QuEST_cpu_distributed.c.

509  {
510  // MPI send/receive vars
511  int TAG=100;
512  MPI_Status status;
513  long long int numAmpsToSend = qureg.numAmpsPerChunk >> 1;
514 
515  // Multiple messages are required as MPI uses int rather than long long int for count
516  // For openmpi, messages are further restricted to 2GB in size -- do this for all cases
517  // to be safe
518  long long int maxMessageCount = MPI_MAX_AMPS_IN_MSG;
519  if (numAmpsToSend < maxMessageCount)
520  maxMessageCount = numAmpsToSend;
521 
522  // safely assume MPI_MAX... = 2^n, so division always exact
523  int numMessages = numAmpsToSend/maxMessageCount;
524  int i;
525  long long int offset;
526  // send the bottom half of my state vector to the top half of pairRank's qureg.pairStateVec
527  // receive pairRank's state vector into the top of qureg.pairStateVec
528  for (i=0; i<numMessages; i++){
529  offset = i*maxMessageCount;
530  MPI_Sendrecv(&qureg.pairStateVec.real[offset+numAmpsToSend], maxMessageCount,
531  MPI_QuEST_REAL, pairRank, TAG,
532  &qureg.pairStateVec.real[offset], maxMessageCount, MPI_QuEST_REAL,
533  pairRank, TAG, MPI_COMM_WORLD, &status);
534  //printf("rank: %d err: %d\n", qureg.rank, err);
535  MPI_Sendrecv(&qureg.pairStateVec.imag[offset+numAmpsToSend], maxMessageCount,
536  MPI_QuEST_REAL, pairRank, TAG,
537  &qureg.pairStateVec.imag[offset], maxMessageCount, MPI_QuEST_REAL,
538  pairRank, TAG, MPI_COMM_WORLD, &status);
539  }
540 }

References Qureg::numAmpsPerChunk, and Qureg::pairStateVec.

Referenced by densmatr_mixDamping(), densmatr_mixDepolarising(), and densmatr_mixTwoQubitDepolarising().

◆ exchangeStateVectors()

void exchangeStateVectors ( Qureg  qureg,
int  pairRank 
)

Definition at line 479 of file QuEST_cpu_distributed.c.

479  {
480  // MPI send/receive vars
481  int TAG=100;
482  MPI_Status status;
483 
484  // Multiple messages are required as MPI uses int rather than long long int for count
485  // For openmpi, messages are further restricted to 2GB in size -- do this for all cases
486  // to be safe
487  long long int maxMessageCount = MPI_MAX_AMPS_IN_MSG;
488  if (qureg.numAmpsPerChunk < maxMessageCount)
489  maxMessageCount = qureg.numAmpsPerChunk;
490 
491  // safely assume MPI_MAX... = 2^n, so division always exact
492  int numMessages = qureg.numAmpsPerChunk/maxMessageCount;
493  int i;
494  long long int offset;
495  // send my state vector to pairRank's qureg.pairStateVec
496  // receive pairRank's state vector into qureg.pairStateVec
497  for (i=0; i<numMessages; i++){
498  offset = i*maxMessageCount;
499  MPI_Sendrecv(&qureg.stateVec.real[offset], maxMessageCount, MPI_QuEST_REAL, pairRank, TAG,
500  &qureg.pairStateVec.real[offset], maxMessageCount, MPI_QuEST_REAL,
501  pairRank, TAG, MPI_COMM_WORLD, &status);
502  //printf("rank: %d err: %d\n", qureg.rank, err);
503  MPI_Sendrecv(&qureg.stateVec.imag[offset], maxMessageCount, MPI_QuEST_REAL, pairRank, TAG,
504  &qureg.pairStateVec.imag[offset], maxMessageCount, MPI_QuEST_REAL,
505  pairRank, TAG, MPI_COMM_WORLD, &status);
506  }
507 }

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

Referenced by statevec_compactUnitary(), statevec_controlledCompactUnitary(), statevec_controlledNot(), statevec_controlledPauliY(), statevec_controlledPauliYConj(), statevec_controlledUnitary(), statevec_hadamard(), statevec_multiControlledUnitary(), statevec_pauliX(), statevec_pauliY(), statevec_pauliYConj(), statevec_swapQubitAmps(), and statevec_unitary().

◆ getChunkIdFromIndex()

int getChunkIdFromIndex ( Qureg  qureg,
long long int  index 
)
static

Definition at line 194 of file QuEST_cpu_distributed.c.

194  {
195  return index/qureg.numAmpsPerChunk; // this is numAmpsPerChunk
196 }

References Qureg::numAmpsPerChunk.

Referenced by statevec_getImagAmp(), and statevec_getRealAmp().

◆ getChunkOuterBlockPairId()

static int getChunkOuterBlockPairId ( int  chunkIsUpper,
int  chunkId,
long long int  chunkSize,
int  targetQubit,
int  numQubits 
)
static

Definition at line 314 of file QuEST_cpu_distributed.c.

315 {
316  long long int sizeOuterHalfBlock = 1LL << (targetQubit+numQubits);
317  int chunksPerOuterHalfBlock = sizeOuterHalfBlock/chunkSize;
318  if (chunkIsUpper){
319  return chunkId + chunksPerOuterHalfBlock;
320  } else {
321  return chunkId - chunksPerOuterHalfBlock;
322  }
323 }

References chunkIsUpper().

Referenced by densmatr_mixDamping(), densmatr_mixDepolarising(), and densmatr_mixTwoQubitDepolarising().

◆ getChunkOuterBlockPairIdForPart3()

static int getChunkOuterBlockPairIdForPart3 ( int  chunkIsUpperSmallerQubit,
int  chunkIsUpperBiggerQubit,
int  chunkId,
long long int  chunkSize,
int  smallerQubit,
int  biggerQubit,
int  numQubits 
)
static

Definition at line 325 of file QuEST_cpu_distributed.c.

327 {
328  long long int sizeOuterHalfBlockBiggerQubit = 1LL << (biggerQubit+numQubits);
329  long long int sizeOuterHalfBlockSmallerQubit = 1LL << (smallerQubit+numQubits);
330  int chunksPerOuterHalfBlockSmallerQubit = sizeOuterHalfBlockSmallerQubit/chunkSize;
331  int chunksPerOuterHalfBlockBiggerQubit = sizeOuterHalfBlockBiggerQubit/chunkSize;
332  int rank;
333  if (chunkIsUpperBiggerQubit){
334  rank = chunkId + chunksPerOuterHalfBlockBiggerQubit;
335  } else {
336  rank = chunkId - chunksPerOuterHalfBlockBiggerQubit;
337  }
338 
339  if (chunkIsUpperSmallerQubit){
340  rank = rank + chunksPerOuterHalfBlockSmallerQubit;
341  } else {
342  rank = rank - chunksPerOuterHalfBlockSmallerQubit;
343  }
344 
345  return rank;
346 }

Referenced by densmatr_mixTwoQubitDepolarising().

◆ getChunkPairId()

static int getChunkPairId ( int  chunkIsUpper,
int  chunkId,
long long int  chunkSize,
int  targetQubit 
)
static

get position of corresponding chunk, holding values required to update values in my chunk (with chunkId) when rotating targetQubit.

Parameters
[in]chunkIsUpper1: chunk is in upper half of block, 0: chunk is in lower half
[in]chunkIdid of chunk in state vector
[in]chunkSizenumber of amps in chunk
[in]targetQubitqubit being rotated
Returns
chunkId of chunk required to rotate targetQubit

Definition at line 303 of file QuEST_cpu_distributed.c.

304 {
305  long long int sizeHalfBlock = 1LL << (targetQubit);
306  int chunksPerHalfBlock = sizeHalfBlock/chunkSize;
307  if (chunkIsUpper){
308  return chunkId + chunksPerHalfBlock;
309  } else {
310  return chunkId - chunksPerHalfBlock;
311  }
312 }

References chunkIsUpper().

Referenced by statevec_compactUnitary(), statevec_controlledCompactUnitary(), statevec_controlledNot(), statevec_controlledPauliY(), statevec_controlledPauliYConj(), statevec_controlledUnitary(), statevec_hadamard(), statevec_multiControlledUnitary(), statevec_pauliX(), statevec_pauliY(), statevec_pauliYConj(), and statevec_unitary().

◆ getGlobalIndOfOddParityInChunk()

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, otherwise returns the global index of one of such contained amplitudes (not necessarily the first)

Definition at line 1335 of file QuEST_cpu_distributed.c.

1335  {
1336  long long int chunkStartInd = qureg.numAmpsPerChunk * qureg.chunkId;
1337  long long int chunkEndInd = chunkStartInd + qureg.numAmpsPerChunk; // exclusive
1338  long long int oddParityInd;
1339 
1340  if (extractBit(qb1, chunkStartInd) != extractBit(qb2, chunkStartInd))
1341  return chunkStartInd;
1342 
1343  oddParityInd = flipBit(chunkStartInd, qb1);
1344  if (oddParityInd >= chunkStartInd && oddParityInd < chunkEndInd)
1345  return oddParityInd;
1346 
1347  oddParityInd = flipBit(chunkStartInd, qb2);
1348  if (oddParityInd >= chunkStartInd && oddParityInd < chunkEndInd)
1349  return oddParityInd;
1350 
1351  return -1;
1352 }

References Qureg::chunkId, extractBit(), flipBit(), and Qureg::numAmpsPerChunk.

Referenced by statevec_swapQubitAmps().

◆ getRotAngle()

static void getRotAngle ( int  chunkIsUpper,
Complex rot1,
Complex rot2,
Complex  alpha,
Complex  beta 
)
static

Get rotation values for a given chunk.

Parameters
[in]chunkIsUpper1: chunk is in upper half of block, 0: chunk is in lower half
[out]rot1,rot2rotation values to use, allocated for upper/lower such that
stateUpper = rot1 * stateUpper + conj(rot2)  * stateLower
or
stateLower = rot1 * stateUpper + conj(rot2)  * stateLower
[in]alpha,betainitial rotation values

Definition at line 258 of file QuEST_cpu_distributed.c.

259 {
260  if (chunkIsUpper){
261  *rot1=alpha;
262  rot2->real=-beta.real;
263  rot2->imag=-beta.imag;
264  } else {
265  *rot1=beta;
266  *rot2=alpha;
267  }
268 }

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

Referenced by statevec_compactUnitary(), and statevec_controlledCompactUnitary().

◆ getRotAngleFromUnitaryMatrix()

static void getRotAngleFromUnitaryMatrix ( int  chunkIsUpper,
Complex rot1,
Complex rot2,
ComplexMatrix2  u 
)
static

Get rotation values for a given chunk given a unitary matrix.

Parameters
[in]chunkIsUpper1: chunk is in upper half of block, 0: chunk is in lower half
[out]rot1,rot2rotation values to use, allocated for upper/lower such that
stateUpper = rot1 * stateUpper + conj(rot2)  * stateLower
or
stateLower = rot1 * stateUpper + conj(rot2)  * stateLower
[in]uunitary matrix operation

Definition at line 283 of file QuEST_cpu_distributed.c.

284 {
285  if (chunkIsUpper){
286  *rot1=(Complex) {.real=u.real[0][0], .imag=u.imag[0][0]};
287  *rot2=(Complex) {.real=u.real[0][1], .imag=u.imag[0][1]};
288  } else {
289  *rot1=(Complex) {.real=u.real[1][0], .imag=u.imag[1][0]};
290  *rot2=(Complex) {.real=u.real[1][1], .imag=u.imag[1][1]};
291  }
292 }

References chunkIsUpper(), ComplexMatrix2::imag, Complex::real, and ComplexMatrix2::real.

Referenced by statevec_controlledUnitary(), statevec_multiControlledUnitary(), and statevec_unitary().

◆ halfMatrixBlockFitsInChunk()

static int halfMatrixBlockFitsInChunk ( long long int  chunkSize,
int  targetQubit 
)
static

return whether the current qubit rotation will use blocks that fit within a single chunk.

Parameters
[in]chunkSizenumber of amps in chunk
[in]targetQubitqubit being rotated
Returns
1: one chunk fits in one block 0: chunk is larger than block fix – this should be renamed to matrixBlockFitsInChunk

Definition at line 356 of file QuEST_cpu_distributed.c.

357 {
358  long long int sizeHalfBlock = 1LL << (targetQubit);
359  if (chunkSize > sizeHalfBlock) return 1;
360  else return 0;
361 }

Referenced by statevec_calcProbOfOutcome(), statevec_collapseToKnownProbOutcome(), statevec_compactUnitary(), statevec_controlledCompactUnitary(), statevec_controlledNot(), statevec_controlledPauliY(), statevec_controlledPauliYConj(), statevec_controlledUnitary(), statevec_hadamard(), statevec_multiControlledMultiQubitUnitary(), statevec_multiControlledTwoQubitUnitary(), statevec_multiControlledUnitary(), statevec_pauliX(), statevec_pauliY(), statevec_pauliYConj(), statevec_swapQubitAmps(), and statevec_unitary().

◆ isChunkToSkipInFindPZero()

static int isChunkToSkipInFindPZero ( int  chunkId,
long long int  chunkSize,
int  measureQubit 
)
static

Find chunks to skip when calculating probability of qubit being zero.

When calculating probability of a bit q being zero, sum up 2^q values, then skip 2^q values, etc. This function finds if an entire chunk is in the range of values to be skipped

Parameters
[in]chunkIdid of chunk in state vector
[in]chunkSizenumber of amps in chunk
[in]measureQubiqubit being measured
Returns
int – 1: skip, 0: don't skip

Definition at line 1251 of file QuEST_cpu_distributed.c.

1252 {
1253  long long int sizeHalfBlock = 1LL << (measureQubit);
1254  int numChunksToSkip = sizeHalfBlock/chunkSize;
1255  // calculate probability by summing over numChunksToSkip, then skipping numChunksToSkip, etc
1256  int bitToCheck = chunkId & numChunksToSkip;
1257  return bitToCheck;
1258 }

Referenced by statevec_calcProbOfOutcome(), and statevec_collapseToKnownProbOutcome().

◆ statevec_calcExpecDiagonalOp()

Complex statevec_calcExpecDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Definition at line 1523 of file QuEST_cpu_distributed.c.

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

References Complex::imag, Qureg::numChunks, qreal, Complex::real, and statevec_calcExpecDiagonalOpLocal().

◆ statevec_calcInnerProduct()

Complex statevec_calcInnerProduct ( Qureg  bra,
Qureg  ket 
)

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 Complex::imag, Qureg::numChunks, qreal, Complex::real, and statevec_calcInnerProductLocal().

◆ statevec_calcProbOfOutcome()

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

Definition at line 1260 of file QuEST_cpu_distributed.c.

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

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

◆ 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 Qureg::numAmpsPerChunk, Qureg::numChunks, qreal, and Qureg::stateVec.

◆ statevec_collapseToKnownProbOutcome()

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

Definition at line 1298 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_compactUnitary()

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

Definition at line 844 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_controlledCompactUnitary()

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

Definition at line 920 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_controlledNot()

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

Definition at line 1061 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_controlledPauliY()

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

Definition at line 1140 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_controlledPauliYConj()

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

Definition at line 1173 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_controlledUnitary()

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

Definition at line 958 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_getImagAmp()

qreal statevec_getImagAmp ( Qureg  qureg,
long long int  index 
)

Definition at line 208 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_getRealAmp()

qreal statevec_getRealAmp ( Qureg  qureg,
long long int  index 
)

Definition at line 198 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_hadamard()

void statevec_hadamard ( Qureg  qureg,
int  targetQubit 
)

Definition at line 1206 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_multiControlledMultiQubitUnitary()

void statevec_multiControlledMultiQubitUnitary ( Qureg  qureg,
long long int  ctrlMask,
int *  targs,
int  numTargs,
ComplexMatrixN  u 
)

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

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

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

Definition at line 1437 of file QuEST_cpu_distributed.c.

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

References flipBit(), getQubitBitMask(), halfMatrixBlockFitsInChunk(), maskContainsBit(), Qureg::numAmpsPerChunk, statevec_multiControlledMultiQubitUnitaryLocal(), and statevec_swapQubitAmps().

◆ statevec_multiControlledTwoQubitUnitary()

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

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

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

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

Definition at line 1381 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_multiControlledUnitary()

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

Definition at line 997 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_pauliX()

void statevec_pauliX ( Qureg  qureg,
int  targetQubit 
)

Definition at line 1034 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_pauliY()

void statevec_pauliY ( Qureg  qureg,
int  targetQubit 
)

Definition at line 1090 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_pauliYConj()

void statevec_pauliYConj ( Qureg  qureg,
int  targetQubit 
)

Definition at line 1115 of file QuEST_cpu_distributed.c.

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

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

◆ statevec_swapQubitAmps()

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

Definition at line 1354 of file QuEST_cpu_distributed.c.

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

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

Referenced by statevec_multiControlledMultiQubitUnitary(), and statevec_multiControlledTwoQubitUnitary().

◆ statevec_unitary()

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

Definition at line 881 of file QuEST_cpu_distributed.c.

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

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

void statevec_controlledNotLocal(Qureg qureg, int controlQubit, int targetQubit)
Definition: QuEST_cpu.c:2584
static void getRotAngle(int chunkIsUpper, Complex *rot1, Complex *rot2, Complex alpha, Complex beta)
Get rotation values for a given chunk.
void statevec_pauliYLocal(Qureg qureg, int targetQubit, int conjFac)
Definition: QuEST_cpu.c:2682
qreal densmatr_calcHilbertSchmidtDistanceSquaredLocal(Qureg a, Qureg b)
computes Tr((a-b) conjTrans(a-b)) = sum of abs values of (a-b)
Definition: QuEST_cpu.c:923
static int isChunkToSkipInFindPZero(int chunkId, long long int chunkSize, int measureQubit)
Find chunks to skip when calculating probability of qubit being zero.
ComplexArray pairStateVec
Temporary storage for a chunk of the state vector received from another process in the MPI version.
Definition: QuEST.h:224
qreal statevec_findProbabilityOfZeroDistributed(Qureg qureg)
Measure the probability of a specified qubit being in the zero state across all amplitudes held in th...
Definition: QuEST_cpu.c:3262
void densmatr_mixDepolarisingDistributed(Qureg qureg, int targetQubit, qreal depolLevel)
Definition: QuEST_cpu.c:224
void densmatr_mixTwoQubitDepolarisingQ1LocalQ2DistributedPart3(Qureg qureg, int targetQubit, int qubit2, qreal delta, qreal gamma)
Definition: QuEST_cpu.c:632
int numChunks
Number of chunks the state vector is broken up into – the number of MPI processes used.
Definition: QuEST.h:219
void statevec_swapQubitAmpsLocal(Qureg qureg, int qb1, int qb2)
It is ensured that all amplitudes needing to be swapped are on this node.
Definition: QuEST_cpu.c:3536
void statevec_multiControlledUnitaryDistributed(Qureg qureg, int targetQubit, long long int ctrlQubitsMask, long long int ctrlFlipMask, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Apply a unitary operation to a single qubit in the state vector of probability amplitudes,...
Definition: QuEST_cpu.c:2447
void statevec_controlledUnitaryDistributed(Qureg qureg, int controlQubit, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Rotate a single qubit in the state vector of probability amplitudes, given two complex numbers alpha ...
Definition: QuEST_cpu.c:2381
void statevec_collapseToKnownProbOutcomeLocal(Qureg qureg, int measureQubit, int outcome, qreal totalProbability)
Update the state vector to be consistent with measuring measureQubit=0 if outcome=0 and measureQubit=...
Definition: QuEST_cpu.c:3380
void compressPairVectorForTwoQubitDepolarise(Qureg qureg, int targetQubit, int qubit2)
void statevec_compactUnitaryLocal(Qureg qureg, int targetQubit, Complex alpha, Complex beta)
Definition: QuEST_cpu.c:1688
qreal densmatr_calcPurityLocal(Qureg qureg)
Definition: QuEST_cpu.c:861
Complex statevec_calcExpecDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:3738
void statevec_multiControlledMultiQubitUnitaryLocal(Qureg qureg, long long int ctrlMask, int *targs, int numTargs, ComplexMatrixN u)
Definition: QuEST_cpu.c:1846
void statevec_multiControlledTwoQubitUnitaryLocal(Qureg qureg, long long int ctrlMask, int q1, int q2, ComplexMatrix4 u)
Definition: QuEST_cpu.c:1747
void statevec_pauliXDistributed(Qureg qureg, ComplexArray stateVecIn, ComplexArray stateVecOut)
Rotate a single qubit by {{0,1},{1,0}.
Definition: QuEST_cpu.c:2556
static int getChunkOuterBlockPairId(int chunkIsUpper, int chunkId, long long int chunkSize, int targetQubit, int numQubits)
void copyVecIntoMatrixPairState(Qureg matr, Qureg vec)
This copies/clones vec (a statevector) into every node's matr pairState.
#define qreal
void exchangePairStateVectorHalves(Qureg qureg, int pairRank)
__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)
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...
void statevec_collapseToOutcomeDistributedSetZero(Qureg qureg)
Set all amplitudes in one chunk to 0.
Definition: QuEST_cpu.c:3501
int chunkId
The position of the chunk of the state vector held by this process in the full state vector.
Definition: QuEST.h:217
qreal imag[2][2]
Definition: QuEST.h:117
qreal * imag
The imaginary values of the 2^numQubits complex elements.
Definition: QuEST.h:191
void compressPairVectorForSingleQubitDepolarise(Qureg qureg, int targetQubit)
long long int numAmpsPerChunk
Number of probability amplitudes held in stateVec by this process In the non-MPI version,...
Definition: QuEST.h:213
void densmatr_mixTwoQubitDepolarisingLocal(Qureg qureg, int qubit1, int qubit2, qreal delta, qreal gamma)
Definition: QuEST_cpu.c:387
static void getRotAngleFromUnitaryMatrix(int chunkIsUpper, Complex *rot1, Complex *rot2, ComplexMatrix2 u)
Get rotation values for a given chunk given a unitary matrix.
void statevec_controlledPauliYLocal(Qureg qureg, int controlQubit, int targetQubit, int conjFac)
Definition: QuEST_cpu.c:2776
void densmatr_mixTwoQubitDephasing(Qureg qureg, int qubit1, int qubit2, qreal dephase)
Definition: QuEST_cpu.c:84
void statevec_compactUnitaryDistributed(Qureg qureg, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Rotate a single qubit in the state vector of probability amplitudes, given two complex numbers alpha ...
Definition: QuEST_cpu.c:2001
void exchangeStateVectors(Qureg qureg, int pairRank)
void statevec_multiControlledUnitaryLocal(Qureg qureg, int targetQubit, long long int ctrlQubitsMask, long long int ctrlFlipMask, ComplexMatrix2 u)
Definition: QuEST_cpu.c:2173
long long int getQubitBitMask(int *qubits, int numQubits)
Definition: QuEST_common.c:44
void statevec_pauliYDistributed(Qureg qureg, ComplexArray stateVecIn, ComplexArray stateVecOut, int updateUpper, int conjFac)
Rotate a single qubit by +-{{0,-i},{i,0}.
Definition: QuEST_cpu.c:2739
void densmatr_mixDampingDistributed(Qureg qureg, int targetQubit, qreal damping)
Definition: QuEST_cpu.c:300
Complex densmatr_calcExpecDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:3781
void statevec_pauliXLocal(Qureg qureg, int targetQubit)
Definition: QuEST_cpu.c:2498
void densmatr_initPureStateLocal(Qureg targetQureg, Qureg copyQureg)
Definition: QuEST_cpu.c:1184
__forceinline__ __device__ int extractBit(const int locationOfBitFromRight, const long long int theEncodedNumber)
Definition: QuEST_gpu.cu:82
void densmatr_mixDampingLocal(Qureg qureg, int targetQubit, qreal damping)
Definition: QuEST_cpu.c:174
qreal densmatr_calcInnerProductLocal(Qureg a, Qureg b)
computes Tr(conjTrans(a) b) = sum of (a_ij^* b_ij)
Definition: QuEST_cpu.c:958
static int getChunkIdFromIndex(Qureg qureg, long long int index)
void statevec_unitaryDistributed(Qureg qureg, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Apply a unitary operation to a single qubit given a subset of the state vector with upper and lower b...
Definition: QuEST_cpu.c:2056
void statevec_controlledCompactUnitaryDistributed(Qureg qureg, int controlQubit, Complex rot1, Complex rot2, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut)
Rotate a single qubit in the state vector of probability amplitudes, given two complex numbers alpha ...
Definition: QuEST_cpu.c:2319
static int densityMatrixBlockFitsInChunk(long long int chunkSize, int numQubits, int targetQubit)
ComplexArray stateVec
Computational state amplitudes - a subset thereof in the MPI version.
Definition: QuEST.h:222
qreal real[2][2]
Definition: QuEST.h:116
void densmatr_mixDepolarisingLocal(Qureg qureg, int targetQubit, qreal depolLevel)
Definition: QuEST_cpu.c:125
void statevec_collapseToKnownProbOutcomeDistributedRenorm(Qureg qureg, int measureQubit, qreal totalProbability)
Renormalise parts of the state vector where measureQubit=0 or 1, based on the total probability of th...
Definition: QuEST_cpu.c:3462
static int halfMatrixBlockFitsInChunk(long long int chunkSize, int targetQubit)
return whether the current qubit rotation will use blocks that fit within a single chunk.
long long int numElemsPerChunk
The number of the 2^numQubits amplitudes stored on each distributed node.
Definition: QuEST.h:183
void statevec_hadamardLocal(Qureg qureg, int targetQubit)
Definition: QuEST_cpu.c:2872
void densmatr_applyDiagonalOpLocal(Qureg qureg, DiagonalOp op)
Definition: QuEST_cpu.c:3696
void statevec_controlledUnitaryLocal(Qureg qureg, int controlQubit, int targetQubit, ComplexMatrix2 u)
Definition: QuEST_cpu.c:2241
long long int getGlobalIndOfOddParityInChunk(Qureg qureg, int qb1, int qb2)
returns -1 if this node contains no amplitudes where qb1 and qb2 have opposite parity,...
void densmatr_mixTwoQubitDepolarisingLocalPart1(Qureg qureg, int qubit1, int qubit2, qreal delta)
Definition: QuEST_cpu.c:488
void copyDiagOpIntoMatrixPairState(Qureg qureg, DiagonalOp op)
void statevec_controlledNotDistributed(Qureg qureg, int controlQubit, ComplexArray stateVecIn, ComplexArray stateVecOut)
Rotate a single qubit by {{0,1},{1,0}.
Definition: QuEST_cpu.c:2646
int numQubitsRepresented
The number of qubits represented in either the state-vector or density matrix.
Definition: QuEST.h:208
qreal * real
The real values of the 2^numQubits complex elements.
Definition: QuEST.h:189
qreal real
Definition: QuEST.h:105
void statevec_swapQubitAmpsDistributed(Qureg qureg, int pairRank, int qb1, int qb2)
qureg.pairStateVec contains the entire set of amplitudes of the paired node which includes the set of...
Definition: QuEST_cpu.c:3579
qreal imag
Definition: QuEST.h:106
static int getChunkOuterBlockPairIdForPart3(int chunkIsUpperSmallerQubit, int chunkIsUpperBiggerQubit, int chunkId, long long int chunkSize, int smallerQubit, int biggerQubit, int numQubits)
void densmatr_mixTwoQubitDepolarisingDistributed(Qureg qureg, int targetQubit, int qubit2, qreal delta, qreal gamma)
Definition: QuEST_cpu.c:541
void statevec_unitaryLocal(Qureg qureg, int targetQubit, ComplexMatrix2 u)
Definition: QuEST_cpu.c:1932
qreal densmatr_findProbabilityOfZeroLocal(Qureg qureg, int measureQubit)
Definition: QuEST_cpu.c:3151
static int chunkIsUpperInOuterBlock(int chunkId, long long int chunkSize, int targetQubit, int numQubits)
fix – do with masking instead
Represents one complex number.
Definition: QuEST.h:103
void statevec_hadamardDistributed(Qureg qureg, ComplexArray stateVecUp, ComplexArray stateVecLo, ComplexArray stateVecOut, int updateUpper)
Rotate a single qubit by {{1,1},{1,-1}}/sqrt2.
Definition: QuEST_cpu.c:2932
static int maskContainsBit(const long long int mask, const int bitInd)
void statevec_controlledPauliYDistributed(Qureg qureg, int controlQubit, ComplexArray stateVecIn, ComplexArray stateVecOut, int conjFac)
Definition: QuEST_cpu.c:2830
void statevec_controlledCompactUnitaryLocal(Qureg qureg, int controlQubit, int targetQubit, Complex alpha, Complex beta)
Definition: QuEST_cpu.c:2101
static int chunkIsUpper(int chunkId, long long int chunkSize, int targetQubit)
Returns whether a given chunk in position chunkId is in the upper or lower half of a block.
Complex statevec_calcInnerProductLocal(Qureg bra, Qureg ket)
Definition: QuEST_cpu.c:1071
qreal densmatr_calcFidelityLocal(Qureg qureg, Qureg pureState)
computes a few dens-columns-worth of (vec^*T) dens * vec
Definition: QuEST_cpu.c:990
qreal statevec_findProbabilityOfZeroLocal(Qureg qureg, int measureQubit)
Measure the total probability of a specified qubit being in the zero state across all amplitudes in t...
Definition: QuEST_cpu.c:3206