test_gates.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( "collapseToOutcome", "[gates]" ) {
16 
19 
20  SECTION( "correctness" ) {
21 
22  int qubit = GENERATE( range(0,NUM_QUBITS) );
23  int outcome = GENERATE( 0, 1 );
24 
25  // repeat these random tests 10 times on every qubit, and for both outcomes
26  GENERATE( range(0,10) );
27 
28  SECTION( "state-vector" ) {
29 
30  // use a random L2 state for every qubit & outcome
32  toQureg(vec, vecRef);
33 
34  // calculate prob of outcome
35  qreal prob = 0;
36  for (size_t ind=0; ind<vecRef.size(); ind++) {
37  int bit = (ind >> qubit) & 1; // target-th bit
38  if (bit == outcome)
39  prob += pow(abs(vecRef[ind]), 2);
40  }
41 
42  // renormalise by the outcome prob
43  for (size_t ind=0; ind<vecRef.size(); ind++) {
44  int bit = (ind >> qubit) & 1; // target-th bit
45  if (bit == outcome)
46  vecRef[ind] /= sqrt(prob);
47  else
48  vecRef[ind] = 0;
49  }
50 
51  qreal res = collapseToOutcome(vec, qubit, outcome);
52  REQUIRE( res == Approx(prob) );
53  REQUIRE( areEqual(vec, vecRef) );
54  }
55  SECTION( "density-matrix" ) {
56 
57  // use a random density matrix for every qubit & outcome
59  toQureg(mat, matRef);
60 
61  // prob is sum of diagonal amps (should be real) where target bit is outcome
62  qcomp tr = 0;
63  for (size_t ind=0; ind<matRef.size(); ind++) {
64  int bit = (ind >> qubit) & 1; // qubit-th bit
65  if (bit == outcome)
66  tr += matRef[ind][ind];
67  }
68  REQUIRE( imag(tr) == Approx(0).margin(REAL_EPS) );
69  qreal prob = real(tr);
70 
71  // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
72  for (size_t r=0; r<matRef.size(); r++) {
73  for (size_t c=0; c<matRef.size(); c++) {
74  int ketBit = (c >> qubit) & 1;
75  int braBit = (r >> qubit) & 1;
76 
77  if (ketBit == outcome && braBit == outcome)
78  matRef[r][c] /= prob;
79  else
80  matRef[r][c] = 0;
81  }
82  }
83 
84  qreal res = collapseToOutcome(mat, qubit, outcome);
85  REQUIRE( res == Approx(prob) );
86  REQUIRE( areEqual(mat, matRef) );
87  }
88  }
89  SECTION( "input validation" ) {
90 
91  SECTION( "qubit index" ) {
92 
93  int qubit = GENERATE( -1, NUM_QUBITS );
94  int outcome = 0;
95  REQUIRE_THROWS_WITH( collapseToOutcome(mat, qubit, outcome), Contains("Invalid target qubit") );
96  }
97  SECTION( "outcome value" ) {
98 
99  int qubit = 0;
100  int outcome = GENERATE( -1, 2 );
101  REQUIRE_THROWS_WITH( collapseToOutcome(mat, qubit, outcome), Contains("Invalid measurement outcome") );
102  }
103  SECTION( "outcome probability" ) {
104 
105  initZeroState(vec);
106  REQUIRE_THROWS_WITH( collapseToOutcome(vec, 0, 1), Contains("Can't collapse to state with zero probability") );
107  initClassicalState(vec, 1);
108  REQUIRE_THROWS_WITH( collapseToOutcome(vec, 0, 0), Contains("Can't collapse to state with zero probability") );
109  }
110  }
111  destroyQureg(vec, QUEST_ENV);
112  destroyQureg(mat, QUEST_ENV);
113 }
114 
115 
116 
121 TEST_CASE( "measure", "[gates]" ) {
122 
125 
126  SECTION( "correctness" ) {
127 
128  int qubit = GENERATE( range(0,NUM_QUBITS) );
129 
130  // repeat these random tests 10 times on every qubit
131  GENERATE( range(0,10) );
132 
133  SECTION( "state-vector" ) {
134 
136  toQureg(vec, vecRef);
137 
138  int outcome = measure(vec, qubit);
139  REQUIRE( (outcome == 0 || outcome == 1) );
140 
141  // calculate prob of this outcome
142  qreal prob = 0;
143  for (size_t ind=0; ind<vecRef.size(); ind++) {
144  int bit = (ind >> qubit) & 1; // target-th bit
145  if (bit == outcome)
146  prob += pow(abs(vecRef[ind]), 2);
147  }
148 
149  REQUIRE( prob > REAL_EPS );
150 
151  // renormalise by the outcome prob
152  for (size_t ind=0; ind<vecRef.size(); ind++) {
153  int bit = (ind >> qubit) & 1; // target-th bit
154  if (bit == outcome)
155  vecRef[ind] /= sqrt(prob);
156  else
157  vecRef[ind] = 0;
158  }
159  REQUIRE( areEqual(vec, vecRef) );
160  }
161  SECTION( "density-matrix" ) {
162 
164  toQureg(mat, matRef);
165 
166  int outcome = measure(mat, qubit);
167  REQUIRE( (outcome == 0 || outcome == 1) );
168 
169  // compute prob of this outcome
170  qreal prob = 0;
171  for (size_t ind=0; ind<matRef.size(); ind++) {
172  int bit = (ind >> qubit) & 1; // qubit-th bit
173  if (bit == outcome)
174  prob += real(matRef[ind][ind]);
175  }
176 
177  REQUIRE( prob > REAL_EPS );
178 
179  // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
180  for (size_t r=0; r<matRef.size(); r++) {
181  for (size_t c=0; c<matRef.size(); c++) {
182  int ketBit = (c >> qubit) & 1;
183  int braBit = (r >> qubit) & 1;
184 
185  if (ketBit == outcome && braBit == outcome)
186  matRef[r][c] /= prob;
187  else
188  matRef[r][c] = 0;
189  }
190  }
191 
192  REQUIRE( areEqual(mat, matRef) );
193  }
194  }
195  SECTION( "input validation" ) {
196 
197  SECTION( "qubit index" ) {
198 
199  int qubit = GENERATE( -1, NUM_QUBITS );
200  REQUIRE_THROWS_WITH( measure(vec, qubit), Contains("Invalid target qubit") );
201  }
202  }
203  destroyQureg(vec, QUEST_ENV);
204  destroyQureg(mat, QUEST_ENV);
205 }
206 
207 
208 
213 TEST_CASE( "measureWithStats", "[gates]" ) {
214 
217 
218  SECTION( "correctness" ) {
219 
220  int qubit = GENERATE( range(0,NUM_QUBITS) );
221 
222  // repeat these random tests 10 times on every qubit
223  GENERATE( range(0,10) );
224 
225  SECTION( "state-vector" ) {
226 
228  toQureg(vec, vecRef);
229 
230  qreal res;
231  int outcome = measureWithStats(vec, qubit, &res);
232  REQUIRE( (outcome == 0 || outcome == 1) );
233 
234  // calculate prob of this outcome
235  qreal prob = 0;
236  for (size_t ind=0; ind<vecRef.size(); ind++) {
237  int bit = (ind >> qubit) & 1; // target-th bit
238  if (bit == outcome)
239  prob += pow(abs(vecRef[ind]), 2);
240  }
241 
242  REQUIRE( prob == Approx(res) );
243 
244  // renormalise by the outcome prob
245  for (size_t ind=0; ind<vecRef.size(); ind++) {
246  int bit = (ind >> qubit) & 1; // target-th bit
247  if (bit == outcome)
248  vecRef[ind] /= sqrt(prob);
249  else
250  vecRef[ind] = 0;
251  }
252  REQUIRE( areEqual(vec, vecRef) );
253  }
254  SECTION( "density-matrix" ) {
255 
257  toQureg(mat, matRef);
258 
259  qreal res;
260  int outcome = measureWithStats(mat, qubit, &res);
261  REQUIRE( (outcome == 0 || outcome == 1) );
262 
263  // compute prob of this outcome
264  qreal prob = 0;
265  for (size_t ind=0; ind<matRef.size(); ind++) {
266  int bit = (ind >> qubit) & 1; // qubit-th bit
267  if (bit == outcome)
268  prob += real(matRef[ind][ind]);
269  }
270 
271  REQUIRE( prob == Approx(res) );
272 
273  // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
274  for (size_t r=0; r<matRef.size(); r++) {
275  for (size_t c=0; c<matRef.size(); c++) {
276  int ketBit = (c >> qubit) & 1;
277  int braBit = (r >> qubit) & 1;
278 
279  if (ketBit == outcome && braBit == outcome)
280  matRef[r][c] /= prob;
281  else
282  matRef[r][c] = 0;
283  }
284  }
285 
286  REQUIRE( areEqual(mat, matRef) );
287  }
288  }
289  SECTION( "input validation" ) {
290 
291  SECTION( "qubit index" ) {
292 
293  int qubit = GENERATE( -1, NUM_QUBITS );
294  qreal res;
295  REQUIRE_THROWS_WITH( measureWithStats(vec, qubit, &res), Contains("Invalid target qubit") );
296  }
297  }
298  destroyQureg(vec, QUEST_ENV);
299  destroyQureg(mat, QUEST_ENV);
300 }
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
#define NUM_QUBITS
The default number of qubits in the registers created for unit testing (both statevectors and density...
Definition: utilities.hpp:36
qreal collapseToOutcome(Qureg qureg, int measureQubit, int outcome)
Updates qureg to be consistent with measuring measureQubit in the given outcome (0 or 1),...
Definition: QuEST.c:966
int measure(Qureg qureg, int measureQubit)
Measures a single qubit, collapsing it randomly to 0 or 1.
Definition: QuEST.c:998
#define qreal
void toQureg(Qureg qureg, QVector vec)
Initialises the state-vector qureg to have the same amplitudes as vec.
Definition: utilities.cpp:1201
int measureWithStats(Qureg qureg, int measureQubit, qreal *outcomeProb)
Measures a single qubit, collapsing it randomly to 0 or 1, and additionally gives the probability of ...
Definition: QuEST.c:985
std::vector< qcomp > QVector
A complex vector, which can be zero-initialised with QVector(numAmps).
Definition: utilities.hpp:60
#define qcomp
void destroyQureg(Qureg qureg, QuESTEnv env)
Deallocate a Qureg, freeing its memory.
Definition: QuEST.c:77
QVector getRandomStateVector(int numQb)
Returns a random numQb-length L2-normalised state-vector from an undisclosed distribution.
Definition: utilities.cpp:468
void initClassicalState(Qureg qureg, long long int stateInd)
Initialise qureg into the classical state (also known as a "computational basis state") with index st...
Definition: QuEST.c:134
Represents a system of qubits.
Definition: QuEST.h:322
std::vector< std::vector< qcomp > > QMatrix
A complex square matrix.
Definition: utilities.hpp:49
Qureg createQureg(int numQubits, QuESTEnv env)
Creates a state-vector Qureg object representing a set of qubits which will remain in a pure state.
Definition: QuEST.c:36
QMatrix getRandomDensityMatrix(int numQb)
Returns a random numQb-by-numQb density matrix, from an undisclosed distribution, in a very mixed sta...
Definition: utilities.cpp:490
TEST_CASE("collapseToOutcome", "[gates]")
Definition: test_gates.cpp:15
void initZeroState(Qureg qureg)
Initialise qureg into the zero state.
Definition: QuEST.c:113
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:398
Qureg createDensityQureg(int numQubits, QuESTEnv env)
Creates a density matrix Qureg object representing a set of qubits which can enter noisy and mixed st...
Definition: QuEST.c:50