test_operators.cpp
Go to the documentation of this file.
1 
2 #include "catch.hpp"
3 #include "QuEST.h"
4 #include "utilities.hpp"
5 
6 /* allows concise use of Contains in catch's REQUIRE_THROWS_WITH */
7 using Catch::Matchers::Contains;
8 
9 
10 
15 TEST_CASE( "applyPauliSum", "[operators]" ) {
16 
21 
22  initDebugState(vecIn);
23  initDebugState(matIn);
24 
25  SECTION( "correctness" ) {
26 
27  int numTerms = GENERATE( 1, 2, 10, 15);
28  int numPaulis = numTerms * NUM_QUBITS;
29 
30  // each test will use random coefficients
31  qreal coeffs[numTerms];
32  for (int i=0; i<numTerms; i++)
33  coeffs[i] = getRandomReal(-5, 5);
34 
35  /* it's too expensive to try ALL Pauli sequences, via
36  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numPaulis) );.
37  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
38  * Hence, we instead opt to repeatedly randomly generate pauliseqs
39  */
40  GENERATE( range(0,10) ); // gen 10 random pauli-codes
41  pauliOpType paulis[numPaulis];
42  for (int i=0; i<numPaulis; i++)
43  paulis[i] = (pauliOpType) getRandomInt(0,4);
44 
45  // build the resulting Pauli sum; sum_j coeffs[j] * paulis[n*j : (n+1)j]
46  QMatrix iMatr{{1,0},{0,1}};
47  QMatrix xMatr{{0,1},{1,0}};
48  QMatrix yMatr{{0,-1i},{1i,0}};
49  QMatrix zMatr{{1,0},{0,-1}};
50  QMatrix pauliSum = getZeroMatrix(1<<NUM_QUBITS);
51 
52  for (int t=0; t<numTerms; t++) {
53  QMatrix pauliProd = QMatrix{{1}};
54 
55  for (int q=0; q<NUM_QUBITS; q++) {
56  int i = q + t*NUM_QUBITS;
57 
58  QMatrix fac;
59  if (paulis[i] == PAULI_I) fac = iMatr;
60  if (paulis[i] == PAULI_X) fac = xMatr;
61  if (paulis[i] == PAULI_Y) fac = yMatr;
62  if (paulis[i] == PAULI_Z) fac = zMatr;
63  pauliProd = getKroneckerProduct(fac, pauliProd);
64  }
65  pauliSum += coeffs[t] * pauliProd;
66  }
67 
68  SECTION( "state-vector" ) {
69 
70  QVector vecRef = toQVector(vecIn);
71  applyPauliSum(vecIn, paulis, coeffs, numTerms, vecOut);
72 
73  // ensure vecIn barely changes under precision
74  REQUIRE( areEqual(vecIn, vecRef) );
75 
76  // ensure vecOut changed correctly
77  REQUIRE( areEqual(vecOut, pauliSum * vecRef) );
78  }
79  SECTION( "density-matrix" ) {
80 
81  QMatrix matRef = toQMatrix(matIn);
82  applyPauliSum(matIn, paulis, coeffs, numTerms, matOut);
83 
84  // ensure matIn barely changes under precision
85  REQUIRE( areEqual(matIn, matRef) );
86 
87  // ensure matOut changed correctly
88  REQUIRE( areEqual(matOut, pauliSum * matRef, 1E2*REAL_EPS) );
89  }
90  }
91  SECTION( "input validation" ) {
92 
93  SECTION( "number of terms" ) {
94 
95  int numTerms = GENERATE( -1, 0 );
96  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, NULL, NULL, numTerms, vecOut), Contains("Invalid number of terms") );
97  }
98  SECTION( "pauli codes" ) {
99 
100  // valid codes
101  int numTerms = 3;
102  int numPaulis = numTerms*NUM_QUBITS;
103  pauliOpType paulis[numPaulis];
104  for (int i=0; i<numPaulis; i++)
105  paulis[i] = PAULI_I;
106 
107  // make one invalid
108  paulis[GENERATE_COPY( range(0,numPaulis) )] = (pauliOpType) GENERATE( -1, 4 );
109  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, numTerms, vecOut), Contains("Invalid Pauli code") );
110  }
111  SECTION( "qureg dimensions" ) {
112 
113  Qureg badVec = createQureg(NUM_QUBITS+1, QUEST_ENV);
114  pauliOpType paulis[NUM_QUBITS];
115  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, 1, badVec), Contains("Dimensions of the qubit registers don't match") );
116  destroyQureg(badVec, QUEST_ENV);
117  }
118  SECTION( "qureg types" ) {
119 
120  pauliOpType paulis[NUM_QUBITS];
121  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, 1, matOut), Contains("Registers must both be state-vectors or both be density matrices") );
122  }
123  }
124  destroyQureg(vecIn, QUEST_ENV);
125  destroyQureg(vecOut, QUEST_ENV);
126  destroyQureg(matIn, QUEST_ENV);
127  destroyQureg(matOut, QUEST_ENV);
128 }
pauliOpType
Codes for specifying Pauli operators.
Definition: QuEST.h:96
QuESTEnv QUEST_ENV
The global QuESTEnv instance, to be created and destroyed once in this main(), so that the MPI enviro...
Definition: main.cpp:20
@ PAULI_Z
Definition: QuEST.h:96
@ PAULI_I
Definition: QuEST.h:96
int getRandomInt(int min, int max)
Returns a random integer between min (inclusive) and max (exclusive), from the uniform distribution.
Definition: utilities.cpp:481
#define NUM_QUBITS
The default number of qubits in the registers created for unit testing (both statevectors and density...
Definition: utilities.hpp:36
TEST_CASE("applyPauliSum", "[operators]")
qreal getRandomReal(qreal min, qreal max)
Returns a random real between min (inclusive) and max (exclusive), from the uniform distribution.
Definition: utilities.cpp:410
#define qreal
QMatrix toQMatrix(ComplexMatrix2 src)
Returns a copy of the given 2-by-2 matrix.
Definition: utilities.cpp:835
@ PAULI_X
Definition: QuEST.h:96
std::vector< qcomp > QVector
A complex vector, which can be zero-initialised with QVector(numAmps).
Definition: utilities.hpp:60
QVector toQVector(Qureg qureg)
Returns an equal-size copy of the given state-vector qureg.
Definition: utilities.cpp:904
@ PAULI_Y
Definition: QuEST.h:96
void destroyQureg(Qureg qureg, QuESTEnv env)
Deallocate a Qureg object representing a set of qubits.
Definition: QuEST.c:75
void initDebugState(Qureg qureg)
Initialises qureg to be in the un-normalised, non-physical state with with n-th complex amplitude (2n...
Definition: QuEST.c:1057
void applyPauliSum(Qureg inQureg, enum pauliOpType *allPauliCodes, qreal *termCoeffs, int numSumTerms, Qureg outQureg)
Modifies outQureg to be the result of applying the weighted sum of Pauli products (a Hermitian but no...
Definition: QuEST.c:806
Represents a system of qubits.
Definition: QuEST.h:160
std::vector< std::vector< qcomp > > QMatrix
A complex square matrix.
Definition: utilities.hpp:49
Qureg createQureg(int numQubits, QuESTEnv env)
Create a Qureg object representing a set of qubits which will remain in a pure state.
Definition: QuEST.c:34
QMatrix getKroneckerProduct(QMatrix a, QMatrix b)
Returns the kronecker product of a and b, where a and b are square but possibly differently-sized com...
Definition: utilities.cpp:169
QMatrix getZeroMatrix(size_t dim)
Returns a dim-by-dim square complex matrix, initialised to all zeroes.
Definition: utilities.cpp:143
bool areEqual(QVector a, QVector b)
Returns true if the absolute value of the difference between every amplitude in vectors a and b is le...
Definition: utilities.cpp:387
Qureg createDensityQureg(int numQubits, QuESTEnv env)
Create a Qureg for qubits which are represented by a density matrix, and can be in mixed states.
Definition: QuEST.c:48