Unit tests

Unit tests of the QuEST API, using Catch2 in C++14. More...

Functions

 TEST_CASE ("applyDiagonalOp", "[operators]")
 
 TEST_CASE ("applyMatrix2", "[operators]")
 
 TEST_CASE ("applyMatrix4", "[operators]")
 
 TEST_CASE ("applyMatrixN", "[operators]")
 
 TEST_CASE ("applyMultiControlledMatrixN", "[operators]")
 
 TEST_CASE ("applyPauliHamil", "[operators]")
 
 TEST_CASE ("applyPauliSum", "[operators]")
 
 TEST_CASE ("applyTrotterCircuit", "[operators]")
 
 TEST_CASE ("calcDensityInnerProduct", "[calculations]")
 
 TEST_CASE ("calcExpecDiagonalOp", "[calculations]")
 
 TEST_CASE ("calcExpecPauliHamil", "[calculations]")
 
 TEST_CASE ("calcExpecPauliProd", "[calculations]")
 
 TEST_CASE ("calcExpecPauliSum", "[calculations]")
 
 TEST_CASE ("calcFidelity", "[calculations]")
 
 TEST_CASE ("calcHilbertSchmidtDistance", "[calculations]")
 
 TEST_CASE ("calcInnerProduct", "[calculations]")
 
 TEST_CASE ("calcProbOfOutcome", "[calculations]")
 
 TEST_CASE ("calcPurity", "[calculations]")
 
 TEST_CASE ("calcTotalProb", "[calculations]")
 
 TEST_CASE ("cloneQureg", "[state_initialisations]")
 
 TEST_CASE ("collapseToOutcome", "[gates]")
 
 TEST_CASE ("compactUnitary", "[unitaries]")
 
 TEST_CASE ("controlledCompactUnitary", "[unitaries]")
 
 TEST_CASE ("controlledMultiQubitUnitary", "[unitaries]")
 
 TEST_CASE ("controlledNot", "[unitaries]")
 
 TEST_CASE ("controlledPauliY", "[unitaries]")
 
 TEST_CASE ("controlledPhaseFlip", "[unitaries]")
 
 TEST_CASE ("controlledPhaseShift", "[unitaries]")
 
 TEST_CASE ("controlledRotateAroundAxis", "[unitaries]")
 
 TEST_CASE ("controlledRotateX", "[unitaries]")
 
 TEST_CASE ("controlledRotateY", "[unitaries]")
 
 TEST_CASE ("controlledRotateZ", "[unitaries]")
 
 TEST_CASE ("controlledTwoQubitUnitary", "[unitaries]")
 
 TEST_CASE ("controlledUnitary", "[unitaries]")
 
 TEST_CASE ("createCloneQureg", "[data_structures]")
 
 TEST_CASE ("createComplexMatrixN", "[data_structures]")
 
 TEST_CASE ("createDensityQureg", "[data_structures]")
 
 TEST_CASE ("createDiagonalOp", "[data_structures]")
 
 TEST_CASE ("createPauliHamil", "[data_structures]")
 
 TEST_CASE ("createPauliHamilFromFile", "[data_structures]")
 
 TEST_CASE ("createQuESTEnv", "[data_structures]")
 
 TEST_CASE ("createQureg", "[data_structures]")
 
 TEST_CASE ("destroyComplexMatrixN", "[data_structures]")
 
 TEST_CASE ("destroyDiagonalOp", "[data_structures]")
 
 TEST_CASE ("destroyPauliHamil", "[data_structures]")
 
 TEST_CASE ("destroyQuESTEnv", "[data_structures]")
 
 TEST_CASE ("destroyQureg", "[data_structures]")
 
 TEST_CASE ("fromComplex", "[data_structures]")
 
 TEST_CASE ("getAmp", "[calculations]")
 
 TEST_CASE ("getDensityAmp", "[calculations]")
 
 TEST_CASE ("getImagAmp", "[calculations]")
 
 TEST_CASE ("getNumAmps", "[calculations]")
 
 TEST_CASE ("getNumQubits", "[calculations]")
 
 TEST_CASE ("getProbAmp", "[calculations]")
 
 TEST_CASE ("getRealAmp", "[calculations]")
 
 TEST_CASE ("getStaticComplexMatrixN", "[data_structures]")
 
 TEST_CASE ("hadamard", "[unitaries]")
 
 TEST_CASE ("initBlankState", "[state_initialisations]")
 
 TEST_CASE ("initClassicalState", "[state_initialisations]")
 
 TEST_CASE ("initComplexMatrixN", "[data_structures]")
 
 TEST_CASE ("initDiagonalOp", "[data_structures]")
 
 TEST_CASE ("initPauliHamil", "[data_structures]")
 
 TEST_CASE ("initPlusState", "[state_initialisations]")
 
 TEST_CASE ("initPureState", "[state_initialisations]")
 
 TEST_CASE ("initStateFromAmps", "[state_initialisations]")
 
 TEST_CASE ("initZeroState", "[state_initialisations]")
 
 TEST_CASE ("measure", "[gates]")
 
 TEST_CASE ("measureWithStats", "[gates]")
 
 TEST_CASE ("mixDamping", "[decoherence]")
 
 TEST_CASE ("mixDensityMatrix", "[decoherence]")
 
 TEST_CASE ("mixDephasing", "[decoherence]")
 
 TEST_CASE ("mixDepolarising", "[decoherence]")
 
 TEST_CASE ("mixKrausMap", "[decoherence]")
 
 TEST_CASE ("mixMultiQubitKrausMap", "[decoherence]")
 
 TEST_CASE ("mixPauli", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitDephasing", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitDepolarising", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitKrausMap", "[decoherence]")
 
 TEST_CASE ("multiControlledMultiQubitUnitary", "[unitaries]")
 
 TEST_CASE ("multiControlledPhaseFlip", "[unitaries]")
 
 TEST_CASE ("multiControlledPhaseShift", "[unitaries]")
 
 TEST_CASE ("multiControlledTwoQubitUnitary", "[unitaries]")
 
 TEST_CASE ("multiControlledUnitary", "[unitaries]")
 
 TEST_CASE ("multiQubitUnitary", "[unitaries]")
 
 TEST_CASE ("multiRotatePauli", "[unitaries]")
 
 TEST_CASE ("multiRotateZ", "[unitaries]")
 
 TEST_CASE ("multiStateControlledUnitary", "[unitaries]")
 
 TEST_CASE ("pauliX", "[unitaries]")
 
 TEST_CASE ("pauliY", "[unitaries]")
 
 TEST_CASE ("pauliZ", "[unitaries]")
 
 TEST_CASE ("phaseShift", "[unitaries]")
 
 TEST_CASE ("rotateAroundAxis", "[unitaries]")
 
 TEST_CASE ("rotateX", "[unitaries]")
 
 TEST_CASE ("rotateY", "[unitaries]")
 
 TEST_CASE ("rotateZ", "[unitaries]")
 
 TEST_CASE ("setAmps", "[state_initialisations]")
 
 TEST_CASE ("setDiagonalOpElems", "[data_structures]")
 
 TEST_CASE ("setWeightedQureg", "[state_initialisations]")
 
 TEST_CASE ("sGate", "[unitaries]")
 
 TEST_CASE ("sqrtSwapGate", "[unitaries]")
 
 TEST_CASE ("swapGate", "[unitaries]")
 
 TEST_CASE ("syncDiagonalOp", "[data_structures]")
 
 TEST_CASE ("tGate", "[unitaries]")
 
 TEST_CASE ("toComplex", "[data_structures]")
 
 TEST_CASE ("twoQubitUnitary", "[unitaries]")
 
 TEST_CASE ("unitary", "[unitaries]")
 

Detailed Description

Unit tests of the QuEST API, using Catch2 in C++14.

Function Documentation

◆ TEST_CASE() [1/106]

TEST_CASE ( "applyDiagonalOp"  ,
""  [operators] 
)
See also
applyDiagonalOp
Author
Tyson Jones

Definition at line 32 of file test_operators.cpp.

32  {
33 
34  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
35 
36  SECTION( "correctness" ) {
37 
38  // try 10 random operators
39  GENERATE( range(0,10) );
40 
41  // make a totally random (non-Hermitian) diagonal oeprator
43  for (long long int i=0; i<op.numElemsPerChunk; i++) {
44  op.real[i] = getRandomReal(-5, 5);
45  op.imag[i] = getRandomReal(-5, 5);
46  }
47  syncDiagonalOp(op);
48 
49  SECTION( "state-vector" ) {
50 
51  QVector ref = toQMatrix(op) * refVec;
52  applyDiagonalOp(quregVec, op);
53  REQUIRE( areEqual(quregVec, ref) );
54  }
55  SECTION( "density-matrix" ) {
56 
57  QMatrix ref = toQMatrix(op) * refMatr;
58  applyDiagonalOp(quregMatr, op);
59  REQUIRE( areEqual(quregMatr, ref, 100*REAL_EPS) );
60  }
61 
63  }
64  SECTION( "input validation" ) {
65 
66  SECTION( "mismatching size" ) {
67 
69 
70  REQUIRE_THROWS_WITH( applyDiagonalOp(quregVec, op), Contains("equal number of qubits"));
71  REQUIRE_THROWS_WITH( applyDiagonalOp(quregMatr, op), Contains("equal number of qubits"));
72 
74  }
75  }
76  CLEANUP_TEST( quregVec, quregMatr );
77 }

References applyDiagonalOp(), areEqual(), CLEANUP_TEST, createDiagonalOp(), destroyDiagonalOp(), getRandomReal(), DiagonalOp::imag, NUM_QUBITS, DiagonalOp::numElemsPerChunk, PREPARE_TEST, QUEST_ENV, DiagonalOp::real, syncDiagonalOp(), and toQMatrix().

◆ TEST_CASE() [2/106]

TEST_CASE ( "applyMatrix2"  ,
""  [operators] 
)
See also
applyMatrix2
Author
Tyson Jones

Definition at line 85 of file test_operators.cpp.

85  {
86 
87  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
88 
89  // every test will use a unique random matrix
90  QMatrix op = getRandomQMatrix(2); // 2-by-2
91  ComplexMatrix2 matr = toComplexMatrix2(op);
92 
93  SECTION( "correctness" ) {
94 
95  int target = GENERATE( range(0,NUM_QUBITS) );
96 
97  // reference boilerplate
98  int* ctrls = NULL;
99  int numCtrls = 0;
100  int targs[] = {target};
101  int numTargs = 1;
102 
103  SECTION( "state-vector" ) {
104 
105  applyMatrix2(quregVec, target, matr);
106  applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
107 
108  REQUIRE( areEqual(quregVec, refVec) );
109  }
110  SECTION( "density-matrix" ) {
111 
112  applyMatrix2(quregMatr, target, matr);
113  applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
114 
115  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
116  }
117  }
118  SECTION( "input validation" ) {
119 
120  SECTION( "qubit indices" ) {
121 
122  int target = GENERATE( -1, NUM_QUBITS );
123  REQUIRE_THROWS_WITH( applyMatrix2(quregVec, target, matr), Contains("Invalid target") );
124  }
125  }
126  CLEANUP_TEST( quregVec, quregMatr );
127 }

References applyMatrix2(), applyReferenceMatrix(), areEqual(), CLEANUP_TEST, getRandomQMatrix(), NUM_QUBITS, PREPARE_TEST, and toComplexMatrix2().

◆ TEST_CASE() [3/106]

TEST_CASE ( "applyMatrix4"  ,
""  [operators] 
)
See also
applyMatrix4
Author
Tyson Jones

Definition at line 135 of file test_operators.cpp.

135  {
136 
137  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
138 
139  // in distributed mode, each node must be able to fit all amps modified by matrix
140  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
141 
142  // every test will use a unique random matrix
143  QMatrix op = getRandomQMatrix(4); // 4-by-4
144  ComplexMatrix4 matr = toComplexMatrix4(op);
145 
146  SECTION( "correctness" ) {
147 
148  int targ1 = GENERATE( range(0,NUM_QUBITS) );
149  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
150 
151  // reference boilerplate
152  int* ctrls = NULL;
153  int numCtrls = 0;
154  int targs[] = {targ1, targ2};
155  int numTargs = 2;
156 
157  SECTION( "state-vector" ) {
158 
159  applyMatrix4(quregVec, targ1, targ2, matr);
160  applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
161  REQUIRE( areEqual(quregVec, refVec) );
162  }
163  SECTION( "density-matrix" ) {
164 
165  applyMatrix4(quregMatr, targ1, targ2, matr);
166  applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
167  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
168  }
169  }
170  SECTION( "input validation" ) {
171 
172  SECTION( "qubit indices" ) {
173 
174  int targ1 = GENERATE( -1, NUM_QUBITS );
175  int targ2 = 0;
176  REQUIRE_THROWS_WITH( applyMatrix4(quregVec, targ1, targ2, matr), Contains("Invalid target") );
177  REQUIRE_THROWS_WITH( applyMatrix4(quregVec, targ2, targ1, matr), Contains("Invalid target") );
178  }
179  SECTION( "repetition of targets" ) {
180 
181  int qb = 0;
182  REQUIRE_THROWS_WITH( applyMatrix4(quregVec, qb, qb, matr), Contains("target") && Contains("unique") );
183  }
184  SECTION( "matrix fits in node" ) {
185 
186  // pretend we have a very limited distributed memory
187  quregVec.numAmpsPerChunk = 1;
188  REQUIRE_THROWS_WITH( applyMatrix4(quregVec, 0, 1, matr), Contains("targets too many qubits"));
189  }
190  }
191  CLEANUP_TEST( quregVec, quregMatr );
192 }

References applyMatrix4(), applyReferenceMatrix(), areEqual(), CLEANUP_TEST, getRandomQMatrix(), NUM_QUBITS, PREPARE_TEST, and toComplexMatrix4().

◆ TEST_CASE() [4/106]

TEST_CASE ( "applyMatrixN"  ,
""  [operators] 
)
See also
applyMatrixN
Author
Tyson Jones

Definition at line 200 of file test_operators.cpp.

200  {
201 
202  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
203 
204  // figure out max-num (inclusive) targs allowed by hardware backend
205  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
206 
207  SECTION( "correctness" ) {
208 
209  // generate all possible qubit arrangements
210  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
211  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
212 
213  // for each qubit arrangement, use a new random matrix
214  QMatrix op = getRandomQMatrix(1 << numTargs);
215  ComplexMatrixN matr = createComplexMatrixN(numTargs);
216  toComplexMatrixN(op, matr);
217 
218  // reference boilerplate
219  int* ctrls = NULL;
220  int numCtrls = 0;
221 
222  SECTION( "state-vector" ) {
223 
224  applyMatrixN(quregVec, targs, numTargs, matr);
225  applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
226  REQUIRE( areEqual(quregVec, refVec) );
227  }
228  SECTION( "density-matrix" ) {
229 
230  applyMatrixN(quregMatr, targs, numTargs, matr);
231  applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
232  REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
233  }
234  destroyComplexMatrixN(matr);
235  }
236  SECTION( "input validation" ) {
237 
238  SECTION( "number of targets" ) {
239 
240  // there cannot be more targets than qubits in register
241  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
242  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
243  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
244 
245  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), Contains("Invalid number of target"));
246  destroyComplexMatrixN(matr);
247  }
248  SECTION( "repetition in targets" ) {
249 
250  int numTargs = 3;
251  int targs[] = {1,2,2};
252  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
253 
254  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), Contains("target") && Contains("unique"));
255  destroyComplexMatrixN(matr);
256  }
257  SECTION( "qubit indices" ) {
258 
259  int numTargs = 3;
260  int targs[] = {1,2,3};
261  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
262 
263  int inv = GENERATE( -1, NUM_QUBITS );
264  targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
265  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), Contains("Invalid target") );
266 
267  destroyComplexMatrixN(matr);
268  }
269  SECTION( "matrix creation" ) {
270 
271  int numTargs = 3;
272  int targs[] = {1,2,3};
273 
274  /* compilers don't auto-initialise to NULL; the below circumstance
275  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
276  * which actually triggers its own validation. Hence this test is useless
277  * currently.
278  */
279  ComplexMatrixN matr;
280  matr.real = NULL;
281  matr.imag = NULL;
282  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), Contains("created") );
283  }
284  SECTION( "matrix dimensions" ) {
285 
286  int targs[2] = {1,2};
287  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
288 
289  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, 2, matr), Contains("matrix size"));
290  destroyComplexMatrixN(matr);
291  }
292  SECTION( "matrix fits in node" ) {
293 
294  // pretend we have a very limited distributed memory (judged by matr size)
295  quregVec.numAmpsPerChunk = 1;
296  int qb[] = {1,2};
297  ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
298  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, qb, 2, matr), Contains("targets too many qubits"));
299  destroyComplexMatrixN(matr);
300  }
301  }
302  CLEANUP_TEST( quregVec, quregMatr );
303 }

References applyMatrixN(), applyReferenceMatrix(), areEqual(), calcLog2(), CLEANUP_TEST, createComplexMatrixN(), destroyComplexMatrixN(), getRandomQMatrix(), ComplexMatrixN::imag, NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [5/106]

TEST_CASE ( "applyMultiControlledMatrixN"  ,
""  [operators] 
)
See also
applyMultiControlledMatrixN
Author
Tyson Jones

Definition at line 311 of file test_operators.cpp.

311  {
312 
313  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
314 
315  // figure out max-num targs (inclusive) allowed by hardware backend
316  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
317  if (maxNumTargs >= NUM_QUBITS)
318  maxNumTargs = NUM_QUBITS - 1; // leave room for min-number of control qubits
319 
320  SECTION( "correctness" ) {
321 
322  // try all possible numbers of targets and controls
323  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
324  int maxNumCtrls = NUM_QUBITS - numTargs;
325  int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
326 
327  // generate all possible valid qubit arrangements
328  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
329  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
330 
331  // for each qubit arrangement, use a new random unitary
332  QMatrix op = getRandomQMatrix(1 << numTargs);
333  ComplexMatrixN matr = createComplexMatrixN(numTargs);
334  toComplexMatrixN(op, matr);
335 
336  SECTION( "state-vector" ) {
337 
338  applyMultiControlledMatrixN(quregVec, ctrls, numCtrls, targs, numTargs, matr);
339  applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
340  REQUIRE( areEqual(quregVec, refVec) );
341  }
342  SECTION( "density-matrix" ) {
343 
344  applyMultiControlledMatrixN(quregMatr, ctrls, numCtrls, targs, numTargs, matr);
345  applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
346  REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
347  }
348  destroyComplexMatrixN(matr);
349  }
350  SECTION( "input validation" ) {
351 
352  SECTION( "number of targets" ) {
353 
354  // there cannot be more targets than qubits in register
355  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
356  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
357  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
358  int ctrls[] = {0};
359  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
360  toComplexMatrixN(getRandomQMatrix( 1 << (NUM_QUBITS+1)), matr);
361 
362  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, numTargs, matr), Contains("Invalid number of target"));
363  destroyComplexMatrixN(matr);
364  }
365  SECTION( "repetition in targets" ) {
366 
367  int ctrls[] = {0};
368  int numTargs = 3;
369  int targs[] = {1,2,2};
370  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
371  toComplexMatrixN(getRandomQMatrix(1 << numTargs), matr);
372 
373  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, numTargs, matr), Contains("target") && Contains("unique"));
374  destroyComplexMatrixN(matr);
375  }
376  SECTION( "number of controls" ) {
377 
378  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
379  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
380  int targs[1] = {0};
382  toComplexMatrixN(getRandomQMatrix(1 << 1), matr);
383 
384  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, numCtrls, targs, 1, matr), Contains("Invalid number of control"));
385  destroyComplexMatrixN(matr);
386  }
387  SECTION( "repetition in controls" ) {
388 
389  int ctrls[] = {0,1,1};
390  int targs[] = {3};
392  toComplexMatrixN(getRandomQMatrix(1 << 1), matr);
393 
394  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 3, targs, 1, matr), Contains("control") && Contains("unique"));
395  destroyComplexMatrixN(matr);
396  }
397  SECTION( "control and target collision" ) {
398 
399  int ctrls[] = {0,1,2};
400  int targs[] = {3,1,4};
402  toComplexMatrixN(getRandomQMatrix(1 << 3), matr);
403 
404  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 3, targs, 3, matr), Contains("Control") && Contains("target") && Contains("disjoint"));
405  destroyComplexMatrixN(matr);
406  }
407  SECTION( "qubit indices" ) {
408 
409  // valid inds
410  int numQb = 2;
411  int qb1[2] = {0,1};
412  int qb2[2] = {2,3};
413  ComplexMatrixN matr = createComplexMatrixN(numQb);
414  toComplexMatrixN(getRandomQMatrix(1 << numQb), matr);
415 
416  // make qb1 invalid
417  int inv = GENERATE( -1, NUM_QUBITS );
418  qb1[GENERATE_COPY(range(0,numQb))] = inv;
419 
420  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, qb1, numQb, qb2, numQb, matr), Contains("Invalid control") );
421  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, qb2, numQb, qb1, numQb, matr), Contains("Invalid target") );
422  destroyComplexMatrixN(matr);
423  }
424  SECTION( "matrix creation" ) {
425 
426  int ctrls[1] = {0};
427  int targs[3] = {1,2,3};
428 
429  /* compilers don't auto-initialise to NULL; the below circumstance
430  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
431  * which actually triggers its own validation. Hence this test is useless
432  * currently.
433  */
434  ComplexMatrixN matr;
435  matr.real = NULL;
436  matr.imag = NULL;
437  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, 3, matr), Contains("created") );
438  }
439  SECTION( "matrix dimensions" ) {
440 
441  int ctrls[1] = {0};
442  int targs[2] = {1,2};
443  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
444  toComplexMatrixN(getRandomQMatrix(1 << 3), matr);
445 
446  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, 2, matr), Contains("matrix size"));
447  destroyComplexMatrixN(matr);
448  }
449  SECTION( "matrix fits in node" ) {
450 
451  // pretend we have a very limited distributed memory (judged by matr size)
452  quregVec.numAmpsPerChunk = 1;
453  int ctrls[1] = {0};
454  int targs[2] = {1,2};
456  toComplexMatrixN(getRandomQMatrix(1 << 2), matr);
457 
458  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, 2, matr), Contains("targets too many qubits"));
459  destroyComplexMatrixN(matr);
460  }
461  }
462  CLEANUP_TEST( quregVec, quregMatr );
463 }

References applyMultiControlledMatrixN(), applyReferenceMatrix(), areEqual(), calcLog2(), CLEANUP_TEST, createComplexMatrixN(), destroyComplexMatrixN(), getRandomQMatrix(), ComplexMatrixN::imag, NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [6/106]

TEST_CASE ( "applyPauliHamil"  ,
""  [operators] 
)
See also
applyPauliHamil
Author
Tyson Jones

Definition at line 471 of file test_operators.cpp.

471  {
472 
477 
478  initDebugState(vecIn);
479  initDebugState(matIn);
480 
481  SECTION( "correctness" ) {
482 
483  /* it's too expensive to try every possible Pauli configuration, so
484  * we'll try 10 random codes, and for each, random coefficients
485  */
486  GENERATE( range(0,10) );
487 
488  int numTerms = GENERATE( 1, 2, 10, 15 );
489  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
490  setRandomPauliSum(hamil);
491  QMatrix refHamil = toQMatrix(hamil);
492 
493  SECTION( "state-vector" ) {
494 
495  QVector vecRef = toQVector(vecIn);
496  applyPauliHamil(vecIn, hamil, vecOut);
497 
498  // ensure vecIn barely changes under precision
499  REQUIRE( areEqual(vecIn, vecRef) );
500 
501  // ensure vecOut changed correctly
502  REQUIRE( areEqual(vecOut, refHamil * vecRef) );
503  }
504  SECTION( "density-matrix" ) {
505 
506  QMatrix matRef = toQMatrix(matIn);
507  applyPauliHamil(matIn, hamil, matOut);
508 
509  // ensure matIn barely changes under precision
510  REQUIRE( areEqual(matIn, matRef) );
511 
512  // ensure matOut changed correctly
513  REQUIRE( areEqual(matOut, refHamil * matRef, 1E2*REAL_EPS) );
514  }
515 
516  destroyPauliHamil(hamil);
517  }
518  SECTION( "input validation" ) {
519 
520  SECTION( "pauli codes" ) {
521 
522  int numTerms = 3;
523  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
524 
525  // make one pauli code wrong
526  hamil.pauliCodes[GENERATE_COPY( range(0,numTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
527  REQUIRE_THROWS_WITH( applyPauliHamil(vecIn, hamil, vecOut), Contains("Invalid Pauli code") );
528 
529  destroyPauliHamil(hamil);
530  }
531  SECTION( "qureg dimensions" ) {
532 
533  Qureg badVec = createQureg(NUM_QUBITS+1, QUEST_ENV);
535 
536  REQUIRE_THROWS_WITH( applyPauliHamil(vecIn, hamil, badVec), Contains("Dimensions of the qubit registers don't match") );
537 
538  destroyQureg(badVec, QUEST_ENV);
539  destroyPauliHamil(hamil);
540  }
541  SECTION( "qureg types" ) {
542 
544 
545  REQUIRE_THROWS_WITH( applyPauliHamil(vecIn, hamil, matOut), Contains("Registers must both be state-vectors or both be density matrices") );
546 
547  destroyPauliHamil(hamil);
548  }
549  SECTION( "matching hamiltonian qubits" ) {
550 
551  PauliHamil hamil = createPauliHamil(NUM_QUBITS + 1, 1);
552 
553  REQUIRE_THROWS_WITH( applyPauliHamil(vecIn, hamil, vecOut), Contains("same number of qubits") );
554  REQUIRE_THROWS_WITH( applyPauliHamil(matIn, hamil, matOut), Contains("same number of qubits") );
555 
556  destroyPauliHamil(hamil);
557  }
558  }
559  destroyQureg(vecIn, QUEST_ENV);
560  destroyQureg(vecOut, QUEST_ENV);
561  destroyQureg(matIn, QUEST_ENV);
562  destroyQureg(matOut, QUEST_ENV);
563 }

References applyPauliHamil(), areEqual(), createDensityQureg(), createPauliHamil(), createQureg(), destroyPauliHamil(), destroyQureg(), initDebugState(), NUM_QUBITS, PauliHamil::pauliCodes, QUEST_ENV, setRandomPauliSum(), toQMatrix(), and toQVector().

◆ TEST_CASE() [7/106]

TEST_CASE ( "applyPauliSum"  ,
""  [operators] 
)
See also
applyPauliSum
Author
Tyson Jones

Definition at line 571 of file test_operators.cpp.

571  {
572 
577 
578  initDebugState(vecIn);
579  initDebugState(matIn);
580 
581  SECTION( "correctness" ) {
582 
583  /* it's too expensive to try ALL Pauli sequences, via
584  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numPaulis) );.
585  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
586  * Hence, we instead opt to repeatedly randomly generate pauliseqs
587  */
588  GENERATE( range(0,10) ); // gen 10 random pauli-codes
589 
590  int numTerms = GENERATE( 1, 2, 10, 15);
591  int numPaulis = numTerms * NUM_QUBITS;
592 
593  // each test will use random coefficients
594  qreal coeffs[numTerms];
595  pauliOpType paulis[numPaulis];
596  setRandomPauliSum(coeffs, paulis, NUM_QUBITS, numTerms);
597  QMatrix pauliSum = toQMatrix(coeffs, paulis, NUM_QUBITS, numTerms);
598 
599  SECTION( "state-vector" ) {
600 
601  QVector vecRef = toQVector(vecIn);
602  applyPauliSum(vecIn, paulis, coeffs, numTerms, vecOut);
603 
604  // ensure vecIn barely changes under precision
605  REQUIRE( areEqual(vecIn, vecRef) );
606 
607  // ensure vecOut changed correctly
608  REQUIRE( areEqual(vecOut, pauliSum * vecRef) );
609  }
610  SECTION( "density-matrix" ) {
611 
612  QMatrix matRef = toQMatrix(matIn);
613  applyPauliSum(matIn, paulis, coeffs, numTerms, matOut);
614 
615  // ensure matIn barely changes under precision
616  REQUIRE( areEqual(matIn, matRef) );
617 
618  // ensure matOut changed correctly
619  REQUIRE( areEqual(matOut, pauliSum * matRef, 1E2*REAL_EPS) );
620  }
621  }
622  SECTION( "input validation" ) {
623 
624  SECTION( "number of terms" ) {
625 
626  int numTerms = GENERATE( -1, 0 );
627  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, NULL, NULL, numTerms, vecOut), Contains("Invalid number of terms") );
628  }
629  SECTION( "pauli codes" ) {
630 
631  // valid codes
632  int numTerms = 3;
633  int numPaulis = numTerms*NUM_QUBITS;
634  pauliOpType paulis[numPaulis];
635  for (int i=0; i<numPaulis; i++)
636  paulis[i] = PAULI_I;
637 
638  // make one invalid
639  paulis[GENERATE_COPY( range(0,numPaulis) )] = (pauliOpType) GENERATE( -1, 4 );
640  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, numTerms, vecOut), Contains("Invalid Pauli code") );
641  }
642  SECTION( "qureg dimensions" ) {
643 
644  Qureg badVec = createQureg(NUM_QUBITS+1, QUEST_ENV);
645  pauliOpType paulis[NUM_QUBITS];
646  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, 1, badVec), Contains("Dimensions of the qubit registers don't match") );
647  destroyQureg(badVec, QUEST_ENV);
648  }
649  SECTION( "qureg types" ) {
650 
651  pauliOpType paulis[NUM_QUBITS];
652  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, 1, matOut), Contains("Registers must both be state-vectors or both be density matrices") );
653  }
654  }
655  destroyQureg(vecIn, QUEST_ENV);
656  destroyQureg(vecOut, QUEST_ENV);
657  destroyQureg(matIn, QUEST_ENV);
658  destroyQureg(matOut, QUEST_ENV);
659 }

References applyPauliSum(), areEqual(), createDensityQureg(), createQureg(), destroyQureg(), initDebugState(), NUM_QUBITS, PAULI_I, qreal, QUEST_ENV, setRandomPauliSum(), toQMatrix(), and toQVector().

◆ TEST_CASE() [8/106]

TEST_CASE ( "applyTrotterCircuit"  ,
""  [operators] 
)
See also
applyTrotterCircuit
Author
Tyson Jones

Definition at line 667 of file test_operators.cpp.

667  {
668 
671  initDebugState(vec);
672  initDebugState(mat);
673 
674  Qureg vecRef = createCloneQureg(vec, QUEST_ENV);
675  Qureg matRef = createCloneQureg(mat, QUEST_ENV);
676 
677  SECTION( "correctness" ) {
678 
679  SECTION( "one term" ) {
680 
681  // a Hamiltonian with one term has an exact (trivial) Trotterisation
683 
684  // H = coeff X Y Z (on qubits 0,1,2)
685  qreal coeff = getRandomReal(-5, 5);
686  int numTargs = 3;
687  int targs[] = {0, 1, 2};
688  pauliOpType codes[] = {PAULI_X, PAULI_Y, PAULI_Z};
689  hamil.termCoeffs[0] = coeff;
690  for (int i=0; i<numTargs; i++)
691  hamil.pauliCodes[targs[i]] = codes[i];
692 
693  // time can be negative
694  qreal time = getRandomReal(-2,2);
695 
696  // by commutation, all reps & orders yield the same total unitary
697  int reps = GENERATE( range(1,5) );
698 
699  // applyTrotter(t, 1, 1) = exp(-i t coeff paulis)
700  // multiRotatePauli(a) = exp(- i a / 2 paulis)
701 
702  SECTION( "state-vector" ) {
703 
704  int order = GENERATE( 1, 2, 4 );
705 
706  applyTrotterCircuit(vec, hamil, time, order, reps);
707  multiRotatePauli(vecRef, targs, codes, numTargs, 2*time*coeff);
708  REQUIRE( areEqual(vec, vecRef, 10*REAL_EPS) );
709  }
710  SECTION( "density-matrix" ) {
711 
712  int order = GENERATE( 1, 2 ); // precision bites density-matrices quickly
713 
714  applyTrotterCircuit(mat, hamil, time, order, reps);
715  multiRotatePauli(matRef, targs, codes, numTargs, 2*time*coeff);
716  REQUIRE( areEqual(mat, matRef, 1E2*REAL_EPS) );
717  }
718 
719  destroyPauliHamil(hamil);
720  }
721  SECTION( "commuting terms" ) {
722 
723  // a Hamiltonian of commuting terms, Trotterises exactly
725 
726  // H = c0 X Y I + c1 X I Z (on qubits 0,1,2)
727  int targs[] = {0, 1, 2};
728  hamil.pauliCodes[0] = PAULI_X;
729  hamil.pauliCodes[0 + NUM_QUBITS] = PAULI_X;
730  hamil.pauliCodes[1] = PAULI_Y;
731  hamil.pauliCodes[1 + NUM_QUBITS] = PAULI_I;
732  hamil.pauliCodes[2] = PAULI_I;
733  hamil.pauliCodes[2 + NUM_QUBITS] = PAULI_Z;
734  for (int i=0; i<hamil.numSumTerms; i++)
735  hamil.termCoeffs[i] = getRandomReal(-5,5);
736 
737  // time can be negative
738  qreal time = getRandomReal(-2,2);
739 
740  // applyTrotter(t, 1, 1) = exp(-i t c0 paulis0) exp(-i t c1 paulis1)
741  // multiRotatePauli(a) = exp(- i a / 2 paulis)
742 
743  SECTION( "state-vector" ) {
744 
745  int reps = GENERATE( range(1,5) );
746  int order = GENERATE( 1, 2, 4 );
747 
748  applyTrotterCircuit(vec, hamil, time, order, reps);
749  multiRotatePauli(vecRef, targs, hamil.pauliCodes, 3, 2*time*hamil.termCoeffs[0]);
750  multiRotatePauli(vecRef, targs, &(hamil.pauliCodes[NUM_QUBITS]), 3, 2*time*hamil.termCoeffs[1]);
751  REQUIRE( areEqual(vec, vecRef, 10*REAL_EPS) );
752  }
753  SECTION( "density-matrix" ) {
754 
755  int reps = GENERATE( range(1,5) );
756  int order = GENERATE( 1, 2 ); // precision hurts density matrices quickly
757 
758  applyTrotterCircuit(mat, hamil, time, order, reps);
759  multiRotatePauli(matRef, targs, hamil.pauliCodes, 3, 2*time*hamil.termCoeffs[0]);
760  multiRotatePauli(matRef, targs, &(hamil.pauliCodes[NUM_QUBITS]), 3, 2*time*hamil.termCoeffs[1]);
761  REQUIRE( areEqual(mat, matRef, 1E2*REAL_EPS) );
762  }
763 
764  destroyPauliHamil(hamil);
765  }
766  SECTION( "general" ) {
767 
768  /* We'll consider an analytic time-evolved state, so that we can avoid
769  * comparing applyTrotterCircuit to other numerical approximations.
770  * We can construct such a state, by using a Hamiltonian with known
771  * analytic eigenvalues, and hence a known period. Time evolution of the
772  * period will just yield the input state.
773  *
774  * E.g. H = pi sqrt(2) X Y Z X Y + pi Y Z X Y Z + pi Z X Y Z X
775  * has (degenerate) eigenvalues +- 2 pi, so the period
776  * of the Hamiltonian is t=1.
777  */
778 
779  // hardcoded 5 qubits here in the Pauli codes
780  REQUIRE( NUM_QUBITS == 5 );
781 
782  // (verbose for C++ compatibility)
784  qreal coeffs[] = {M_PI * sqrt(2.0), M_PI, M_PI};
785  enum pauliOpType codes[] = {
789  initPauliHamil(hamil, coeffs, codes);
790 
791  // evolving to t=1 should leave the input state unchanged
792  qreal time = 1;
793 
794  // since unnormalised (initDebugState), max fid is 728359.8336
795  qreal fidNorm = 728359.8336;
796 
797  SECTION( "absolute" ) {
798 
799  // such a high order and reps should yield precise solution
800  int order = 4;
801  int reps = 20;
802  applyTrotterCircuit(vec, hamil, time, 4, 20);
803  qreal fid = calcFidelity(vec, vecRef) / fidNorm;
804 
805  REQUIRE( fid == Approx(1).epsilon(1E-8) );
806  }
807  SECTION( "repetitions scaling" ) {
808 
809  // exclude order 1; too few reps for monotonic increase of accuracy
810  int order = GENERATE( 2, 4, 6 );
811 
812  // accuracy should increase with increasing repetitions
813  int reps[] = {1, 5, 10};
814 
815  qreal prevFid = 0;
816  for (int i=0; i<3; i++) {
817  initDebugState(vec);
818  applyTrotterCircuit(vec, hamil, time, order, reps[i]);
819  qreal fid = calcFidelity(vec, vecRef) / fidNorm;
820 
821  REQUIRE( fid >= prevFid );
822  prevFid = fid;
823  }
824  }
825  SECTION( "order scaling" ) {
826 
827  // exclude order 1; too few reps for monotonic increase of accuracy
828  int reps = GENERATE( 5, 10 );
829 
830  // accuracy should increase with increasing repetitions
831  int orders[] = {1, 2, 4, 6};
832 
833  qreal prevFid = 0;
834  for (int i=0; i<4; i++) {
835  initDebugState(vec);
836  applyTrotterCircuit(vec, hamil, time, orders[i], reps);
837  qreal fid = calcFidelity(vec, vecRef) / fidNorm;
838 
839  REQUIRE( fid >= prevFid );
840  prevFid = fid;
841  }
842  }
843 
844  destroyPauliHamil(hamil);
845  }
846  }
847  SECTION( "input validation" ) {
848 
849  SECTION( "repetitions" ) {
850 
852  int reps = GENERATE( -1, 0 );
853 
854  REQUIRE_THROWS_WITH( applyTrotterCircuit(vec, hamil, 1, 1, reps), Contains("repetitions must be >=1") );
855 
856  destroyPauliHamil(hamil);
857  }
858  SECTION( "order" ) {
859 
861  int order = GENERATE( -1, 0, 3, 5, 7 );
862 
863  REQUIRE_THROWS_WITH( applyTrotterCircuit(vec, hamil, 1, order, 1), Contains("order must be 1, or an even number") );
864 
865  destroyPauliHamil(hamil);
866  }
867  SECTION( "pauli codes" ) {
868 
869  int numTerms = 3;
870  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
871 
872  // make one pauli code wrong
873  hamil.pauliCodes[GENERATE_COPY( range(0,numTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
874  REQUIRE_THROWS_WITH( applyTrotterCircuit(vec, hamil, 1, 1, 1), Contains("Invalid Pauli code") );
875 
876  destroyPauliHamil(hamil);
877  }
878  SECTION( "matching hamiltonian qubits" ) {
879 
880  PauliHamil hamil = createPauliHamil(NUM_QUBITS + 1, 1);
881 
882  REQUIRE_THROWS_WITH( applyTrotterCircuit(vec, hamil, 1, 1, 1), Contains("same number of qubits") );
883  REQUIRE_THROWS_WITH( applyTrotterCircuit(mat, hamil, 1, 1, 1), Contains("same number of qubits") );
884 
885  destroyPauliHamil(hamil);
886  }
887  }
888 
889  destroyQureg(vec, QUEST_ENV);
890  destroyQureg(mat, QUEST_ENV);
891  destroyQureg(vecRef, QUEST_ENV);
892  destroyQureg(matRef, QUEST_ENV);
893 }

References applyTrotterCircuit(), areEqual(), calcFidelity(), createCloneQureg(), createDensityQureg(), createPauliHamil(), createQureg(), destroyPauliHamil(), destroyQureg(), getRandomReal(), initDebugState(), initPauliHamil(), multiRotatePauli(), NUM_QUBITS, PauliHamil::numSumTerms, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, PauliHamil::pauliCodes, qreal, QUEST_ENV, and PauliHamil::termCoeffs.

◆ TEST_CASE() [9/106]

TEST_CASE ( "calcDensityInnerProduct"  ,
""  [calculations] 
)
See also
calcDensityInnerProduct
Author
Tyson Jones

Definition at line 15 of file test_calculations.cpp.

15  {
16 
19 
20  SECTION( "correctness" ) {
21 
22  // repeat these random tests 10 times
23  GENERATE( range(0,10) );
24 
25  SECTION( "density-matrix" ) {
26 
27  SECTION( "pure" ) {
28 
29  // mat1 = |r1><r1|
31  toQureg(mat1, getKetBra(r1,r1));
32 
33  // mat2 = |r2><r2|
35  toQureg(mat2, getKetBra(r2,r2));
36 
37  // prod( |r1><r1|, |r2><r2| ) = |<r1|r2>|^2
38  qcomp prod = 0;
39  for (size_t i=0; i<r1.size(); i++)
40  prod += conj(r1[i]) * r2[i];
41  qreal densProd = pow(abs(prod),2);
42 
43  REQUIRE( calcDensityInnerProduct(mat1,mat2) == Approx(densProd) );
44  }
45  SECTION( "mixed" ) {
46 
49  toQureg(mat1, ref1);
50  toQureg(mat2, ref2);
51 
52  // prod(mat1, mat2) = sum_{ij} conj(mat1_{ij}) * mat2_{ij}
53  qcomp refProd = 0;
54  for (size_t i=0; i<ref1.size(); i++)
55  for (size_t j=0; j<ref1.size(); j++)
56  refProd += conj(ref1[i][j]) * ref2[i][j];
57  REQUIRE( imag(refProd) == Approx(0).margin(REAL_EPS) );
58 
59  REQUIRE( calcDensityInnerProduct(mat1,mat2) == Approx(real(refProd)) );
60 
61  // should be invariant under ordering
62  REQUIRE( calcDensityInnerProduct(mat1,mat2) == Approx(calcDensityInnerProduct(mat2,mat1)) );
63  }
64  SECTION( "unnormalised" ) {
65 
66  // set both to random (non-Hermitian) complex matrices
69  toQureg(mat1, ref1);
70  toQureg(mat2, ref2);
71 
72  // prod(mat1, mat2) = real(sum_{ij} conj(mat1_{ij}) * mat2_{ij})
73  qcomp refProd = 0;
74  for (size_t i=0; i<ref1.size(); i++)
75  for (size_t j=0; j<ref1.size(); j++)
76  refProd += conj(ref1[i][j]) * ref2[i][j];
77 
78  REQUIRE( calcDensityInnerProduct(mat1,mat2) == Approx(real(refProd)) );
79  }
80  }
81  }
82  SECTION( "input validation" ) {
83 
84  SECTION( "dimensions" ) {
85 
87  REQUIRE_THROWS_WITH( calcDensityInnerProduct(mat1,mat3), Contains("Dimensions") && Contains("don't match") );
88  destroyQureg(mat3, QUEST_ENV);
89  }
90  SECTION( "state-vectors" ) {
91 
93 
94  REQUIRE_THROWS_WITH( calcDensityInnerProduct(mat1,vec), Contains("valid only for density matrices") );
95  REQUIRE_THROWS_WITH( calcDensityInnerProduct(vec,mat1), Contains("valid only for density matrices") );
96  REQUIRE_THROWS_WITH( calcDensityInnerProduct(vec,vec), Contains("valid only for density matrices") );
97 
98  destroyQureg(vec, QUEST_ENV);
99  }
100  }
101  destroyQureg(mat1, QUEST_ENV);
102  destroyQureg(mat2, QUEST_ENV);
103 }

References calcDensityInnerProduct(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomStateVector(), NUM_QUBITS, qcomp, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [10/106]

TEST_CASE ( "calcExpecDiagonalOp"  ,
""  [calculations] 
)
See also
calcExpecDiagonalOp
Author
Tyson Jones

Definition at line 111 of file test_calculations.cpp.

111  {
112 
115  initDebugState(vec);
116  initDebugState(mat);
117  QVector vecRef = toQVector(vec);
118  QMatrix matRef = toQMatrix(mat);
119 
120  SECTION( "correctness" ) {
121 
122  // try 10 random operators
123  GENERATE( range(0,10) );
124 
125  // make a totally random (non-Hermitian) diagonal oeprator
127  for (long long int i=0; i<op.numElemsPerChunk; i++) {
128  op.real[i] = getRandomReal(-5, 5);
129  op.imag[i] = getRandomReal(-5, 5);
130  }
131  syncDiagonalOp(op);
132 
133  SECTION( "state-vector" ) {
134 
135  /* calcExpecDiagOp calculates <qureg|diag|qureg> */
136 
137  QVector sumRef = toQMatrix(op) * vecRef;
138  qcomp prod = 0;
139  for (size_t i=0; i<vecRef.size(); i++)
140  prod += conj(vecRef[i]) * sumRef[i];
141 
142  Complex res = calcExpecDiagonalOp(vec, op);
143  REQUIRE( res.real == Approx(real(prod)).margin(REAL_EPS) );
144  REQUIRE( res.imag == Approx(imag(prod)).margin(REAL_EPS) );
145  }
146  SECTION( "density-matrix" ) {
147 
148  /* calcExpecDiagOp calculates Trace( diag * qureg ) */
149  matRef = toQMatrix(op) * matRef;
150  qcomp tr = 0;
151  for (size_t i=0; i<matRef.size(); i++)
152  tr += matRef[i][i];
153 
154  Complex res = calcExpecDiagonalOp(mat, op);
155  REQUIRE( res.real == Approx(real(tr)).margin(100*REAL_EPS) );
156  REQUIRE( res.imag == Approx(imag(tr)).margin(100*REAL_EPS) );
157  }
158 
160  }
161  SECTION( "input validation" ) {
162 
163  SECTION( "mismatching size" ) {
164 
166 
167  REQUIRE_THROWS_WITH( calcExpecDiagonalOp(vec, op), Contains("equal number of qubits"));
168  REQUIRE_THROWS_WITH( calcExpecDiagonalOp(mat, op), Contains("equal number of qubits"));
169 
171  }
172  }
173  destroyQureg(vec, QUEST_ENV);
174  destroyQureg(mat, QUEST_ENV);
175 }

References calcExpecDiagonalOp(), createDensityQureg(), createDiagonalOp(), createQureg(), destroyDiagonalOp(), destroyQureg(), getRandomReal(), Complex::imag, DiagonalOp::imag, initDebugState(), NUM_QUBITS, DiagonalOp::numElemsPerChunk, qcomp, QUEST_ENV, Complex::real, DiagonalOp::real, syncDiagonalOp(), toQMatrix(), and toQVector().

◆ TEST_CASE() [11/106]

TEST_CASE ( "calcExpecPauliHamil"  ,
""  [calculations] 
)
See also
calcExpecPauliHamil
Author
Tyson Jones

Definition at line 183 of file test_calculations.cpp.

183  {
184 
187  initDebugState(vec);
188  initDebugState(mat);
189  QVector vecRef = toQVector(vec);
190  QMatrix matRef = toQMatrix(mat);
191 
194 
195  SECTION( "correctness" ) {
196 
197  /* it's too expensive to try every possible Pauli configuration, so
198  * we'll try 10 random codes, and for each, random coefficients
199  */
200  GENERATE( range(0,10) );
201 
202  int numTerms = GENERATE( 1, 2, 10, 15 );
203  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
204  setRandomPauliSum(hamil);
205  QMatrix refHamil = toQMatrix(hamil);
206 
207  SECTION( "state-vector" ) {
208 
209  /* calcExpecPauliHamil calculates <qureg|pauliHum|qureg> */
210 
211  QVector sumRef = refHamil * vecRef;
212  qcomp prod = 0;
213  for (size_t i=0; i<vecRef.size(); i++)
214  prod += conj(vecRef[i]) * sumRef[i];
215  REQUIRE( imag(prod) == Approx(0).margin(10*REAL_EPS) );
216 
217  qreal res = calcExpecPauliHamil(vec, hamil, vecWork);
218  REQUIRE( res == Approx(real(prod)).margin(10*REAL_EPS) );
219  }
220  SECTION( "density-matrix" ) {
221 
222  /* calcExpecPauliHamil calculates Trace( pauliHamil * qureg ) */
223  matRef = refHamil * matRef;
224  qreal tr = 0;
225  for (size_t i=0; i<matRef.size(); i++)
226  tr += real(matRef[i][i]);
227  // (get real, since we start in a non-Hermitian state, hence diagonal isn't real)
228 
229  qreal res = calcExpecPauliHamil(mat, hamil, matWork);
230  REQUIRE( res == Approx(tr).margin(1E2*REAL_EPS) );
231  }
232 
233  destroyPauliHamil(hamil);
234  }
235  SECTION( "validation" ) {
236 
237  SECTION( "pauli codes" ) {
238 
239  int numTerms = 3;
240  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
241 
242  // make one pauli code wrong
243  hamil.pauliCodes[GENERATE_COPY( range(0,numTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
244  REQUIRE_THROWS_WITH( calcExpecPauliHamil(vec, hamil, vecWork), Contains("Invalid Pauli code") );
245 
246  destroyPauliHamil(hamil);
247  }
248  SECTION( "workspace type" ) {
249 
250  int numTerms = 1;
251  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
252 
253  REQUIRE_THROWS_WITH( calcExpecPauliHamil(vec, hamil, mat), Contains("Registers must both be state-vectors or both be density matrices") );
254  REQUIRE_THROWS_WITH( calcExpecPauliHamil(mat, hamil, vec), Contains("Registers must both be state-vectors or both be density matrices") );
255 
256  destroyPauliHamil(hamil);
257  }
258  SECTION( "workspace dimensions" ) {
259 
260  int numTerms = 1;
261  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
262 
263  Qureg vec2 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
264  REQUIRE_THROWS_WITH( calcExpecPauliHamil(vec, hamil, vec2), Contains("Dimensions") && Contains("don't match") );
265  destroyQureg(vec2, QUEST_ENV);
266 
268  REQUIRE_THROWS_WITH( calcExpecPauliHamil(mat, hamil, mat2), Contains("Dimensions") && Contains("don't match") );
269  destroyQureg(mat2, QUEST_ENV);
270 
271  destroyPauliHamil(hamil);
272  }
273  SECTION( "matching hamiltonian qubits" ) {
274 
275  int numTerms = 1;
276  PauliHamil hamil = createPauliHamil(NUM_QUBITS + 1, numTerms);
277 
278  REQUIRE_THROWS_WITH( calcExpecPauliHamil(vec, hamil, vecWork), Contains("same number of qubits") );
279  REQUIRE_THROWS_WITH( calcExpecPauliHamil(mat, hamil, matWork), Contains("same number of qubits") );
280 
281  destroyPauliHamil(hamil);
282  }
283  }
284  destroyQureg(vec, QUEST_ENV);
285  destroyQureg(mat, QUEST_ENV);
286  destroyQureg(vecWork, QUEST_ENV);
287  destroyQureg(matWork, QUEST_ENV);
288 }

References calcExpecPauliHamil(), createDensityQureg(), createPauliHamil(), createQureg(), destroyPauliHamil(), destroyQureg(), initDebugState(), NUM_QUBITS, PauliHamil::pauliCodes, qcomp, qreal, QUEST_ENV, setRandomPauliSum(), toQMatrix(), and toQVector().

◆ TEST_CASE() [12/106]

TEST_CASE ( "calcExpecPauliProd"  ,
""  [calculations] 
)
See also
calcExpecPauliProd
Author
Tyson Jones

Definition at line 296 of file test_calculations.cpp.

296  {
297 
300  initDebugState(vec);
301  initDebugState(mat);
302  QVector vecRef = toQVector(vec);
303  QMatrix matRef = toQMatrix(mat);
304 
307 
308  SECTION( "correctness" ) {
309 
310  int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
311  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
312 
313  /* it's too expensive to try ALL Pauli sequences, via
314  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
315  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
316  * Hence, we instead opt to repeatedlyrandomly generate pauliseqs
317  */
318  GENERATE( range(0,10) ); // gen 10 random pauli-codes for every targs
319  pauliOpType paulis[numTargs];
320  for (int i=0; i<numTargs; i++)
321  paulis[i] = (pauliOpType) getRandomInt(0,4);
322 
323  // produce a numTargs-big matrix 'pauliProd' by pauli-matrix tensoring
324  QMatrix iMatr{{1,0},{0,1}};
325  QMatrix xMatr{{0,1},{1,0}};
326  QMatrix yMatr{{0,-1i},{1i,0}};
327  QMatrix zMatr{{1,0},{0,-1}};
328  QMatrix pauliProd{{1}};
329  for (int i=0; i<numTargs; i++) {
330  QMatrix fac;
331  if (paulis[i] == PAULI_I) fac = iMatr;
332  if (paulis[i] == PAULI_X) fac = xMatr;
333  if (paulis[i] == PAULI_Y) fac = yMatr;
334  if (paulis[i] == PAULI_Z) fac = zMatr;
335  pauliProd = getKroneckerProduct(fac, pauliProd);
336  }
337 
338  SECTION( "state-vector" ) {
339 
340  /* calcExpecPauliProd calculates <qureg|pauliProd|qureg> */
341 
342  QVector prodRef = vecRef;
343  applyReferenceOp(prodRef, targs, numTargs, pauliProd);
344  qcomp prod = 0;
345  for (size_t i=0; i<vecRef.size(); i++)
346  prod += conj(vecRef[i]) * prodRef[i];
347  REQUIRE( imag(prod) == Approx(0).margin(REAL_EPS) );
348 
349  qreal res = calcExpecPauliProd(vec, targs, paulis, numTargs, vecWork);
350  REQUIRE( res == Approx(real(prod)).margin(REAL_EPS) );
351  }
352  SECTION( "density-matrix" ) {
353 
354  /* calcExpecPauliProd calculates Trace( pauliProd * qureg ) */
355 
356  // produce (pauliProd * mat)
357  QMatrix fullOp = getFullOperatorMatrix(NULL, 0, targs, numTargs, pauliProd, NUM_QUBITS);
358  matRef = fullOp * matRef;
359 
360  // compute real(trace(pauliProd * mat))
361  qreal tr = 0;
362  for (size_t i=0; i<matRef.size(); i++)
363  tr += real(matRef[i][i]);
364  // (get real, since we start in a non-Hermitian state, hence diagonal isn't real)
365 
366  qreal res = calcExpecPauliProd(mat, targs, paulis, numTargs, matWork);
367  REQUIRE( res == Approx(tr).margin(10*REAL_EPS) );
368  }
369  }
370  SECTION( "validation" ) {
371 
372  SECTION( "number of targets" ) {
373 
374  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
375  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, NULL, NULL, numTargs, vecWork), Contains("Invalid number of target") );
376  }
377  SECTION( "target indices" ) {
378 
379  int numTargs = 3;
380  int targs[3] = {0, 1, 2};
381 
382  // make one index wrong
383  targs[GENERATE( range(0,3) )] = GENERATE( -1, NUM_QUBITS );
384  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, NULL, numTargs, vecWork), Contains("Invalid target qubit") );
385  }
386  SECTION( "repetition in targets" ) {
387 
388  int numTargs = 3;
389  int targs[3] = {0, 1, 1};
390  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, NULL, numTargs, vecWork), Contains("target qubits must be unique") );
391  }
392  SECTION( "pauli codes" ) {
393 
394  int numTargs = 3;
395  int targs[3] = {0, 1, 2};
396  pauliOpType codes[3] = {PAULI_X, PAULI_Y, PAULI_Z};
397 
398  // make one pauli wrong
399  codes[GENERATE( range(0,3) )] = (pauliOpType) GENERATE( -1, 4 );
400  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, vecWork), Contains("Invalid Pauli code") );
401  }
402  SECTION( "workspace type" ) {
403 
404  int numTargs = 1;
405  int targs[1] = {0};
406  pauliOpType codes[1] = {PAULI_I};
407 
408  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, matWork), Contains("Registers must both be state-vectors or both be density matrices") );
409  REQUIRE_THROWS_WITH( calcExpecPauliProd(mat, targs, codes, numTargs, vecWork), Contains("Registers must both be state-vectors or both be density matrices") );
410  }
411  SECTION( "workspace dimensions" ) {
412 
413  int numTargs = 1;
414  int targs[1] = {0};
415  pauliOpType codes[1] = {PAULI_I};
416 
417  Qureg vec2 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
418  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, vec2), Contains("Dimensions") && Contains("don't match") );
419  destroyQureg(vec2, QUEST_ENV);
420 
422  REQUIRE_THROWS_WITH( calcExpecPauliProd(mat, targs, codes, numTargs, mat2), Contains("Dimensions") && Contains("don't match") );
423  destroyQureg(mat2, QUEST_ENV);
424  }
425  }
426  destroyQureg(vec, QUEST_ENV);
427  destroyQureg(mat, QUEST_ENV);
428  destroyQureg(vecWork, QUEST_ENV);
429  destroyQureg(matWork, QUEST_ENV);
430 }

References applyReferenceOp(), calcExpecPauliProd(), createDensityQureg(), createQureg(), destroyQureg(), getFullOperatorMatrix(), getKroneckerProduct(), getRandomInt(), initDebugState(), NUM_QUBITS, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, qcomp, qreal, QUEST_ENV, sublists(), toQMatrix(), and toQVector().

◆ TEST_CASE() [13/106]

TEST_CASE ( "calcExpecPauliSum"  ,
""  [calculations] 
)
See also
calcExpecPauliSum
Author
Tyson Jones

Definition at line 438 of file test_calculations.cpp.

438  {
439 
442  initDebugState(vec);
443  initDebugState(mat);
444  QVector vecRef = toQVector(vec);
445  QMatrix matRef = toQMatrix(mat);
446 
449 
450  SECTION( "correctness" ) {
451 
452  int numSumTerms = GENERATE( 1, 2, 10, 15 );
453 
454  /* it's too expensive to try every possible Pauli configuration, so
455  * we'll try 10 random codes, and for each, random coefficients
456  */
457  GENERATE( range(0,10) );
458  int totNumCodes = numSumTerms*NUM_QUBITS;
459  pauliOpType paulis[totNumCodes];
460  qreal coeffs[numSumTerms];
461  setRandomPauliSum(coeffs, paulis, NUM_QUBITS, numSumTerms);
462 
463  // produce a numTargs-big matrix 'pauliSum' by pauli-matrix tensoring and summing
464  QMatrix pauliSum = toQMatrix(coeffs, paulis, NUM_QUBITS, numSumTerms);
465 
466  SECTION( "state-vector" ) {
467 
468  /* calcExpecPauliSum calculates <qureg|pauliSum|qureg> */
469 
470  QVector sumRef = pauliSum * vecRef;
471  qcomp prod = 0;
472  for (size_t i=0; i<vecRef.size(); i++)
473  prod += conj(vecRef[i]) * sumRef[i];
474  REQUIRE( imag(prod) == Approx(0).margin(10*REAL_EPS) );
475 
476  qreal res = calcExpecPauliSum(vec, paulis, coeffs, numSumTerms, vecWork);
477  REQUIRE( res == Approx(real(prod)).margin(10*REAL_EPS) );
478  }
479  SECTION( "density-matrix" ) {
480 
481  /* calcExpecPauliSum calculates Trace( pauliSum * qureg ) */
482  matRef = pauliSum * matRef;
483  qreal tr = 0;
484  for (size_t i=0; i<matRef.size(); i++)
485  tr += real(matRef[i][i]);
486  // (get real, since we start in a non-Hermitian state, hence diagonal isn't real)
487 
488  qreal res = calcExpecPauliSum(mat, paulis, coeffs, numSumTerms, matWork);
489  REQUIRE( res == Approx(tr).margin(1E2*REAL_EPS) );
490  }
491  }
492  SECTION( "validation" ) {
493 
494  SECTION( "number of sum terms" ) {
495 
496  int numSumTerms = GENERATE( -1, 0 );
497  REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, NULL, NULL, numSumTerms, vecWork), Contains("Invalid number of terms in the Pauli sum") );
498  }
499  SECTION( "pauli codes" ) {
500 
501  // make valid params
502  int numSumTerms = 3;
503  qreal coeffs[numSumTerms];
504  pauliOpType codes[numSumTerms*NUM_QUBITS];
505  for (int i=0; i<numSumTerms*NUM_QUBITS; i++)
506  codes[i] = PAULI_I;
507 
508  // make one pauli wrong
509  codes[GENERATE_COPY( range(0,numSumTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
510  REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes, coeffs, numSumTerms, vecWork), Contains("Invalid Pauli code") );
511  }
512  SECTION( "workspace type" ) {
513 
514  // make valid params
515  int numSumTerms = 1;
516  qreal coeffs[1] = {0};
517  pauliOpType codes[NUM_QUBITS];
518  for (int i=0; i<NUM_QUBITS; i++)
519  codes[i] = PAULI_I;
520 
521  REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes, coeffs, numSumTerms, mat), Contains("Registers must both be state-vectors or both be density matrices") );
522  REQUIRE_THROWS_WITH( calcExpecPauliSum(mat, codes, coeffs, numSumTerms, vec), Contains("Registers must both be state-vectors or both be density matrices") );
523  }
524  SECTION( "workspace dimensions" ) {
525 
526  // make valid params
527  int numSumTerms = 1;
528  qreal coeffs[1] = {0};
529  pauliOpType codes[NUM_QUBITS];
530  for (int i=0; i<NUM_QUBITS; i++)
531  codes[i] = PAULI_I;
532 
533  Qureg vec2 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
534  REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes, coeffs, numSumTerms, vec2), Contains("Dimensions") && Contains("don't match") );
535  destroyQureg(vec2, QUEST_ENV);
536 
538  REQUIRE_THROWS_WITH( calcExpecPauliSum(mat, codes, coeffs, numSumTerms, mat2), Contains("Dimensions") && Contains("don't match") );
539  destroyQureg(mat2, QUEST_ENV);
540  }
541  }
542  destroyQureg(vec, QUEST_ENV);
543  destroyQureg(mat, QUEST_ENV);
544  destroyQureg(vecWork, QUEST_ENV);
545  destroyQureg(matWork, QUEST_ENV);
546 }

References calcExpecPauliSum(), createDensityQureg(), createQureg(), destroyQureg(), initDebugState(), NUM_QUBITS, PAULI_I, qcomp, qreal, QUEST_ENV, setRandomPauliSum(), toQMatrix(), and toQVector().

◆ TEST_CASE() [14/106]

TEST_CASE ( "calcFidelity"  ,
""  [calculations] 
)
See also
calcFidelity
Author
Tyson Jones

Definition at line 554 of file test_calculations.cpp.

554  {
555 
559 
560  SECTION( "correctness" ) {
561 
562  // repeat the below random tests 10 times
563  GENERATE( range(0,10) );
564 
565  SECTION( "state-vector" ) {
566 
567  /* calcFidelity computes |<vec|pure>|^2 */
568 
569  SECTION( "normalised" ) {
570 
571  // random L2 vectors
574  toQureg(vec, vecRef);
575  toQureg(pure, pureRef);
576 
577  // |<vec|vec>|^2 = |1|^2 = 1
578  REQUIRE( calcFidelity(vec,vec) == Approx(1) );
579 
580  // |<vec|pure>|^2 = |sum_j conj(vec_j) * pure_j|^2
581  qcomp dotProd = 0;
582  for (size_t i=0; i<vecRef.size(); i++)
583  dotProd += conj(vecRef[i]) * pureRef[i];
584  qreal refFid = pow(abs(dotProd), 2);
585 
586  REQUIRE( calcFidelity(vec,pure) == Approx(refFid) );
587  }
588  SECTION( "unnormalised" ) {
589 
590  // random unnormalised vectors
591  QVector vecRef = getRandomQVector(1<<NUM_QUBITS);
592  QVector pureRef = getRandomQVector(1<<NUM_QUBITS);
593  toQureg(vec, vecRef);
594  toQureg(pure, pureRef);
595 
596  // Let nv be magnitude of vec, hence |unit-vec> = 1/sqrt(nv)|vec>
597  qreal nv = 0;
598  for (size_t i=0; i<vecRef.size(); i++)
599  nv += pow(abs(vecRef[i]), 2);
600  // then <vec|vec> = sqrt(nv)*sqrt(nv) <unit-vec|unit-vec> = nv,
601  // hence |<vec|vec>|^2 = nv*nv
602  REQUIRE( calcFidelity(vec,vec) == Approx( nv*nv ) );
603 
604  qcomp dotProd = 0;
605  for (size_t i=0; i<vecRef.size(); i++)
606  dotProd += conj(vecRef[i]) * pureRef[i];
607  qreal refFid = pow(abs(dotProd), 2);
608 
609  REQUIRE( calcFidelity(vec,pure) == Approx(refFid) );
610  }
611  }
612  SECTION( "density-matrix" ) {
613 
614  /* calcFidelity computes <pure|mat|pure> */
615 
616  SECTION( "pure" ) {
617 
619  toQureg(pure, pureRef);
620 
621  // test when density matrix is the same pure state
622  QMatrix matRef = getKetBra(pureRef, pureRef);
623  toQureg(mat, matRef);
624  REQUIRE( calcFidelity(mat,pure) == Approx(1) );
625 
626  // test when density matrix is a random pure state
628  matRef = getKetBra(r1, r1); // actually pure |r1><r1|
629  toQureg(mat, matRef);
630 
631  // <pure|r1><r1|pure> = |<r1|pure>|^2 = |sum_j conj(r1_j) * pure_j|^2
632  qcomp dotProd = 0;
633  for (size_t i=0; i<r1.size(); i++)
634  dotProd += conj(r1[i]) * pureRef[i];
635  qreal refFid = pow(abs(dotProd), 2);
636 
637  REQUIRE( calcFidelity(mat,pure) == Approx(refFid) );
638  }
639  SECTION( "mixed" ) {
640 
642  toQureg(pure, pureRef);
643 
644  // test when density matrix is mixed
646  toQureg(mat, matRef);
647 
648  // <pure|mat|pure> = <pure| (Mat|pure>)
649  QVector rhs = matRef * pureRef;
650  qcomp dotProd = 0;
651  for (size_t i=0; i<rhs.size(); i++)
652  dotProd += conj(pureRef[i]) * rhs[i];
653 
654  REQUIRE( imag(dotProd) == Approx(0).margin(REAL_EPS) );
655  REQUIRE( calcFidelity(mat,pure) == Approx(real(dotProd)) );
656  }
657  SECTION( "unnormalised" ) {
658 
659  // test when both density matrix and pure state are unnormalised
660  QVector pureRef = getRandomQVector(1<<NUM_QUBITS);
661  QMatrix matRef = getRandomQMatrix(1<<NUM_QUBITS);
662  toQureg(pure, pureRef);
663  toQureg(mat, matRef);
664 
665  // real[ <pure|mat|pure> ] = real[ <pure| (Mat|pure>) ]
666  QVector rhs = matRef * pureRef;
667  qcomp dotProd = 0;
668  for (size_t i=0; i<rhs.size(); i++)
669  dotProd += conj(pureRef[i]) * rhs[i];
670 
671  REQUIRE( calcFidelity(mat,pure) == Approx(real(dotProd)) );
672  }
673  }
674  }
675  SECTION( "input validation" ) {
676 
677  SECTION( "dimensions" ) {
678 
679  // two state-vectors
681  REQUIRE_THROWS_WITH( calcFidelity(vec2,vec), Contains("Dimensions") && Contains("don't match") );
682  destroyQureg(vec2, QUEST_ENV);
683 
684  // density-matrix and state-vector
686  REQUIRE_THROWS_WITH( calcFidelity(mat2,vec), Contains("Dimensions") && Contains("don't match") );
687  destroyQureg(mat2, QUEST_ENV);
688  }
689  SECTION( "density-matrices" ) {
690 
691  // two mixed statess
692  REQUIRE_THROWS_WITH( calcFidelity(mat,mat), Contains("Second argument must be a state-vector") );
693  }
694  }
695  destroyQureg(vec, QUEST_ENV);
696  destroyQureg(mat, QUEST_ENV);
697  destroyQureg(pure, QUEST_ENV);
698 }

References calcFidelity(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomQVector(), getRandomStateVector(), NUM_QUBITS, Qureg::numQubitsRepresented, qcomp, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [15/106]

TEST_CASE ( "calcHilbertSchmidtDistance"  ,
""  [calculations] 
)
See also
calcHilbertSchmidtDistance
Author
Tyson Jones

Definition at line 706 of file test_calculations.cpp.

706  {
707 
710 
711  SECTION( "correctness" ) {
712 
713  // perform these random tests 10 times
714  GENERATE( range(0,10) );
715 
716  SECTION( "density-matrix" ) {
717 
718  SECTION( "pure" ) {
719 
720  // create random |r1><r1| and |r2><r2| states
722  QMatrix m1 = getKetBra(r1,r1);
723  toQureg(mat1, m1);
725  QMatrix m2 = getKetBra(r2,r2);
726  toQureg(mat2, m2);
727 
728  // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
729  qreal tr = 0;
730  for (size_t i=0; i<m1.size(); i++)
731  for (size_t j=0; j<m1.size(); j++)
732  tr += pow(abs(m1[i][j] - m2[i][j]), 2);
733 
734  qreal res = calcHilbertSchmidtDistance(mat1, mat2);
735  REQUIRE( res == Approx(sqrt(tr)) );
736 
737  }
738  SECTION( "normalised" ) {
739 
742  toQureg(mat1, ref1);
743  toQureg(mat2, ref2);
744 
745  // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
746  qreal tr = 0;
747  for (size_t i=0; i<ref1.size(); i++)
748  for (size_t j=0; j<ref1.size(); j++)
749  tr += pow(abs(ref1[i][j] - ref2[i][j]), 2);
750 
751  qreal res = calcHilbertSchmidtDistance(mat1, mat2);
752  REQUIRE( res == Approx(sqrt(tr)) );
753  }
754  SECTION( "unnormalised" ) {
755 
756  // mat1 and mat2 are both random matrices
759  toQureg(mat1, ref1);
760  toQureg(mat2, ref2);
761 
762  // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
763  qreal tr = 0;
764  for (size_t i=0; i<ref1.size(); i++)
765  for (size_t j=0; j<ref1.size(); j++)
766  tr += pow(abs(ref1[i][j] - ref2[i][j]), 2);
767 
768  qreal res = calcHilbertSchmidtDistance(mat1, mat2);
769  REQUIRE( res == Approx(sqrt(tr)) );
770  }
771  }
772  }
773  SECTION( "input validation") {
774 
775  SECTION( "dimensions" ) {
776 
778  REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(mat1,mat3), Contains("Dimensions") && Contains("don't match") );
779  destroyQureg(mat3, QUEST_ENV);
780  }
781  SECTION( "state-vector" ) {
782 
784 
785  REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(vec,mat1), Contains("valid only for density matrices") );
786  REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(mat1,vec), Contains("valid only for density matrices") );
787  REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(vec,vec), Contains("valid only for density matrices") );
788 
789  destroyQureg(vec, QUEST_ENV);
790  }
791  }
792  destroyQureg(mat1, QUEST_ENV);
793  destroyQureg(mat2, QUEST_ENV);
794 }

References calcHilbertSchmidtDistance(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomStateVector(), NUM_QUBITS, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [16/106]

TEST_CASE ( "calcInnerProduct"  ,
""  [calculations] 
)
See also
calcInnerProduct
Author
Tyson Jones

Definition at line 802 of file test_calculations.cpp.

802  {
803 
806 
807  SECTION( "correctness" ) {
808 
809  // perform these random tests 10 times
810  GENERATE( range(0,10) );
811 
812  SECTION( "state-vector" ) {
813 
814  SECTION( "normalised" ) {
815 
816  // <r1|r2> = sum_j conj(r1_j) * r2_j
819  qcomp prod = 0;
820  for (size_t i=0; i<r1.size(); i++)
821  prod += conj(r1[i]) * r2[i];
822 
823  toQureg(vec1, r1);
824  toQureg(vec2, r2);
825  Complex res = calcInnerProduct(vec1,vec2);
826 
827  REQUIRE( res.real == Approx(real(prod)) );
828  REQUIRE( res.imag == Approx(imag(prod)) );
829  }
830  SECTION( "unnormalised" ) {
831 
832  // <r1|r2> = sum_j conj(r1_j) * r2_j
835  qcomp prod = 0;
836  for (size_t i=0; i<r1.size(); i++)
837  prod += conj(r1[i]) * r2[i];
838 
839  toQureg(vec1, r1);
840  toQureg(vec2, r2);
841  Complex res = calcInnerProduct(vec1,vec2);
842 
843  REQUIRE( res.real == Approx(real(prod)) );
844  REQUIRE( res.imag == Approx(imag(prod)) );
845  }
846  }
847  }
848  SECTION( "input validation" ) {
849 
850  SECTION( "dimensions" ) {
851 
852  Qureg vec3 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
853  REQUIRE_THROWS_WITH( calcInnerProduct(vec1,vec3), Contains("Dimensions") && Contains("don't match") );
854  destroyQureg(vec3, QUEST_ENV);
855  }
856  SECTION( "density-matrix" ) {
857 
859 
860  REQUIRE_THROWS_WITH( calcInnerProduct(vec1,mat), Contains("valid only for state-vectors") );
861  REQUIRE_THROWS_WITH( calcInnerProduct(mat,vec1), Contains("valid only for state-vectors") );
862  REQUIRE_THROWS_WITH( calcInnerProduct(mat,mat), Contains("valid only for state-vectors") );
863 
864  destroyQureg(mat, QUEST_ENV);
865  }
866  }
867  destroyQureg(vec1, QUEST_ENV);
868  destroyQureg(vec2, QUEST_ENV);
869 }

References calcInnerProduct(), createDensityQureg(), createQureg(), destroyQureg(), getRandomQVector(), getRandomStateVector(), Complex::imag, NUM_QUBITS, qcomp, QUEST_ENV, Complex::real, and toQureg().

◆ TEST_CASE() [17/106]

TEST_CASE ( "calcProbOfOutcome"  ,
""  [calculations] 
)
See also
calcProbOfOutcome
Author
Tyson Jones

Definition at line 877 of file test_calculations.cpp.

877  {
878 
881 
882  SECTION( "correctness" ) {
883 
884  int target = GENERATE( range(0,NUM_QUBITS) );
885  int outcome = GENERATE( 0, 1 );
886 
887  SECTION( "state-vector" ) {
888 
889  SECTION( "normalised" ) {
890 
892  toQureg(vec, ref);
893 
894  // prob is sum of |amp|^2 of amplitudes where target bit is outcome
895  qreal prob = 0;
896  for (size_t ind=0; ind<ref.size(); ind++) {
897  int bit = (ind >> target) & 1; // target-th bit
898  if (bit == outcome)
899  prob += pow(abs(ref[ind]), 2);
900  }
901 
902  REQUIRE( calcProbOfOutcome(vec, target, outcome) == Approx(prob) );
903  }
904  SECTION( "unnormalised" ) {
905 
907  toQureg(vec, ref);
908 
909  // prob is (sum of |amp|^2 of amplitudes where target bit is zero)
910  // or 1 - (this) if outcome == 1
911  qreal prob = 0;
912  for (size_t ind=0; ind<ref.size(); ind++) {
913  int bit = (ind >> target) & 1; // target-th bit
914  if (bit == 0)
915  prob += pow(abs(ref[ind]), 2);
916  }
917  if (outcome == 1)
918  prob = 1 - prob;
919 
920  REQUIRE( calcProbOfOutcome(vec, target, outcome) == Approx(prob) );
921  }
922  }
923  SECTION( "density-matrix" ) {
924 
925  SECTION( "pure" ) {
926 
927  // set mat to a random |r><r|
929  toQureg(mat, getKetBra(ref, ref));
930 
931  // calc prob of the state-vector
932  qreal prob = 0;
933  for (size_t ind=0; ind<ref.size(); ind++) {
934  int bit = (ind >> target) & 1; // target-th bit
935  if (bit == outcome)
936  prob += pow(abs(ref[ind]), 2);
937  }
938 
939  REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(prob) );
940  }
941  SECTION( "mixed" ) {
942 
944  toQureg(mat, ref);
945 
946  // prob is sum of diagonal amps (should be real) where target bit is outcome
947  qcomp tr = 0;
948  for (size_t ind=0; ind<ref.size(); ind++) {
949  int bit = (ind >> target) & 1; // target-th bit
950  if (bit == outcome)
951  tr += ref[ind][ind];
952  }
953  REQUIRE( imag(tr) == Approx(0).margin(REAL_EPS) );
954 
955  REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(real(tr)) );
956  }
957  SECTION( "unnormalised" ) {
958 
960  toQureg(mat, ref);
961 
962  // prob is (sum of real of diagonal amps where target bit is outcome)
963  // or 1 - (this) if outcome == 1
964  qreal tr = 0;
965  for (size_t ind=0; ind<ref.size(); ind++) {
966  int bit = (ind >> target) & 1; // target-th bit
967  if (bit == 0)
968  tr += real(ref[ind][ind]);
969  }
970  if (outcome == 1)
971  tr = 1 - tr;
972 
973  REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(tr) );
974  }
975  }
976  }
977  SECTION( "validation" ) {
978 
979  SECTION( "qubit indices" ) {
980 
981  int target = GENERATE( -1, NUM_QUBITS );
982  REQUIRE_THROWS_WITH( calcProbOfOutcome(vec, target, 0), Contains("Invalid target qubit") );
983  }
984  SECTION( "outcome value" ) {
985 
986  int outcome = GENERATE( -1, 2 );
987  REQUIRE_THROWS_WITH( calcProbOfOutcome(vec, 0, outcome), Contains("Invalid measurement outcome") );
988  }
989  }
990  destroyQureg(vec, QUEST_ENV);
991  destroyQureg(mat, QUEST_ENV);
992 }

References calcProbOfOutcome(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomQVector(), getRandomStateVector(), NUM_QUBITS, qcomp, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [18/106]

TEST_CASE ( "calcPurity"  ,
""  [calculations] 
)
See also
calcPurity
Author
Tyson Jones

Definition at line 1000 of file test_calculations.cpp.

1000  {
1001 
1003 
1004  SECTION( "correctness" ) {
1005 
1006  // perform the following random tests 10 times
1007  GENERATE( range(1,10) );
1008 
1009  SECTION( "density-matrix" ) {
1010 
1011  SECTION( "pure" ) {
1012 
1013  // pure states have unity purity
1014  initZeroState(mat);
1015  REQUIRE( calcPurity(mat) == 1 );
1016 
1017  // (try also a pure random L2-vector)
1019  QMatrix m1 = getKetBra(r1, r1); // |r><r|
1020  toQureg(mat, m1);
1021  REQUIRE( calcPurity(mat) == Approx(1) );
1022 
1023  }
1024  SECTION( "mixed" ) {
1025 
1026  // mixed states have 1/2^N < purity < 1
1028  toQureg(mat, ref);
1029  qreal purity = calcPurity(mat);
1030  REQUIRE( purity < 1 );
1031  REQUIRE( purity >= 1/pow(2.,NUM_QUBITS) );
1032 
1033  // compare to Tr(rho^2)
1034  QMatrix prod = ref*ref;
1035  qreal tr = 0;
1036  for (size_t i=0; i<prod.size(); i++)
1037  tr += real(prod[i][i]);
1038  REQUIRE( purity == Approx(tr) );
1039  }
1040  SECTION( "unnormalised" ) {
1041 
1042  // unphysical states give sum_{ij} |rho_ij|^2
1044  qreal tot = 0;
1045  for (size_t i=0; i<ref.size(); i++)
1046  for (size_t j=0; j<ref.size(); j++)
1047  tot += pow(abs(ref[i][j]), 2);
1048 
1049  toQureg(mat, ref);
1050  REQUIRE( calcPurity(mat) == Approx(tot) );
1051  }
1052  }
1053  }
1054  SECTION( "input validation" ) {
1055 
1056  SECTION( "state-vector" ) {
1057 
1059  REQUIRE_THROWS_WITH( calcPurity(vec), Contains("valid only for density matrices") );
1060  destroyQureg(vec, QUEST_ENV);
1061  }
1062  }
1063  destroyQureg(mat, QUEST_ENV);
1064 }

References calcPurity(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomStateVector(), initZeroState(), NUM_QUBITS, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [19/106]

TEST_CASE ( "calcTotalProb"  ,
""  [calculations] 
)
See also
calcTotalProb
Author
Tyson Jones

Definition at line 1072 of file test_calculations.cpp.

1072  {
1073 
1076 
1077  SECTION( "correctness" ) {
1078 
1079  SECTION( "state-vector" ) {
1080 
1081  // normalised: prob(vec) = 1
1082  initPlusState(vec);
1083  REQUIRE( calcTotalProb(vec) == Approx(1) );
1084 
1085  // zero norm: prob(vec) = 0
1086  initBlankState(vec);
1087  REQUIRE( calcTotalProb(vec) == 0 );
1088 
1089  // random L2 state: prob(vec) = 1
1091  REQUIRE( calcTotalProb(vec) == Approx(1) );
1092 
1093  // unnormalised: prob(vec) = sum_i |vec_i|^2
1094  initDebugState(vec);
1095  QVector ref = toQVector(vec);
1096  qreal refProb = 0;
1097  for (size_t i=0; i<ref.size(); i++)
1098  refProb += pow(abs(ref[i]), 2);
1099  REQUIRE( calcTotalProb(vec) == Approx(refProb) );
1100  }
1101  SECTION( "density-matrix" ) {
1102 
1103  // normalised: prob(mat) = 1
1104  initPlusState(mat);
1105  REQUIRE( calcTotalProb(mat) == Approx(1) );
1106 
1107  // zero norm: prob(mat) = 0
1108  initBlankState(mat);
1109  REQUIRE( calcTotalProb(mat) == 0 );
1110 
1111  // random density matrix: prob(mat) = 1
1113  REQUIRE( calcTotalProb(mat) == Approx(1) );
1114 
1115  // unnormalised: prob(mat) = sum_i real(mat_{ii})
1116  initDebugState(mat);
1117  QMatrix ref = toQMatrix(mat);
1118  qreal refProb = 0;
1119  for (size_t i=0; i<ref.size(); i++)
1120  refProb += real(ref[i][i]);
1121  REQUIRE( calcTotalProb(mat) == Approx(refProb) );
1122  }
1123  }
1124  SECTION( "input validation" ) {
1125 
1126  // no validation
1127  SUCCEED();
1128  }
1129  destroyQureg(vec, QUEST_ENV);
1130  destroyQureg(mat, QUEST_ENV);
1131 }

References calcTotalProb(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomStateVector(), initBlankState(), initDebugState(), initPlusState(), NUM_QUBITS, qreal, QUEST_ENV, toQMatrix(), toQureg(), and toQVector().

◆ TEST_CASE() [20/106]

TEST_CASE ( "cloneQureg"  ,
""  [state_initialisations] 
)
See also
cloneQureg
Author
Tyson Jones

Definition at line 15 of file test_state_initialisations.cpp.

15  {
16 
19 
20  SECTION( "correctness" ) {
21 
22  SECTION( "state-vector" ) {
23 
25 
26  // make sure states start differently
27  initDebugState(vec1);
28  initBlankState(vec2);
29  REQUIRE( !areEqual(vec1, vec2) );
30 
31  // make sure vec2 is changed
32  QVector copy1 = toQVector(vec1);
33  cloneQureg(vec2, vec1);
34  REQUIRE( areEqual(vec1, vec2) );
35 
36  // make sure vec1 unaffected
37  REQUIRE( areEqual(vec1, copy1) );
38 
39  destroyQureg(vec2, QUEST_ENV);
40  }
41  SECTION( "density-matrix" ) {
42 
44 
45  // make sure states start differently
46  initDebugState(mat1);
47  initBlankState(mat2);
48  REQUIRE( !areEqual(mat1, mat2) );
49 
50  // make sure vec2 is changed
51  QMatrix copy1 = toQMatrix(mat1);
52  cloneQureg(mat2, mat1);
53  REQUIRE( areEqual(mat1, mat2) );
54 
55  // make sure vec1 unaffected
56  REQUIRE( areEqual(mat1, copy1) );
57 
58  destroyQureg(mat2, QUEST_ENV);
59  }
60  }
61  SECTION( "input validation" ) {
62 
63  SECTION( "qureg type" ) {
64 
65  REQUIRE_THROWS_WITH( cloneQureg(mat1, vec1), Contains("both be state-vectors") && Contains("density matrices") );
66  REQUIRE_THROWS_WITH( cloneQureg(vec1, mat1), Contains("both be state-vectors") && Contains("density matrices") );
67  }
68  SECTION( "qureg dimensions" ) {
69 
72 
73  REQUIRE_THROWS_WITH( cloneQureg(vec1, vec3), Contains("Dimensions") && Contains("don't match") );
74  REQUIRE_THROWS_WITH( cloneQureg(mat1, mat3), Contains("Dimensions") && Contains("don't match") );
75 
76  destroyQureg(vec3, QUEST_ENV);
77  destroyQureg(mat3, QUEST_ENV);
78  }
79  }
80  destroyQureg(vec1, QUEST_ENV);
81  destroyQureg(mat1, QUEST_ENV);
82 }

References areEqual(), cloneQureg(), createDensityQureg(), createQureg(), destroyQureg(), initBlankState(), initDebugState(), NUM_QUBITS, Qureg::numQubitsRepresented, QUEST_ENV, toQMatrix(), and toQVector().

◆ TEST_CASE() [21/106]

TEST_CASE ( "collapseToOutcome"  ,
""  [gates] 
)
See also
collapseToOutcome
Author
Tyson Jones

Definition at line 15 of file test_gates.cpp.

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

References areEqual(), collapseToOutcome(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomStateVector(), initClassicalState(), initZeroState(), NUM_QUBITS, qcomp, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [22/106]

TEST_CASE ( "compactUnitary"  ,
""  [unitaries] 
)
See also
compactUnitary
Author
Tyson Jones

Definition at line 46 of file test_unitaries.cpp.

46  {
47 
48  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
49 
50  qcomp a = getRandomReal(-1,1) * expI(getRandomReal(0,2*M_PI));
51  qcomp b = sqrt(1-abs(a)*abs(a)) * expI(getRandomReal(0,2*M_PI));
52  Complex alpha = toComplex( a );
53  Complex beta = toComplex( b );
54  QMatrix op = toQMatrix(alpha, beta);
55 
56  SECTION( "correctness" ) {
57 
58  int target = GENERATE( range(0,NUM_QUBITS) );
59 
60  SECTION( "state-vector" ) {
61 
62  compactUnitary(quregVec, target, alpha, beta);
63  applyReferenceOp(refVec, target, op);
64  REQUIRE( areEqual(quregVec, refVec) );
65  }
66  SECTION( "density-matrix" ) {
67 
68  compactUnitary(quregMatr, target, alpha, beta);
69  applyReferenceOp(refMatr, target, op);
70  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
71  }
72  }
73  SECTION( "input validation" ) {
74 
75  SECTION( "qubit indices" ) {
76 
77  int target = GENERATE( -1, NUM_QUBITS );
78  REQUIRE_THROWS_WITH( compactUnitary(quregVec, target, alpha, beta), Contains("Invalid target") );
79  }
80  SECTION( "unitarity" ) {
81 
82  // unitary when |alpha|^2 + |beta|^2 = 1
83  alpha = {.real=1, .imag=2};
84  beta = {.real=3, .imag=4};
85  REQUIRE_THROWS_WITH( compactUnitary(quregVec, 0, alpha, beta), Contains("unitary") );
86  }
87  }
88  CLEANUP_TEST( quregVec, quregMatr );
89 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, compactUnitary(), expI(), getRandomReal(), NUM_QUBITS, PREPARE_TEST, qcomp, Complex::real, toComplex, and toQMatrix().

◆ TEST_CASE() [23/106]

TEST_CASE ( "controlledCompactUnitary"  ,
""  [unitaries] 
)
See also
controlledCompactUnitary
Author
Tyson Jones

Definition at line 97 of file test_unitaries.cpp.

97  {
98 
99  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
100 
101  qcomp a = getRandomReal(-1,1) * expI(getRandomReal(0,2*M_PI));
102  qcomp b = sqrt(1-abs(a)*abs(a)) * expI(getRandomReal(0,2*M_PI));
103  Complex alpha = toComplex( a );
104  Complex beta = toComplex( b );
105  QMatrix op = toQMatrix(alpha, beta);
106 
107  SECTION( "correctness" ) {
108 
109  int target = GENERATE( range(0,NUM_QUBITS) );
110  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
111 
112  SECTION( "state-vector" ) {
113 
114  controlledCompactUnitary(quregVec, control, target, alpha, beta);
115  applyReferenceOp(refVec, control, target, op);
116  REQUIRE( areEqual(quregVec, refVec) );
117  }
118  SECTION( "density-matrix" ) {
119 
120  controlledCompactUnitary(quregMatr, control, target, alpha, beta);
121  applyReferenceOp(refMatr, control, target, op);
122  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
123  }
124  }
125  SECTION( "input validation" ) {
126 
127  SECTION( "control and target collision" ) {
128 
129  int qb = 0;
130  REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, qb, qb, alpha, beta), Contains("Control") && Contains("target") );
131  }
132  SECTION( "qubit indices" ) {
133 
134  int qb = GENERATE( -1, NUM_QUBITS );
135  REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, qb, 0, alpha, beta), Contains("Invalid control") );
136  REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, 0, qb, alpha, beta), Contains("Invalid target") );
137  }
138  SECTION( "unitarity" ) {
139 
140  // unitary when |a|^2 + |b^2 = 1
141  alpha = {.real=1, .imag=2};
142  beta = {.real=3, .imag=4};
143  REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, 0, 1, alpha, beta), Contains("unitary") );
144  }
145  }
146  CLEANUP_TEST( quregVec, quregMatr );
147 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledCompactUnitary(), expI(), getRandomReal(), NUM_QUBITS, PREPARE_TEST, qcomp, Complex::real, toComplex, and toQMatrix().

◆ TEST_CASE() [24/106]

TEST_CASE ( "controlledMultiQubitUnitary"  ,
""  [unitaries] 
)
See also
controlledMultiQubitUnitary
Author
Tyson Jones

Definition at line 155 of file test_unitaries.cpp.

155  {
156 
157  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
158 
159  // figure out max-num targs (inclusive) allowed by hardware backend
160  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
161  if (maxNumTargs >= NUM_QUBITS)
162  maxNumTargs = NUM_QUBITS - 1; // make space for control qubit
163 
164  SECTION( "correctness" ) {
165 
166  // generate all possible qubit arrangements
167  int ctrl = GENERATE( range(0,NUM_QUBITS) );
168  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
169  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs, ctrl) );
170 
171  // for each qubit arrangement, use a new random unitary
172  QMatrix op = getRandomUnitary(numTargs);
173  ComplexMatrixN matr = createComplexMatrixN(numTargs);
174  toComplexMatrixN(op, matr);
175 
176  SECTION( "state-vector" ) {
177 
178  controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr);
179  applyReferenceOp(refVec, ctrl, targs, numTargs, op);
180  REQUIRE( areEqual(quregVec, refVec) );
181  }
182  SECTION( "density-matrix" ) {
183 
184  controlledMultiQubitUnitary(quregMatr, ctrl, targs, numTargs, matr);
185  applyReferenceOp(refMatr, ctrl, targs, numTargs, op);
186  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
187  }
188  destroyComplexMatrixN(matr);
189  }
190  SECTION( "input validation" ) {
191 
192  SECTION( "number of targets" ) {
193 
194  // there cannot be more targets than qubits in register
195  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrl is invalid)
196  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
197  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
198  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
199  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, targs, numTargs, matr), Contains("Invalid number of target"));
200  destroyComplexMatrixN(matr);
201  }
202  SECTION( "repetition in targets" ) {
203 
204  int ctrl = 0;
205  int numTargs = 3;
206  int targs[] = {1,2,2};
207  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
208 
209  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("target") && Contains("unique"));
210  destroyComplexMatrixN(matr);
211  }
212  SECTION( "control and target collision" ) {
213 
214  int numTargs = 3;
215  int targs[] = {0,1,2};
216  int ctrl = targs[GENERATE_COPY( range(0,numTargs) )];
217  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
218 
219  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("Control") && Contains("target"));
220  destroyComplexMatrixN(matr);
221  }
222  SECTION( "qubit indices" ) {
223 
224  int ctrl = 0;
225  int numTargs = 3;
226  int targs[] = {1,2,3};
227  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
228 
229  int inv = GENERATE( -1, NUM_QUBITS );
230  ctrl = inv;
231  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("Invalid control") );
232 
233  ctrl = 0; // restore valid ctrl
234  targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
235  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("Invalid target") );
236 
237  destroyComplexMatrixN(matr);
238  }
239  SECTION( "unitarity" ) {
240 
241  int ctrl = 0;
242  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
243  ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
244 
245  int targs[numTargs];
246  for (int i=0; i<numTargs; i++)
247  targs[i] = i+1;
248 
249  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("unitary") );
250  destroyComplexMatrixN(matr);
251  }
252  SECTION( "unitary creation" ) {
253 
254  int numTargs = 3;
255  int targs[] = {1,2,3};
256 
257  /* compilers don't auto-initialise to NULL; the below circumstance
258  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
259  * which actually triggers its own validation. Hence this test is useless
260  * currently.
261  */
262  ComplexMatrixN matr;
263  matr.real = NULL;
264  matr.imag = NULL;
265  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, targs, numTargs, matr), Contains("created") );
266  }
267  SECTION( "unitary dimensions" ) {
268 
269  int ctrl = 0;
270  int targs[2] = {1,2};
272 
273  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, 2, matr), Contains("matrix size"));
274  destroyComplexMatrixN(matr);
275  }
276  SECTION( "unitary fits in node" ) {
277 
278  // pretend we have a very limited distributed memory (judged by matr size)
279  quregVec.numAmpsPerChunk = 1;
280  int qb[] = {1,2};
281  ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
282  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, qb, 2, matr), Contains("targets too many qubits"));
283  destroyComplexMatrixN(matr);
284  }
285  }
286  CLEANUP_TEST( quregVec, quregMatr );
287 }

References applyReferenceOp(), areEqual(), calcLog2(), CLEANUP_TEST, controlledMultiQubitUnitary(), createComplexMatrixN(), destroyComplexMatrixN(), getRandomUnitary(), ComplexMatrixN::imag, NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [25/106]

TEST_CASE ( "controlledNot"  ,
""  [unitaries] 
)
See also
controlledNot
Author
Tyson Jones

Definition at line 295 of file test_unitaries.cpp.

295  {
296 
297  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
298  QMatrix op{{0,1},{1,0}};
299 
300  SECTION( "correctness" ) {
301 
302  int target = GENERATE( range(0,NUM_QUBITS) );
303  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
304 
305  SECTION( "state-vector" ) {
306 
307  controlledNot(quregVec, control, target);
308  applyReferenceOp(refVec, control, target, op);
309  REQUIRE( areEqual(quregVec, refVec) );
310  }
311  SECTION( "density-matrix" ) {
312 
313  controlledNot(quregMatr, control, target);
314  applyReferenceOp(refMatr, control, target, op);
315  REQUIRE( areEqual(quregMatr, refMatr) );
316  }
317  }
318  SECTION( "input validation" ) {
319 
320  SECTION( "control and target collision" ) {
321 
322  int qb = GENERATE( range(0,NUM_QUBITS) );
323  REQUIRE_THROWS_WITH( controlledNot(quregVec, qb, qb), Contains("Control") && Contains("target") );
324  }
325  SECTION( "qubit indices" ) {
326 
327  int qb = GENERATE( -1, NUM_QUBITS );
328  REQUIRE_THROWS_WITH( controlledNot(quregVec, qb, 0), Contains("Invalid control") );
329  REQUIRE_THROWS_WITH( controlledNot(quregVec, 0, qb), Contains("Invalid target") );
330  }
331  }
332  CLEANUP_TEST( quregVec, quregMatr );
333 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledNot(), NUM_QUBITS, and PREPARE_TEST.

◆ TEST_CASE() [26/106]

TEST_CASE ( "controlledPauliY"  ,
""  [unitaries] 
)
See also
controlledPauliY
Author
Tyson Jones

Definition at line 341 of file test_unitaries.cpp.

341  {
342 
343  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
344  QMatrix op{{0,-1i},{1i,0}};
345 
346  SECTION( "correctness" ) {
347 
348  int target = GENERATE( range(0,NUM_QUBITS) );
349  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
350 
351  SECTION( "state-vector" ) {
352 
353  controlledPauliY(quregVec, control, target);
354  applyReferenceOp(refVec, control, target, op);
355  REQUIRE( areEqual(quregVec, refVec) );
356  }
357  SECTION( "density-matrix" ) {
358 
359  controlledPauliY(quregMatr, control, target);
360  applyReferenceOp(refMatr, control, target, op);
361  REQUIRE( areEqual(quregMatr, refMatr) );
362  }
363  }
364  SECTION( "input validation" ) {
365 
366  SECTION( "control and target collision" ) {
367 
368  int qb = GENERATE( range(0,NUM_QUBITS) );
369  REQUIRE_THROWS_WITH( controlledPauliY(quregVec, qb, qb), Contains("Control") && Contains("target") );
370  }
371  SECTION( "qubit indices" ) {
372 
373  int qb = GENERATE( -1, NUM_QUBITS );
374  REQUIRE_THROWS_WITH( controlledPauliY(quregVec, qb, 0), Contains("Invalid control") );
375  REQUIRE_THROWS_WITH( controlledPauliY(quregVec, 0, qb), Contains("Invalid target") );
376  }
377  }
378  CLEANUP_TEST( quregVec, quregMatr );
379 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledPauliY(), NUM_QUBITS, and PREPARE_TEST.

◆ TEST_CASE() [27/106]

TEST_CASE ( "controlledPhaseFlip"  ,
""  [unitaries] 
)
See also
controlledPhaseFlip
Author
Tyson Jones

Definition at line 387 of file test_unitaries.cpp.

387  {
388 
389  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
390  QMatrix op{{1,0},{0,-1}};
391 
392  SECTION( "correctness" ) {
393 
394  int target = GENERATE( range(0,NUM_QUBITS) );
395  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
396 
397  SECTION( "state-vector" ) {
398 
399  controlledPhaseFlip(quregVec, control, target);
400  applyReferenceOp(refVec, control, target, op);
401  REQUIRE( areEqual(quregVec, refVec) );
402  }
403  SECTION( "density-matrix" ) {
404 
405  controlledPhaseFlip(quregMatr, control, target);
406  applyReferenceOp(refMatr, control, target, op);
407  REQUIRE( areEqual(quregMatr, refMatr) );
408  }
409  }
410  SECTION( "input validation" ) {
411 
412  SECTION( "control and target collision" ) {
413 
414  int qb = GENERATE( range(0,NUM_QUBITS) );
415  REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, qb, qb), Contains("Control") && Contains("target") );
416  }
417  SECTION( "qubit indices" ) {
418 
419  int qb = GENERATE( -1, NUM_QUBITS );
420  REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, qb, 0), Contains("Invalid control") );
421  REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, 0, qb), Contains("Invalid target") );
422  }
423  }
424  CLEANUP_TEST( quregVec, quregMatr );
425 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledPhaseFlip(), NUM_QUBITS, and PREPARE_TEST.

◆ TEST_CASE() [28/106]

TEST_CASE ( "controlledPhaseShift"  ,
""  [unitaries] 
)
See also
controlledPhaseShift
Author
Tyson Jones

Definition at line 433 of file test_unitaries.cpp.

433  {
434 
435  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
436  qreal param = getRandomReal(-2*M_PI, 2*M_PI);
437  QMatrix op{{1,0},{0,expI(param)}};
438 
439  SECTION( "correctness" ) {
440 
441  int target = GENERATE( range(0,NUM_QUBITS) );
442  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
443 
444  SECTION( "state-vector" ) {
445 
446  controlledPhaseShift(quregVec, control, target, param);
447  applyReferenceOp(refVec, control, target, op);
448  REQUIRE( areEqual(quregVec, refVec) );
449  }
450  SECTION( "density-matrix" ) {
451 
452  controlledPhaseShift(quregMatr, control, target, param);
453  applyReferenceOp(refMatr, control, target, op);
454  REQUIRE( areEqual(quregMatr, refMatr) );
455  }
456  }
457  SECTION( "input validation" ) {
458 
459  SECTION( "control and target collision" ) {
460 
461  int qb = GENERATE( range(0,NUM_QUBITS) );
462  REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
463  }
464  SECTION( "qubit indices" ) {
465 
466  int qb = GENERATE( -1, NUM_QUBITS );
467  REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, qb, 0, param), Contains("Invalid control") );
468  REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, 0, qb, param), Contains("Invalid target") );
469  }
470  }
471  CLEANUP_TEST( quregVec, quregMatr );
472 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledPhaseShift(), expI(), getRandomReal(), NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [29/106]

TEST_CASE ( "controlledRotateAroundAxis"  ,
""  [unitaries] 
)
See also
controlledRotateAroundAxis
Author
Tyson Jones

Definition at line 480 of file test_unitaries.cpp.

480  {
481 
482  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
483 
484  // each test will use a random parameter and axis vector
485  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
486  Vector vec = {.x=getRandomReal(-1,1), .y=getRandomReal(-1,1), .z=getRandomReal(-1,1)};
487 
488  // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
489  // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
490  qreal c = cos(param/2);
491  qreal s = sin(param/2);
492  qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
493  QMatrix op{{c - 1i*vec.z*s/m, -(vec.y + 1i*vec.x)*s/m},
494  {(vec.y - 1i*vec.x)*s/m, c + 1i*vec.z*s/m}};
495 
496  SECTION( "correctness" ) {
497 
498  int target = GENERATE( range(0,NUM_QUBITS) );
499  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
500 
501  SECTION( "state-vector" ) {
502 
503  controlledRotateAroundAxis(quregVec, control, target, param, vec);
504  applyReferenceOp(refVec, control, target, op);
505  REQUIRE( areEqual(quregVec, refVec) );
506  }
507  SECTION( "density-matrix" ) {
508 
509  controlledRotateAroundAxis(quregMatr, control, target, param, vec);
510  applyReferenceOp(refMatr, control, target, op);
511  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
512  }
513  }
514  SECTION( "input validation" ) {
515 
516  SECTION( "control and target collision" ) {
517 
518  int qb = GENERATE( range(0,NUM_QUBITS) );
519  REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, qb, qb, param, vec), Contains("Control") && Contains("target") );
520  }
521  SECTION( "qubit indices" ) {
522 
523  int qb = GENERATE( -1, NUM_QUBITS );
524  REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, qb, 0, param, vec), Contains("Invalid control") );
525  REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, 0, qb, param, vec), Contains("Invalid target") );
526  }
527  SECTION( "zero rotation axis" ) {
528 
529  vec = {.x=0, .y=0, .z=0};
530  REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, 0, 1, param, vec), Contains("Invalid axis") && Contains("zero") );
531  }
532  }
533  CLEANUP_TEST( quregVec, quregMatr );
534 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledRotateAroundAxis(), getRandomReal(), NUM_QUBITS, PREPARE_TEST, qreal, Vector::x, Vector::y, and Vector::z.

◆ TEST_CASE() [30/106]

TEST_CASE ( "controlledRotateX"  ,
""  [unitaries] 
)
See also
controlledRotateX
Author
Tyson Jones

Definition at line 542 of file test_unitaries.cpp.

542  {
543 
544  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
545  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
546  QMatrix op{{cos(param/2), -1i*sin(param/2)}, {-1i*sin(param/2), cos(param/2)}};
547 
548  SECTION( "correctness" ) {
549 
550  int target = GENERATE( range(0,NUM_QUBITS) );
551  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
552 
553  SECTION( "state-vector" ) {
554 
555  controlledRotateX(quregVec, control, target, param);
556  applyReferenceOp(refVec, control, target, op);
557  REQUIRE( areEqual(quregVec, refVec) );
558  }
559  SECTION( "density-matrix" ) {
560 
561  controlledRotateX(quregMatr, control, target, param);
562  applyReferenceOp(refMatr, control, target, op);
563  REQUIRE( areEqual(quregMatr, refMatr) );
564  }
565  }
566  SECTION( "input validation" ) {
567 
568  SECTION( "control and target collision" ) {
569 
570  int qb = GENERATE( range(0,NUM_QUBITS) );
571  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
572  }
573  SECTION( "qubit indices" ) {
574 
575  int qb = GENERATE( -1, NUM_QUBITS );
576  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, 0, param), Contains("Invalid control") );
577  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, 0, qb, param), Contains("Invalid target") );
578  }
579  }
580  CLEANUP_TEST( quregVec, quregMatr );
581 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledRotateX(), getRandomReal(), NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [31/106]

TEST_CASE ( "controlledRotateY"  ,
""  [unitaries] 
)
See also
controlledRotateY
Author
Tyson Jones

Definition at line 589 of file test_unitaries.cpp.

589  {
590 
591  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
592  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
593  QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
594 
595  SECTION( "correctness" ) {
596 
597  int target = GENERATE( range(0,NUM_QUBITS) );
598  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
599 
600  SECTION( "state-vector" ) {
601 
602  controlledRotateY(quregVec, control, target, param);
603  applyReferenceOp(refVec, control, target, op);
604  REQUIRE( areEqual(quregVec, refVec) );
605  }
606  SECTION( "density-matrix" ) {
607 
608  controlledRotateY(quregMatr, control, target, param);
609  applyReferenceOp(refMatr, control, target, op);
610  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
611  }
612  }
613  SECTION( "input validation" ) {
614 
615  SECTION( "control and target collision" ) {
616 
617  int qb = GENERATE( range(0,NUM_QUBITS) );
618  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
619  }
620  SECTION( "qubit indices" ) {
621 
622  int qb = GENERATE( -1, NUM_QUBITS );
623  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, 0, param), Contains("Invalid control") );
624  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, 0, qb, param), Contains("Invalid target") );
625  }
626  }
627  CLEANUP_TEST( quregVec, quregMatr );
628 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledRotateY(), getRandomReal(), NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [32/106]

TEST_CASE ( "controlledRotateZ"  ,
""  [unitaries] 
)
See also
controlledRotateZ
Author
Tyson Jones

Definition at line 636 of file test_unitaries.cpp.

636  {
637 
638  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
639  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
640  QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
641 
642  SECTION( "correctness" ) {
643 
644  int target = GENERATE( range(0,NUM_QUBITS) );
645  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
646 
647  SECTION( "state-vector" ) {
648 
649  controlledRotateZ(quregVec, control, target, param);
650  applyReferenceOp(refVec, control, target, op);
651  REQUIRE( areEqual(quregVec, refVec) );
652  }
653  SECTION( "density-matrix" ) {
654 
655  controlledRotateZ(quregMatr, control, target, param);
656  applyReferenceOp(refMatr, control, target, op);
657  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
658  }
659  }
660  SECTION( "input validation" ) {
661 
662  SECTION( "control and target collision" ) {
663 
664  int qb = GENERATE( range(0,NUM_QUBITS) );
665  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
666  }
667  SECTION( "qubit indices" ) {
668 
669  int qb = GENERATE( -1, NUM_QUBITS );
670  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, 0, param), Contains("Invalid control") );
671  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, 0, qb, param), Contains("Invalid target") );
672  }
673  }
674  CLEANUP_TEST( quregVec, quregMatr );
675 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledRotateZ(), expI(), getRandomReal(), NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [33/106]

TEST_CASE ( "controlledTwoQubitUnitary"  ,
""  [unitaries] 
)
See also
controlledTwoQubitUnitary
Author
Tyson Jones

Definition at line 683 of file test_unitaries.cpp.

683  {
684 
685  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
686 
687  // in distributed mode, each node must be able to fit all amps modified by unitary
688  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
689 
690  // every test will use a unique random matrix
691  QMatrix op = getRandomUnitary(2);
692  ComplexMatrix4 matr = toComplexMatrix4(op);
693 
694  SECTION( "correctness" ) {
695 
696  int targ1 = GENERATE( range(0,NUM_QUBITS) );
697  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
698  int control = GENERATE_COPY( filter([=](int c){ return c!=targ1 && c!=targ2; }, range(0,NUM_QUBITS)) );
699 
700  SECTION( "state-vector" ) {
701 
702  controlledTwoQubitUnitary(quregVec, control, targ1, targ2, matr);
703  applyReferenceOp(refVec, control, targ1, targ2, op);
704  REQUIRE( areEqual(quregVec, refVec) );
705  }
706  SECTION( "density-matrix" ) {
707 
708  controlledTwoQubitUnitary(quregMatr, control, targ1, targ2, matr);
709  applyReferenceOp(refMatr, control, targ1, targ2, op);
710  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
711  }
712  }
713  SECTION( "input validation" ) {
714 
715  SECTION( "repetition of targets" ) {
716  int targ = 0;
717  int ctrl = 1;
718  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ, targ, matr), Contains("target") && Contains("unique") );
719  }
720  SECTION( "control and target collision" ) {
721 
722  int targ1 = 1;
723  int targ2 = 2;
724  int ctrl = GENERATE( 1,2 ); // catch2 bug; can't do GENERATE_COPY( targ1, targ2 )
725  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, targ2, matr), Contains("Control") && Contains("target") );
726  }
727  SECTION( "qubit indices" ) {
728 
729  // valid config
730  int ctrl = 0;
731  int targ1 = 1;
732  int targ2 = 2;
733 
734  int qb = GENERATE( -1, NUM_QUBITS );
735  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, qb, targ1, targ2, matr), Contains("Invalid control") );
736  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, qb, targ2, matr), Contains("Invalid target") );
737  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, qb, matr), Contains("Invalid target") );
738  }
739  SECTION( "unitarity" ) {
740 
741  matr.real[0][0] = 0; // break matr unitarity
742  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), Contains("unitary") );
743  }
744  SECTION( "unitary fits in node" ) {
745 
746  // pretend we have a very limited distributed memory
747  quregVec.numAmpsPerChunk = 1;
748  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), Contains("targets too many qubits"));
749  }
750  }
751  CLEANUP_TEST( quregVec, quregMatr );
752 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledTwoQubitUnitary(), getRandomUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix4::real, and toComplexMatrix4().

◆ TEST_CASE() [34/106]

TEST_CASE ( "controlledUnitary"  ,
""  [unitaries] 
)
See also
controlledUnitary
Author
Tyson Jones

Definition at line 760 of file test_unitaries.cpp.

760  {
761 
762  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
763  QMatrix op = getRandomUnitary(1);
764  ComplexMatrix2 matr = toComplexMatrix2(op);
765 
766  SECTION( "correctness" ) {
767 
768  int target = GENERATE( range(0,NUM_QUBITS) );
769  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
770 
771  SECTION( "state-vector" ) {
772 
773  controlledUnitary(quregVec, control, target, matr);
774  applyReferenceOp(refVec, control, target, op);
775  REQUIRE( areEqual(quregVec, refVec) );
776  }
777  SECTION( "density-matrix" ) {
778 
779  controlledUnitary(quregMatr, control, target, matr);
780  applyReferenceOp(refMatr, control, target, op);
781  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
782  }
783  }
784  SECTION( "input validation" ) {
785 
786  SECTION( "control and target collision" ) {
787 
788  int qb = GENERATE( range(0,NUM_QUBITS) );
789  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, qb, matr), Contains("Control") && Contains("target") );
790  }
791  SECTION( "qubit indices" ) {
792 
793  int qb = GENERATE( -1, NUM_QUBITS );
794  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, 0, matr), Contains("Invalid control") );
795  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, qb, matr), Contains("Invalid target") );
796  }
797  SECTION( "unitarity" ) {
798 
799  matr.real[0][0] = 0; // break unitarity
800  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, 1, matr), Contains("unitary") );
801  }
802  }
803  CLEANUP_TEST( quregVec, quregMatr );
804 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledUnitary(), getRandomUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix2::real, and toComplexMatrix2().

◆ TEST_CASE() [35/106]

TEST_CASE ( "createCloneQureg"  ,
""  [data_structures] 
)
See also
createCloneQureg
Author
Tyson Jones

Definition at line 57 of file test_data_structures.cpp.

57  {
58 
59  SECTION( "state-vector" ) {
60 
63 
64  // check properties are the same
65  REQUIRE( b.isDensityMatrix == a.isDensityMatrix );
67  REQUIRE( b.numQubitsInStateVec == a.numQubitsInStateVec );
68  REQUIRE( b.numAmpsPerChunk == a.numAmpsPerChunk );
69  REQUIRE( b.numAmpsTotal == a.numAmpsTotal );
70 
71  // check state-vector is the same (works for GPU and distributed)
72  REQUIRE( areEqual(a, b) );
73 
76  }
77  SECTION( "density-matrix" ) {
78 
81 
82  // check properties are the same
83  REQUIRE( b.isDensityMatrix == a.isDensityMatrix );
85  REQUIRE( b.numQubitsInStateVec == a.numQubitsInStateVec );
86  REQUIRE( b.numAmpsPerChunk == a.numAmpsPerChunk );
87  REQUIRE( b.numAmpsTotal == a.numAmpsTotal );
88 
89  // check state-vector is the same (works for GPU and distributed)
90  REQUIRE( areEqual(a, b) );
91 
94  }
95 }

References areEqual(), createCloneQureg(), createDensityQureg(), createQureg(), destroyQureg(), Qureg::isDensityMatrix, NUM_QUBITS, Qureg::numAmpsPerChunk, Qureg::numAmpsTotal, Qureg::numQubitsInStateVec, Qureg::numQubitsRepresented, and QUEST_ENV.

◆ TEST_CASE() [36/106]

TEST_CASE ( "createComplexMatrixN"  ,
""  [data_structures] 
)
See also
createComplexMatrixN
Author
Tyson Jones

Definition at line 103 of file test_data_structures.cpp.

103  {
104 
105  SECTION( "correctness" ) {
106 
107  int numQb = GENERATE( range(1,10+1) );
109 
110  // ensure elems are created and initialised to 0
111  REQUIRE( areEqual(toQMatrix(m), getZeroMatrix(1<<numQb)) );
112 
114  }
115  SECTION( "input validation" ) {
116 
117  SECTION( "number of qubits" ) {
118 
119  int numQb = GENERATE( -1, 0 );
120  REQUIRE_THROWS_WITH( createComplexMatrixN(numQb), Contains("Invalid number of qubits") );
121  }
122  }
123 }

References areEqual(), createComplexMatrixN(), destroyComplexMatrixN(), getZeroMatrix(), and toQMatrix().

◆ TEST_CASE() [37/106]

TEST_CASE ( "createDensityQureg"  ,
""  [data_structures] 
)
See also
createDensityQureg
Author
Tyson Jones

Definition at line 131 of file test_data_structures.cpp.

131  {
132 
133  // must be at least one amplitude per node
134  int minNumQb = calcLog2(QUEST_ENV.numRanks) - 1; // density matrix has 2*numQb in state-vec
135  if (minNumQb <= 0)
136  minNumQb = 1;
137 
138  SECTION( "correctness" ) {
139 
140  // try 10 valid number of qubits
141  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
142  Qureg reg = createDensityQureg(numQb, QUEST_ENV);
143 
144  // ensure elems (CPU and/or GPU) are created, and reg begins in |0><0|
145  QMatrix ref = getZeroMatrix(1<<numQb);
146  ref[0][0] = 1; // |0><0|
147  REQUIRE( areEqual(reg, ref) );
148 
149  destroyQureg(reg, QUEST_ENV);
150  }
151  SECTION( "input validation") {
152 
153  SECTION( "number of qubits" ) {
154 
155  int numQb = GENERATE( -1, 0 );
156  REQUIRE_THROWS_WITH( createDensityQureg(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
157  }
158  SECTION( "number of amplitudes" ) {
159 
160  // use local QuESTEnv to safely modify
161  QuESTEnv env = QUEST_ENV;
162 
163  // too many amplitudes to store in type
164  int maxQb = (int) calcLog2(SIZE_MAX) / 2;
165  REQUIRE_THROWS_WITH( createDensityQureg(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
166 
167  /* n-qubit density matrix contains 2^(2n) amplitudes
168  * so can be spread between at most 2^(2n) ranks
169  */
170  int minQb = GENERATE_COPY( range(3,maxQb) );
171  env.numRanks = (int) pow(2, 2*minQb);
172  int numQb = GENERATE_COPY( range(1,minQb) );
173  REQUIRE_THROWS_WITH( createDensityQureg(numQb, env), Contains("Too few qubits") );
174  }
175  SECTION( "available memory" ) {
176 
177  /* there is no reliable way to force the malloc statements to
178  * fail, and hence trigger the matrixInit validation */
179  SUCCEED( );
180  }
181  }
182 }

References areEqual(), calcLog2(), createDensityQureg(), destroyQureg(), getZeroMatrix(), QuESTEnv::numRanks, and QUEST_ENV.

◆ TEST_CASE() [38/106]

TEST_CASE ( "createDiagonalOp"  ,
""  [data_structures] 
)
See also
createDiagonalOp
Author
Tyson Jones

Definition at line 190 of file test_data_structures.cpp.

190  {
191 
192  // must be at least one amplitude per node
193  int minNumQb = calcLog2(QUEST_ENV.numRanks);
194  if (minNumQb == 0)
195  minNumQb = 1;
196 
197  SECTION( "correctness" ) {
198 
199  // try 10 valid number of qubits
200  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
202 
203  // check properties are correct
204  REQUIRE( op.numQubits == numQb );
205  REQUIRE( op.chunkId == QUEST_ENV.rank );
206  REQUIRE( op.numChunks == QUEST_ENV.numRanks );
207  REQUIRE( op.numElemsPerChunk == (1LL << numQb) / QUEST_ENV.numRanks );
208  REQUIRE( op.real != NULL );
209  REQUIRE( op.imag != NULL );
210 
211  // check all elements in CPU are zero
212  REQUIRE( areEqual(toQVector(op), QVector(1LL << numQb)) );
213 
214  // (no concise way to check this for GPU)
215 
217  }
218  SECTION( "input validation" ) {
219 
220  SECTION( "number of qubits" ) {
221 
222  int numQb = GENERATE( -1, 0 );
223  REQUIRE_THROWS_WITH( createDiagonalOp(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
224  }
225  SECTION( "number of amplitudes" ) {
226 
227  // use local QuESTEnv to safely modify
228  QuESTEnv env = QUEST_ENV;
229 
230  // too many amplitudes to store in type
231  int maxQb = (int) calcLog2(SIZE_MAX);
232  REQUIRE_THROWS_WITH( createDiagonalOp(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
233 
234  // too few amplitudes to distribute
235  int minQb = GENERATE_COPY( range(2,maxQb) );
236  env.numRanks = (int) pow(2, minQb);
237  int numQb = GENERATE_COPY( range(1,minQb) );
238  REQUIRE_THROWS_WITH( createDiagonalOp(numQb, env), Contains("Too few qubits") );
239  }
240  SECTION( "available memory" ) {
241 
242  /* there is no reliable way to force the malloc statements to
243  * fail, and hence trigger the diagonalOpInit validation */
244  SUCCEED( );
245  }
246  }
247 }

References areEqual(), calcLog2(), DiagonalOp::chunkId, createDiagonalOp(), destroyDiagonalOp(), DiagonalOp::imag, DiagonalOp::numChunks, DiagonalOp::numElemsPerChunk, DiagonalOp::numQubits, QuESTEnv::numRanks, QUEST_ENV, QuESTEnv::rank, DiagonalOp::real, and toQVector().

◆ TEST_CASE() [39/106]

TEST_CASE ( "createPauliHamil"  ,
""  [data_structures] 
)
See also
createPauliHamil
Author
Tyson Jones

Definition at line 255 of file test_data_structures.cpp.

255  {
256 
257  SECTION( "correctness" ) {
258 
259  int numQb = GENERATE( range(1,5) );
260  int numTerms = GENERATE( range(1,5) );
261  PauliHamil hamil = createPauliHamil(numQb, numTerms);
262 
263  // check fields are correct
264  REQUIRE( hamil.numQubits == numQb );
265  REQUIRE( hamil.numSumTerms == numTerms );
266 
267  // check all Pauli codes are identity
268  int numPaulis = numQb * numTerms;
269  for (int i=0; i<numPaulis; i++) {
270  REQUIRE( hamil.pauliCodes[i] == PAULI_I );
271  }
272 
273  // check all term coefficients can be written to (no seg fault)
274  for (int j=0; j<numTerms; j++) {
275  hamil.termCoeffs[j] = 1;
276  REQUIRE( hamil.termCoeffs[j] == 1 );
277  }
278 
279  destroyPauliHamil(hamil);
280  }
281  SECTION( "input validation") {
282 
283  SECTION( "number of qubits" ) {
284 
285  int numQb = GENERATE( -1, 0 );
286  REQUIRE_THROWS_WITH( createPauliHamil(numQb, 1), Contains("The number of qubits and terms in the PauliHamil must be strictly positive.") );
287  }
288  SECTION( "number of terms" ) {
289 
290  int numTerms = GENERATE( -1, 0 );
291  REQUIRE_THROWS_WITH( createPauliHamil(1, numTerms), Contains("The number of qubits and terms in the PauliHamil must be strictly positive.") );
292  }
293  }
294 }

References createPauliHamil(), destroyPauliHamil(), PauliHamil::numQubits, PauliHamil::numSumTerms, PAULI_I, PauliHamil::pauliCodes, and PauliHamil::termCoeffs.

◆ TEST_CASE() [40/106]

TEST_CASE ( "createPauliHamilFromFile"  ,
""  [data_structures] 
)
See also
createPauliHamilFromFile
Author
Tyson Jones

Definition at line 302 of file test_data_structures.cpp.

302  {
303 
304  // a file created & populated during the test, and deleted afterward
305  char fn[] = "temp_test_output_file.txt";
306 
307  SECTION( "correctness" ) {
308 
309  SECTION( "general" ) {
310 
311  // for several sizes...
312  int numQb = GENERATE( range(1,6) );
313  int numTerms = GENERATE( range(1,6) );
314  int numPaulis = numQb*numTerms;
315 
316  // create a PauliHamil with random elements
317  qreal coeffs[numTerms];
318  enum pauliOpType paulis[numPaulis];
319  setRandomPauliSum(coeffs, paulis, numQb, numTerms);
320 
321  // write the Hamiltonian to file (with trailing whitespace, and trailing newline)
322  FILE* file = fopen(fn, "w");
323  int i=0;
324  for (int n=0; n<numTerms; n++) {
325  fprintf(file, "%.20f ", coeffs[n]);
326  for (int q=0; q<numQb; q++)
327  fprintf(file, "%d ", (int) paulis[i++]);
328  fprintf(file, "\n");
329  }
330  fprintf(file, "\n");
331  fclose(file);
332 
333  // load the file as a PauliHamil
335 
336  // check fields agree
337  REQUIRE( hamil.numQubits == numQb );
338  REQUIRE( hamil.numSumTerms == numTerms );
339 
340  // check elements agree
341  i=0;
342  for (int n=0; n<numTerms; n++) {
343  REQUIRE( hamil.termCoeffs[n] == coeffs[n] );
344  for (int q=0; q<numQb; q++) {
345  REQUIRE( hamil.pauliCodes[i] == paulis[i] );
346  i++;
347  }
348  }
349 
350  destroyPauliHamil(hamil);
351  }
352  SECTION( "edge cases" ) {
353 
354  SECTION( "no trailing newline or space" ) {
355 
356  FILE* file = fopen(fn, "w");
357  fprintf(file, ".1 1 0 1");
358  fclose(file);
360 
361  REQUIRE( hamil.numSumTerms == 1 );
362  REQUIRE( hamil.numQubits == 3 );
363  destroyPauliHamil(hamil);
364  }
365  SECTION( "trailing newlines" ) {
366 
367  FILE* file = fopen(fn, "w");
368  fprintf(file, ".1 1 0 1\n\n\n");
369  fclose(file);
371 
372  REQUIRE( hamil.numSumTerms == 1 );
373  REQUIRE( hamil.numQubits == 3 );
374  destroyPauliHamil(hamil);
375  }
376  SECTION( "trailing spaces" ) {
377 
378  FILE* file = fopen(fn, "w");
379  fprintf(file, ".1 1 0 1 ");
380  fclose(file);
382 
383  REQUIRE( hamil.numSumTerms == 1 );
384  REQUIRE( hamil.numQubits == 3 );
385  destroyPauliHamil(hamil);
386  }
387  }
388  }
389  SECTION( "input validation") {
390 
391  SECTION( "number of qubits" ) {
392 
393  FILE* file = fopen(fn, "w");
394  fprintf(file, ".1 ");
395  fclose(file);
396  REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("The number of qubits") && Contains("strictly positive"));
397  }
398  SECTION( "coefficient type" ) {
399 
400  FILE* file = fopen(fn, "w");
401  fprintf(file, "notanumber 1 2 3");
402  fclose(file);
403  REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("Failed to parse") && Contains("coefficient"));
404  }
405  SECTION( "pauli code" ) {
406 
407  // invalid int
408  FILE* file = fopen(fn, "w");
409  fprintf(file, ".1 1 2 4");
410  fclose(file);
411  REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("invalid pauli code"));
412 
413  // invalid type
414  file = fopen(fn, "w");
415  fprintf(file, ".1 1 2 notanumber");
416  fclose(file);
417  REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("Failed to parse the next expected Pauli code"));
418  }
419  }
420 
421  // delete the test file
422  remove(fn);
423 }

References createPauliHamilFromFile(), destroyPauliHamil(), PauliHamil::numQubits, PauliHamil::numSumTerms, PauliHamil::pauliCodes, qreal, setRandomPauliSum(), and PauliHamil::termCoeffs.

◆ TEST_CASE() [41/106]

TEST_CASE ( "createQuESTEnv"  ,
""  [data_structures] 
)
See also
createQuESTEnv
Author
Tyson Jones

Definition at line 431 of file test_data_structures.cpp.

431  {
432 
433  /* there is no meaningful way to test this */
434  SUCCEED( );
435 }

◆ TEST_CASE() [42/106]

TEST_CASE ( "createQureg"  ,
""  [data_structures] 
)
See also
createQureg
Author
Tyson Jones

Definition at line 443 of file test_data_structures.cpp.

443  {
444 
445  // must be at least one amplitude per node
446  int minNumQb = calcLog2(QUEST_ENV.numRanks);
447  if (minNumQb == 0)
448  minNumQb = 1;
449 
450  SECTION( "correctness" ) {
451 
452  // try 10 valid number of qubits
453  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
454  Qureg reg = createQureg(numQb, QUEST_ENV);
455 
456  // ensure elems (CPU and/or GPU) are created, and reg begins in |0>
457  QVector ref = QVector(1<<numQb);
458  ref[0] = 1; // |0>
459  REQUIRE( areEqual(reg, ref) );
460 
461  destroyQureg(reg, QUEST_ENV);
462  }
463  SECTION( "input validation") {
464 
465  SECTION( "number of qubits" ) {
466 
467  int numQb = GENERATE( -1, 0 );
468  REQUIRE_THROWS_WITH( createQureg(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
469  }
470  SECTION( "number of amplitudes" ) {
471 
472  // use local QuESTEnv to safely modify
473  QuESTEnv env = QUEST_ENV;
474 
475  // too many amplitudes to store in type
476  int maxQb = (int) calcLog2(SIZE_MAX);
477  REQUIRE_THROWS_WITH( createQureg(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
478 
479  // too few amplitudes to distribute
480  int minQb = GENERATE_COPY( range(2,maxQb) );
481  env.numRanks = (int) pow(2, minQb);
482  int numQb = GENERATE_COPY( range(1,minQb) );
483  REQUIRE_THROWS_WITH( createQureg(numQb, env), Contains("Too few qubits") );
484  }
485  SECTION( "available memory" ) {
486 
487  /* there is no reliable way to force the malloc statements to
488  * fail, and hence trigger the matrixInit validation */
489  SUCCEED( );
490  }
491  }
492 }

References areEqual(), calcLog2(), createQureg(), destroyQureg(), QuESTEnv::numRanks, and QUEST_ENV.

◆ TEST_CASE() [43/106]

TEST_CASE ( "destroyComplexMatrixN"  ,
""  [data_structures] 
)
See also
destroyComplexMatrixN
Author
Tyson Jones

Definition at line 500 of file test_data_structures.cpp.

500  {
501 
502  SECTION( "correctness" ) {
503 
504  /* there is no meaningful way to test this */
505  SUCCEED( );
506  }
507  SECTION( "input validation" ) {
508 
509  SECTION( "matrix not created" ) {
510 
511  /* this is an artificial test case since nothing in the QuEST API
512  * automatically sets un-initialised ComplexMatrixN fields to
513  * the NULL pointer.
514  */
515  ComplexMatrixN m;
516  m.real = NULL;
517 
518  /* the error message is also somewhat unrelated, but oh well
519  */
520  REQUIRE_THROWS_WITH( destroyComplexMatrixN(m), Contains("The ComplexMatrixN was not successfully created") );
521  }
522  }
523 }

References destroyComplexMatrixN(), and ComplexMatrixN::real.

◆ TEST_CASE() [44/106]

TEST_CASE ( "destroyDiagonalOp"  ,
""  [data_structures] 
)
See also
destroyDiagonalOp
Author
Tyson Jones

Definition at line 531 of file test_data_structures.cpp.

531  {
532 
533  /* there is no meaningful way to test this */
534  SUCCEED( );
535 }

◆ TEST_CASE() [45/106]

TEST_CASE ( "destroyPauliHamil"  ,
""  [data_structures] 
)
See also
destroyPauliHamil
Author
Tyson Jones

Definition at line 543 of file test_data_structures.cpp.

543  {
544 
545  /* there is no meaningful way to test this.
546  * We e.g. cannot check that the pointers are NULL because
547  * they are not updated; this function passes the struct by value,
548  * not by reference. We also cannot reliably monitor the
549  * memory used in the heap at runtime.
550  */
551  SUCCEED( );
552 }

◆ TEST_CASE() [46/106]

TEST_CASE ( "destroyQuESTEnv"  ,
""  [data_structures] 
)
See also
destroyQuESTEnv
Author
Tyson Jones

Definition at line 560 of file test_data_structures.cpp.

560  {
561 
562  /* there is no meaningful way to test this */
563  SUCCEED( );
564 }

◆ TEST_CASE() [47/106]

TEST_CASE ( "destroyQureg"  ,
""  [data_structures] 
)
See also
destroyQureg
Author
Tyson Jones

Definition at line 572 of file test_data_structures.cpp.

572  {
573 
574  /* there is no meaningful way to test this.
575  * We e.g. cannot check that the pointers are NULL because
576  * they are not updated; this function passes the struct by value,
577  * not by reference. We also cannot reliably monitor the
578  * memory used in the heap at runtime.
579  */
580  SUCCEED( );
581 }

◆ TEST_CASE() [48/106]

TEST_CASE ( "fromComplex"  ,
""  [data_structures] 
)
See also
fromComplex
Author
Tyson Jones

Definition at line 15 of file test_data_structures.cpp.

15  {
16 
17  Complex a = {.real=.5, .imag=-.2};
18  qcomp b = fromComplex(a);
19 
20  REQUIRE( a.real == real(b) );
21  REQUIRE( a.imag == imag(b) );
22 }

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

◆ TEST_CASE() [49/106]

TEST_CASE ( "getAmp"  ,
""  [calculations] 
)
See also
getAmp
Author
Tyson Jones

Definition at line 1139 of file test_calculations.cpp.

1139  {
1140 
1142 
1143  SECTION( "correctness" ) {
1144 
1145  SECTION( "state-vector" ) {
1146 
1147  initDebugState(vec);
1148  QVector ref = toQVector(vec);
1149 
1150  int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1151  Complex amp = getAmp(vec,ind);
1152  REQUIRE( fromComplex(amp) == ref[ind] );
1153  }
1154  }
1155  SECTION( "input validation" ) {
1156 
1157  SECTION( "state index" ) {
1158 
1159  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1160  REQUIRE_THROWS_WITH( getAmp(vec,ind), Contains("Invalid amplitude index") );
1161  }
1162  SECTION( "density-matrix" ) {
1163 
1165  REQUIRE_THROWS_WITH( getAmp(mat,0), Contains("valid only for state-vectors") );
1166  destroyQureg(mat, QUEST_ENV);
1167  }
1168  }
1169  destroyQureg(vec, QUEST_ENV);
1170 }

References createDensityQureg(), createQureg(), destroyQureg(), fromComplex, getAmp(), initDebugState(), NUM_QUBITS, QUEST_ENV, and toQVector().

◆ TEST_CASE() [50/106]

TEST_CASE ( "getDensityAmp"  ,
""  [calculations] 
)
See also
getDensityAmp
Author
Tyson Jones

Definition at line 1178 of file test_calculations.cpp.

1178  {
1179 
1181 
1182  SECTION( "correctness" ) {
1183 
1184  SECTION( "density-matrix" ) {
1185 
1186  initDebugState(mat);
1187  QMatrix ref = toQMatrix(mat);
1188 
1189  int row = GENERATE( range(0,1<<NUM_QUBITS) );
1190  int col = GENERATE( range(0,1<<NUM_QUBITS) );
1191 
1192  Complex amp = getDensityAmp(mat,row,col);
1193  REQUIRE( fromComplex(amp) == ref[row][col] );
1194  }
1195  }
1196  SECTION( "input validation" ) {
1197 
1198  SECTION( "state index" ) {
1199 
1200  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1201  REQUIRE_THROWS_WITH( getDensityAmp(mat,ind,0), Contains("Invalid amplitude index") );
1202  REQUIRE_THROWS_WITH( getDensityAmp(mat,0,ind), Contains("Invalid amplitude index") );
1203 
1204  }
1205  SECTION( "state-vector" ) {
1206 
1208  REQUIRE_THROWS_WITH( getDensityAmp(vec,0,0), Contains("valid only for density matrices") );
1209  destroyQureg(vec, QUEST_ENV);
1210  }
1211  }
1212  destroyQureg(mat, QUEST_ENV);
1213 }

References createDensityQureg(), createQureg(), destroyQureg(), fromComplex, getDensityAmp(), initDebugState(), NUM_QUBITS, QUEST_ENV, and toQMatrix().

◆ TEST_CASE() [51/106]

TEST_CASE ( "getImagAmp"  ,
""  [calculations] 
)
See also
getImagAmp
Author
Tyson Jones

Definition at line 1221 of file test_calculations.cpp.

1221  {
1222 
1224 
1225  SECTION( "correctness" ) {
1226 
1227  SECTION( "state-vector" ) {
1228 
1229  initDebugState(vec);
1230  QVector ref = toQVector(vec);
1231 
1232  int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1233  REQUIRE( getImagAmp(vec,ind) == imag(ref[ind]) );
1234  }
1235  }
1236  SECTION( "input validation" ) {
1237 
1238  SECTION( "state index" ) {
1239 
1240  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1241  REQUIRE_THROWS_WITH( getImagAmp(vec,ind), Contains("Invalid amplitude index") );
1242  }
1243  SECTION( "density-matrix" ) {
1244 
1246  REQUIRE_THROWS_WITH( getImagAmp(mat,0), Contains("valid only for state-vectors") );
1247  destroyQureg(mat, QUEST_ENV);
1248  }
1249  }
1250  destroyQureg(vec, QUEST_ENV);
1251 }

References createDensityQureg(), createQureg(), destroyQureg(), getImagAmp(), initDebugState(), NUM_QUBITS, QUEST_ENV, and toQVector().

◆ TEST_CASE() [52/106]

TEST_CASE ( "getNumAmps"  ,
""  [calculations] 
)
See also
getNumAmps
Author
Tyson Jones

Definition at line 1259 of file test_calculations.cpp.

1259  {
1260 
1261  SECTION( "correctness" ) {
1262 
1263  // test >= NUM_QUBITS so as not to limit distribution size
1264  int numQb = GENERATE( range(NUM_QUBITS, NUM_QUBITS+10) );
1265 
1266  SECTION( "state-vector" ) {
1267 
1268  Qureg vec = createQureg(numQb, QUEST_ENV);
1269  REQUIRE( getNumAmps(vec) == (1<<numQb) );
1270  destroyQureg(vec, QUEST_ENV);
1271  }
1272  }
1273  SECTION( "input validation" ) {
1274 
1275  SECTION( "density-matrix" ) {
1277  REQUIRE_THROWS_WITH( getNumAmps(mat), Contains("valid only for state-vectors") );
1278  destroyQureg(mat, QUEST_ENV);
1279  }
1280  }
1281 }

References createDensityQureg(), createQureg(), destroyQureg(), getNumAmps(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [53/106]

TEST_CASE ( "getNumQubits"  ,
""  [calculations] 
)
See also
getNumQubits
Author
Tyson Jones

Definition at line 1289 of file test_calculations.cpp.

1289  {
1290 
1291  SECTION( "correctness" ) {
1292 
1293  // test >= NUM_QUBITS so as not to limit distribution size
1294  int numQb = GENERATE( range(NUM_QUBITS, NUM_QUBITS+10) );
1295 
1296  SECTION( "state-vector" ) {
1297 
1298  Qureg vec = createQureg(numQb, QUEST_ENV);
1299  REQUIRE( getNumQubits(vec) == numQb );
1300  destroyQureg(vec, QUEST_ENV);
1301  }
1302  SECTION( "density-matrix" ) {
1303 
1304  Qureg mat = createDensityQureg(numQb, QUEST_ENV);
1305  REQUIRE( getNumQubits(mat) == numQb );
1306  destroyQureg(mat, QUEST_ENV);
1307  }
1308  }
1309  SECTION( "input validation" ) {
1310 
1311  // no validation
1312  SUCCEED();
1313  }
1314 }

References createDensityQureg(), createQureg(), destroyQureg(), getNumQubits(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [54/106]

TEST_CASE ( "getProbAmp"  ,
""  [calculations] 
)
See also
getProbAmp
Author
Tyson Jones

Definition at line 1322 of file test_calculations.cpp.

1322  {
1323 
1325 
1326  SECTION( "correctness" ) {
1327 
1328  SECTION( "state-vector" ) {
1329 
1330  initDebugState(vec);
1331  QVector ref = toQVector(vec);
1332 
1333  int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1334  qreal refCalc = pow(abs(ref[ind]), 2);
1335  REQUIRE( getProbAmp(vec,ind) == Approx(refCalc) );
1336  }
1337  }
1338  SECTION( "input validation" ) {
1339 
1340  SECTION( "state index" ) {
1341 
1342  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1343  REQUIRE_THROWS_WITH( getProbAmp(vec,ind), Contains("Invalid amplitude index") );
1344  }
1345  SECTION( "density-matrix" ) {
1346 
1348  REQUIRE_THROWS_WITH( getProbAmp(mat,0), Contains("valid only for state-vectors") );
1349  destroyQureg(mat, QUEST_ENV);
1350  }
1351  }
1352  destroyQureg(vec, QUEST_ENV);
1353 }

References createDensityQureg(), createQureg(), destroyQureg(), getProbAmp(), initDebugState(), NUM_QUBITS, qreal, QUEST_ENV, and toQVector().

◆ TEST_CASE() [55/106]

TEST_CASE ( "getRealAmp"  ,
""  [calculations] 
)
See also
getRealAmp
Author
Tyson Jones

Definition at line 1361 of file test_calculations.cpp.

1361  {
1362 
1364 
1365  SECTION( "correctness" ) {
1366 
1367  SECTION( "state-vector" ) {
1368 
1369  initDebugState(vec);
1370  QVector ref = toQVector(vec);
1371 
1372  int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1373  REQUIRE( getRealAmp(vec,ind) == real(ref[ind]) );
1374  }
1375  }
1376  SECTION( "input validation" ) {
1377 
1378  SECTION( "state index" ) {
1379 
1380  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1381  REQUIRE_THROWS_WITH( getRealAmp(vec,ind), Contains("Invalid amplitude index") );
1382  }
1383  SECTION( "density-matrix" ) {
1384 
1386  REQUIRE_THROWS_WITH( getRealAmp(mat,0), Contains("valid only for state-vectors") );
1387  destroyQureg(mat, QUEST_ENV);
1388  }
1389  }
1390  destroyQureg(vec, QUEST_ENV);
1391 }

References createDensityQureg(), createQureg(), destroyQureg(), getRealAmp(), initDebugState(), NUM_QUBITS, QUEST_ENV, and toQVector().

◆ TEST_CASE() [56/106]

TEST_CASE ( "getStaticComplexMatrixN"  ,
""  [data_structures] 
)
See also
getStaticComplexMatrixN
Author
Tyson Jones

Definition at line 30 of file test_data_structures.cpp.

30  {
31 
32  /* use of this function is illegal in C++ */
33  SUCCEED( );
34 }

◆ TEST_CASE() [57/106]

TEST_CASE ( "hadamard"  ,
""  [unitaries] 
)
See also
hadamard
Author
Tyson Jones

Definition at line 812 of file test_unitaries.cpp.

812  {
813 
814  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
815  qreal a = 1/sqrt(2);
816  QMatrix op{{a,a},{a,-a}};
817 
818  SECTION( "correctness" ) {
819 
820  int target = GENERATE( range(0,NUM_QUBITS) );
821 
822  SECTION( "state-vector ") {
823 
824  hadamard(quregVec, target);
825  applyReferenceOp(refVec, target, op);
826  REQUIRE( areEqual(quregVec, refVec) );
827  }
828  SECTION( "density-matrix" ) {
829 
830  hadamard(quregMatr, target);
831  applyReferenceOp(refMatr, target, op);
832  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
833  }
834  }
835  SECTION( "input validation" ) {
836 
837  SECTION( "qubit indices" ) {
838 
839  int target = GENERATE( -1, NUM_QUBITS );
840  REQUIRE_THROWS_WITH( hadamard(quregVec, target), Contains("Invalid target") );
841  }
842  }
843  CLEANUP_TEST( quregVec, quregMatr );
844 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, hadamard(), NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [58/106]

TEST_CASE ( "initBlankState"  ,
""  [state_initialisations] 
)
See also
initBlankState
Author
Tyson Jones

Definition at line 90 of file test_state_initialisations.cpp.

90  {
91 
94 
95  SECTION( "correctness" ) {
96 
97  SECTION( "state-vector" ) {
98 
99  initBlankState(vec);
100  REQUIRE( areEqual(vec, QVector(1<<NUM_QUBITS)) );
101  }
102  SECTION( "density-matrix" ) {
103 
104  initBlankState(mat);
105  REQUIRE( areEqual(mat, getZeroMatrix(1<<NUM_QUBITS)) );
106  }
107  }
108  SECTION( "input validation" ) {
109 
110  // no user validation
111  SUCCEED( );
112  }
113  destroyQureg(vec, QUEST_ENV);
114  destroyQureg(mat, QUEST_ENV);
115 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initBlankState(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [59/106]

TEST_CASE ( "initClassicalState"  ,
""  [state_initialisations] 
)
See also
initClassicalState
Author
Tyson Jones

Definition at line 123 of file test_state_initialisations.cpp.

123  {
124 
127 
128  SECTION( "correctness" ) {
129 
130  int numInds = (1<<NUM_QUBITS);
131  int ind = GENERATE_COPY( range(0,numInds) );
132 
133  SECTION( "state-vector" ) {
134 
135  initClassicalState(vec, ind);
136  QVector vecRef = QVector(1<<NUM_QUBITS);
137  vecRef[ind] = 1;
138  REQUIRE( areEqual(vec, vecRef) );
139  }
140  SECTION( "density-matrix" ) {
141 
142  initClassicalState(mat, ind);
143  QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
144  matRef[ind][ind] = 1;
145  REQUIRE( areEqual(mat, matRef) );
146  }
147  }
148  SECTION( "input validation" ) {
149 
150  SECTION( "state index" ) {
151 
152  int ind = GENERATE( -1, (1<<NUM_QUBITS) );
153  REQUIRE_THROWS_WITH( initClassicalState(vec, ind), Contains("Invalid state index") );
154  }
155  }
156  destroyQureg(vec, QUEST_ENV);
157  destroyQureg(mat, QUEST_ENV);
158 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initClassicalState(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [60/106]

TEST_CASE ( "initComplexMatrixN"  ,
""  [data_structures] 
)
See also
initComplexMatrixN
Author
Tyson Jones

Definition at line 589 of file test_data_structures.cpp.

589  {
590 
591  /* use of this function is illegal in C++ */
592  SUCCEED( );
593 }

◆ TEST_CASE() [61/106]

TEST_CASE ( "initDiagonalOp"  ,
""  [data_structures] 
)
See also
initDiagonalOp
Author
Tyson Jones

Definition at line 601 of file test_data_structures.cpp.

601  {
602 
603  // must be at least one amplitude per node
604  int minNumQb = calcLog2(QUEST_ENV.numRanks);
605  if (minNumQb == 0)
606  minNumQb = 1;
607 
608  SECTION( "correctness" ) {
609 
610  // try 10 valid number of qubits
611  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
613 
614  long long int len = (1LL << numQb);
615  qreal reals[len];
616  qreal imags[len];
617  long long int n;
618  for (n=0; n<len; n++) {
619  reals[n] = (qreal) n;
620  imags[n] = (qreal) -2*n; // (n - 2n i)
621  }
622  initDiagonalOp(op, reals, imags);
623 
624  // check that op.real and op.imag were modified...
625  REQUIRE( areEqual(toQVector(op), reals, imags) );
626 
627  // and also that GPU real and imag were modified
628  // via if it modifies an all-unity state-vec correctly
629  Qureg qureg = createQureg(numQb, QUEST_ENV);
630  for (long long int i=0; i<qureg.numAmpsPerChunk; i++) {
631  qureg.stateVec.real[i] = 1;
632  qureg.stateVec.imag[i] = 1;
633  }
634  copyStateToGPU(qureg);
635 
636  QVector prodRef = toQMatrix(op) * toQVector(qureg);
637 
638  // (n - 2n i) * (1 + 1i) = 3n - n*i
639  applyDiagonalOp(qureg, op);
640  copyStateFromGPU(qureg);
641  QVector result = toQVector(qureg);
642  REQUIRE( areEqual(prodRef, result) );
643 
644  destroyQureg(qureg, QUEST_ENV);
646  }
647 }

References applyDiagonalOp(), areEqual(), calcLog2(), copyStateFromGPU(), copyStateToGPU(), createDiagonalOp(), createQureg(), destroyDiagonalOp(), destroyQureg(), initDiagonalOp(), Qureg::numAmpsPerChunk, QuESTEnv::numRanks, qreal, QUEST_ENV, Qureg::stateVec, toQMatrix(), and toQVector().

◆ TEST_CASE() [62/106]

TEST_CASE ( "initPauliHamil"  ,
""  [data_structures] 
)
See also
initPauliHamil
Author
Tyson Jones

Definition at line 655 of file test_data_structures.cpp.

655  {
656 
657  SECTION( "correctness" ) {
658 
659  PauliHamil hamil = createPauliHamil(3, 2);
660 
661  qreal coeffs[] = {-5, 5};
662  enum pauliOpType codes[] = {
665  initPauliHamil(hamil, coeffs, codes);
666 
667  // check everything written correctly
668  for (int t=0; t<2; t++) {
669  REQUIRE( coeffs[t] == hamil.termCoeffs[t] );
670  for (int q=0; q<3; q++) {
671  int ind = 3*t+q;
672  REQUIRE( codes[ind] == hamil.pauliCodes[ind] );
673  }
674  }
675 
676  destroyPauliHamil(hamil);
677  }
678  SECTION( "input validation" ) {
679 
680  SECTION( "parameters" ) {
681 
682  // parameters checked before codes, so safe to leave un-initialised
683  qreal coeffs[1];
684  enum pauliOpType codes[1];
685  PauliHamil hamil;
686 
687  hamil.numQubits = GENERATE( -1, 0 );
688  hamil.numSumTerms = 1;
689  REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("number of qubits") && Contains("strictly positive") );
690 
691  hamil.numQubits = 1;
692  hamil.numSumTerms = GENERATE( -1, 0 );
693  REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("terms") && Contains("strictly positive") );
694  }
695  SECTION( "Pauli codes" ) {
696 
697  int numQb = 3;
698  int numTerms = 2;
699  int numCodes = numQb * numTerms;
700  qreal coeffs[numTerms];
701  enum pauliOpType codes[numCodes];
702 
703  // make only one code invalid
704  for (int i=0; i<numCodes; i++)
705  codes[i] = PAULI_I;
706  codes[GENERATE_COPY( range(0,numCodes) )] = (pauliOpType) GENERATE( -1, 4 );
707 
708  PauliHamil hamil = createPauliHamil(numQb, numTerms);
709  REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("Invalid Pauli code") );
710  destroyPauliHamil(hamil);
711  }
712  }
713 }

References createPauliHamil(), destroyPauliHamil(), initPauliHamil(), PauliHamil::numQubits, PauliHamil::numSumTerms, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, PauliHamil::pauliCodes, qreal, and PauliHamil::termCoeffs.

◆ TEST_CASE() [63/106]

TEST_CASE ( "initPlusState"  ,
""  [state_initialisations] 
)
See also
initPlusState
Author
Tyson Jones

Definition at line 166 of file test_state_initialisations.cpp.

166  {
167 
170 
171  SECTION( "correctness" ) {
172 
173  SECTION( "state-vector" ) {
174 
175  // |+> = 1/sqrt(N^2) sum_i |i>
176  // = 1/sqrt(N^2) {1, ..., 1}
177  initPlusState(vec);
178  QVector vecRef = QVector(1<<NUM_QUBITS);
179  for (size_t i=0; i<vecRef.size(); i++)
180  vecRef[i] = 1./sqrt(pow(2,NUM_QUBITS));
181  REQUIRE( areEqual(vec, vecRef) );
182  }
183  SECTION( "density-matrix" ) {
184 
185  // |+><+| = 1/sqrt(N^2) sum_i |i> 1/sqrt(N^2) sum_j <j|
186  // = 1/(N^2) sum_{ij} |i><j|
187  // = 1/(N^2) {{1, ..., 1}, ...}
188  initPlusState(mat);
189  QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
190  for (size_t i=0; i<matRef.size(); i++)
191  for (size_t j=0; j<matRef.size(); j++)
192  matRef[i][j] = 1./pow(2, NUM_QUBITS);
193  REQUIRE( areEqual(mat, matRef) );
194  }
195  }
196  SECTION( "input validation" ) {
197 
198  // no user validation
199  SUCCEED( );
200  }
201  destroyQureg(vec, QUEST_ENV);
202  destroyQureg(mat, QUEST_ENV);
203 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initPlusState(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [64/106]

TEST_CASE ( "initPureState"  ,
""  [state_initialisations] 
)
See also
initPureState
Author
Tyson Jones

Definition at line 211 of file test_state_initialisations.cpp.

211  {
212 
215 
216  SECTION( "correctness" ) {
217 
218  SECTION( "state-vector" ) {
219 
220  /* state-vector version just performs cloneQureg */
221 
223 
224  // make sure states start differently
225  initDebugState(vec1);
226  initBlankState(vec2);
227  REQUIRE( !areEqual(vec1, vec2) );
228 
229  // make sure vec2 is overwritten with vec1
230  QVector copy1 = toQVector(vec1);
231  initPureState(vec2, vec1);
232  REQUIRE( areEqual(vec1, vec2) );
233 
234  // make sure vec1 was not modified
235  REQUIRE( areEqual(vec1, copy1) );
236 
237  destroyQureg(vec2, QUEST_ENV);
238  }
239  SECTION( "density-matrix" ) {
240 
241  /* density matrix version initialises matrix in |pure><pure| */
242 
243  initDebugState(vec1); // |vec1> = sum_i a_i |i>
244  QVector copy1 = toQVector(vec1);
245 
246  // make sure mat1 is modified correctly
247  initBlankState(mat1);
248  initPureState(mat1, vec1); // mat1 = |vec1><vec1| = sum_{ij} a_i a_j* |i><j|
249 
250  QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
251  for (size_t i=0; i<matRef.size(); i++)
252  for (size_t j=0; j<matRef.size(); j++)
253  matRef[i][j] = copy1[i] * conj(copy1[j]);
254  REQUIRE( areEqual(mat1, matRef) );
255 
256  // make sure vec1 was not modified
257  REQUIRE( areEqual(vec1, copy1) );
258  }
259  }
260  SECTION( "input validation" ) {
261 
262  SECTION( "qureg types" ) {
263 
264  // density matrix as second arg is illegal (regardless of first arg)
265  REQUIRE_THROWS_WITH( initPureState(vec1, mat1), Contains("Second argument must be a state-vector") );
266  REQUIRE_THROWS_WITH( initPureState(mat1, mat1), Contains("Second argument must be a state-vector") );
267  }
268  SECTION( "qureg dimensions" ) {
269 
270  Qureg vec2 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
271  REQUIRE_THROWS_WITH( initPureState(vec1, vec2), Contains("Dimensions") && Contains("don't match") );
272  REQUIRE_THROWS_WITH( initPureState(mat1, vec2), Contains("Dimensions") && Contains("don't match") );
273  destroyQureg(vec2, QUEST_ENV);
274  }
275  }
276  destroyQureg(vec1, QUEST_ENV);
277  destroyQureg(mat1, QUEST_ENV);
278 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initBlankState(), initDebugState(), initPureState(), NUM_QUBITS, QUEST_ENV, and toQVector().

◆ TEST_CASE() [65/106]

TEST_CASE ( "initStateFromAmps"  ,
""  [state_initialisations] 
)
See also
initStateFromAmps
Author
Tyson Jones

Definition at line 286 of file test_state_initialisations.cpp.

286  {
287 
289 
290  SECTION( "correctness" ) {
291 
292  SECTION( "state-vector" ) {
293 
294  // create arbitrary (but distinctly non-zero) amplitudes
295  qreal ampsRe[vec.numAmpsTotal];
296  qreal ampsIm[vec.numAmpsTotal];
297  QVector vecRef = QVector(vec.numAmpsTotal);
298  for (int i=0; i<vec.numAmpsTotal; i++) {
299  ampsRe[i] = 2*i;
300  ampsIm[i] = 2*i + 1;
301  vecRef[i] = (ampsRe[i]) + 1i*(ampsIm[i]);
302  }
303 
304  initBlankState(vec);
305  initStateFromAmps(vec, ampsRe, ampsIm);
306  REQUIRE( areEqual(vec, vecRef) );
307  }
308  }
309  SECTION( "input validation" ) {
310 
311  SECTION( "density-matrix" ) {
312 
314  REQUIRE_THROWS_WITH( initStateFromAmps(mat, NULL, NULL), Contains("valid only for state-vectors") );
315  destroyQureg(mat, QUEST_ENV);
316  }
317  }
318  destroyQureg(vec, QUEST_ENV);
319 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), initBlankState(), initStateFromAmps(), NUM_QUBITS, Qureg::numAmpsTotal, qreal, and QUEST_ENV.

◆ TEST_CASE() [66/106]

TEST_CASE ( "initZeroState"  ,
""  [state_initialisations] 
)
See also
initZeroState
Author
Tyson Jones

Definition at line 327 of file test_state_initialisations.cpp.

327  {
328 
331 
332  SECTION( "correctness" ) {
333 
334  SECTION( "state-vector" ) {
335 
336  initBlankState(vec);
337  initZeroState(vec);
338 
339  QVector refVec = QVector(vec.numAmpsTotal);
340  refVec[0] = 1;
341  REQUIRE( areEqual(vec, refVec) );
342  }
343  SECTION( "density-matrix" ) {
344 
345  initBlankState(mat);
346  initZeroState(mat);
347 
348  QMatrix refMat = getZeroMatrix(1<<mat.numQubitsRepresented);
349  refMat[0][0] = 1;
350  REQUIRE( areEqual(mat, refMat) );
351  }
352  }
353  SECTION( "input validation" ) {
354 
355  // no input validation
356  SUCCEED( );
357  }
358  destroyQureg(vec, QUEST_ENV);
359  destroyQureg(mat, QUEST_ENV);
360 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initBlankState(), initZeroState(), NUM_QUBITS, Qureg::numAmpsTotal, Qureg::numQubitsRepresented, and QUEST_ENV.

◆ TEST_CASE() [67/106]

TEST_CASE ( "measure"  ,
""  [gates] 
)
See also
measure
Author
Tyson Jones

Definition at line 121 of file test_gates.cpp.

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

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomStateVector(), measure(), NUM_QUBITS, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [68/106]

TEST_CASE ( "measureWithStats"  ,
""  [gates] 
)
See also
measureWithStats
Author
Tyson Jones

Definition at line 213 of file test_gates.cpp.

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

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomStateVector(), measureWithStats(), NUM_QUBITS, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [69/106]

TEST_CASE ( "mixDamping"  ,
""  [decoherence] 
)
See also
mixDamping
Author
Tyson Jones

Definition at line 23 of file test_decoherence.cpp.

23  {
24 
25  PREPARE_TEST(qureg, ref);
26 
27  SECTION( "correctness" ) {
28 
29  int target = GENERATE( range(0,NUM_QUBITS) );
30  qreal prob = getRandomReal(0, 1);
31  mixDamping(qureg, target, prob);
32 
33  // ref -> kraus0 ref kraus0^dagger + kraus1 ref kraus1^dagger
34  QMatrix kraus0{{1,0},{0,sqrt(1-prob)}};
35  QMatrix rho0 = ref;
36  applyReferenceOp(rho0, target, kraus0);
37  QMatrix kraus1{{0,sqrt(prob)},{0,0}};
38  QMatrix rho1 = ref;
39  applyReferenceOp(rho1, target, kraus1);
40  ref = rho0 + rho1;
41 
42  REQUIRE( areEqual(qureg, ref) );
43  }
44  SECTION( "validation ") {
45 
46  SECTION( "qubit index" ) {
47 
48  int target = GENERATE( -1, NUM_QUBITS );
49  REQUIRE_THROWS_WITH( mixDamping(qureg, target, 0), Contains("Invalid target") );
50 
51  }
52  SECTION( "probability" ) {
53 
54  REQUIRE_THROWS_WITH( mixDamping(qureg, 0, -.1), Contains("Probabilities") );
55  REQUIRE_THROWS_WITH( mixDamping(qureg, 0, 1.1), Contains("Probabilities") );
56  }
57  SECTION( "density-matrix" ) {
58 
60  REQUIRE_THROWS_WITH( mixDamping(vec, 0, 0), Contains("density matrices") );
61  destroyQureg(vec, QUEST_ENV);
62  }
63  }
64  destroyQureg(qureg, QUEST_ENV);
65 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixDamping(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [70/106]

TEST_CASE ( "mixDensityMatrix"  ,
""  [decoherence] 
)
See also
mixDensityMatrix
Author
Tyson Jones

Definition at line 73 of file test_decoherence.cpp.

73  {
74 
77  initDebugState(qureg1);
78  initDebugState(qureg2);
79  QMatrix ref1 = toQMatrix(qureg1);
80  QMatrix ref2 = toQMatrix(qureg2);
81 
82  SECTION( "correctness" ) {
83 
84  // test p in {0, 1} and 10 random values in (0,1)
85  qreal prob = GENERATE( 0., 1., take(10, random(0.,1.)) );
86  mixDensityMatrix(qureg1, prob, qureg2);
87 
88  // ensure target qureg modified correctly
89  ref1 = (1-prob)*ref1 + (prob)*ref2;
90  REQUIRE( areEqual(qureg1, ref1) );
91 
92  // enure other qureg was not modified
93  REQUIRE( areEqual(qureg2, ref2) );
94  }
95  SECTION( "input validation" ) {
96 
97  SECTION( "probabilities") {
98 
99  qreal prob = GENERATE( -0.1, 1.1 );
100  REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, prob, qureg2), Contains("Probabilities") );
101  }
102  SECTION( "density matrices" ) {
103 
104  // one is statevec
106  REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, 0, state1), Contains("density matrices") );
107  REQUIRE_THROWS_WITH( mixDensityMatrix(state1, 0, qureg1), Contains("density matrices") );
108 
109  // both are statevec
111  REQUIRE_THROWS_WITH( mixDensityMatrix(state1, 0, state2), Contains("density matrices") );
112 
113  destroyQureg(state1, QUEST_ENV);
114  destroyQureg(state2, QUEST_ENV);
115  }
116  SECTION( "matching dimensions" ) {
117 
119  REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, 0, qureg3), Contains("Dimensions") );
120  REQUIRE_THROWS_WITH( mixDensityMatrix(qureg3, 0, qureg1), Contains("Dimensions") );
121  destroyQureg(qureg3, QUEST_ENV);
122  }
123  }
124  destroyQureg(qureg1, QUEST_ENV);
125  destroyQureg(qureg2, QUEST_ENV);
126 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), initDebugState(), mixDensityMatrix(), NUM_QUBITS, Qureg::numQubitsRepresented, qreal, QUEST_ENV, and toQMatrix().

◆ TEST_CASE() [71/106]

TEST_CASE ( "mixDephasing"  ,
""  [decoherence] 
)
See also
mixDephasing
Author
Tyson Jones

Definition at line 134 of file test_decoherence.cpp.

134  {
135 
136  PREPARE_TEST(qureg, ref);
137 
138  SECTION( "correctness " ) {
139 
140  int target = GENERATE( range(0,NUM_QUBITS) );
141  qreal prob = getRandomReal(0, 1/2.);
142  mixDephasing(qureg, target, prob);
143 
144  // ref -> (1 - prob) ref + prob Z ref Z
145  QMatrix phaseRef = ref;
146  applyReferenceOp(phaseRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
147  ref = ((1 - prob) * ref) + (prob * phaseRef);
148 
149  REQUIRE( areEqual(qureg, ref) );
150  }
151  SECTION( "validation ") {
152 
153  SECTION( "qubit index" ) {
154 
155  int target = GENERATE( -1, NUM_QUBITS );
156  REQUIRE_THROWS_WITH( mixDephasing(qureg, target, 0), Contains("Invalid target") );
157 
158  }
159  SECTION( "probability" ) {
160 
161  REQUIRE_THROWS_WITH( mixDephasing(qureg, 0, -.1), Contains("Probabilities") );
162  REQUIRE_THROWS_WITH( mixDephasing(qureg, 0, .6), Contains("probability") && Contains("cannot exceed 1/2") );
163  }
164  SECTION( "density-matrix" ) {
165 
167  REQUIRE_THROWS_WITH( mixDephasing(vec, 0, 0), Contains("density matrices") );
168  destroyQureg(vec, QUEST_ENV);
169  }
170  }
171  destroyQureg(qureg, QUEST_ENV);
172 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixDephasing(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [72/106]

TEST_CASE ( "mixDepolarising"  ,
""  [decoherence] 
)
See also
mixDepolarising
Author
Tyson Jones

Definition at line 180 of file test_decoherence.cpp.

180  {
181 
182  PREPARE_TEST(qureg, ref);
183 
184  SECTION( "correctness " ) {
185 
186  int target = GENERATE( range(0,NUM_QUBITS) );
187  qreal prob = getRandomReal(0, 3/4.);
188  mixDepolarising(qureg, target, prob);
189 
190  QMatrix xRef = ref;
191  applyReferenceOp(xRef, target, QMatrix{{0,1},{1,0}}); // X ref X
192  QMatrix yRef = ref;
193  applyReferenceOp(yRef, target, QMatrix{{0,-1i},{1i,0}}); // Y ref Y
194  QMatrix zRef = ref;
195  applyReferenceOp(zRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
196  ref = ((1 - prob) * ref) + ((prob/3.) * ( xRef + yRef + zRef));
197 
198  REQUIRE( areEqual(qureg, ref) );
199  }
200  SECTION( "validation ") {
201 
202  SECTION( "qubit index" ) {
203 
204  int target = GENERATE( -1, NUM_QUBITS );
205  REQUIRE_THROWS_WITH( mixDepolarising(qureg, target, 0), Contains("Invalid target") );
206 
207  }
208  SECTION( "probability" ) {
209 
210  REQUIRE_THROWS_WITH( mixDepolarising(qureg, 0, -.1), Contains("Probabilities") );
211  REQUIRE_THROWS_WITH( mixDepolarising(qureg, 0, .76), Contains("probability") && Contains("cannot exceed 3/4") );
212  }
213  SECTION( "density-matrix" ) {
214 
216  REQUIRE_THROWS_WITH( mixDepolarising(vec, 0, 0), Contains("density matrices") );
217  destroyQureg(vec, QUEST_ENV);
218  }
219  }
220  destroyQureg(qureg, QUEST_ENV);
221 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixDepolarising(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [73/106]

TEST_CASE ( "mixKrausMap"  ,
""  [decoherence] 
)
See also
mixKrausMap
Author
Tyson Jones

Definition at line 520 of file test_decoherence.cpp.

520  {
521 
522  PREPARE_TEST(qureg, ref);
523 
524  SECTION( "correctness" ) {
525 
526  int target = GENERATE( range(0,NUM_QUBITS) );
527  int numOps = GENERATE( range(1,5) ); // max 4 inclusive
528  std::vector<QMatrix> matrs = getRandomKrausMap(1, numOps);
529 
530  ComplexMatrix2 ops[numOps];
531  for (int i=0; i<numOps; i++)
532  ops[i] = toComplexMatrix2(matrs[i]);
533  mixKrausMap(qureg, target, ops, numOps);
534 
535  // set ref -> K_i ref K_i^dagger
536  QMatrix matrRefs[numOps];
537  for (int i=0; i<numOps; i++) {
538  matrRefs[i] = ref;
539  applyReferenceOp(matrRefs[i], target, matrs[i]);
540  }
541  ref = getZeroMatrix(ref.size());
542  for (int i=0; i<numOps; i++)
543  ref += matrRefs[i];
544 
545  REQUIRE( areEqual(qureg, ref, 10*REAL_EPS) );
546  }
547  SECTION( "input validation" ) {
548 
549  SECTION( "number of operators" ) {
550 
551  int numOps = GENERATE( 0, 5 );
552  REQUIRE_THROWS_WITH( mixKrausMap(qureg, 0, NULL, numOps), Contains("operators") );
553  }
554  SECTION( "trace preserving" ) {
555 
556  // valid Kraus map
557  int numOps = GENERATE( range(1,5) ); // max 4 inclusive
558  std::vector<QMatrix> matrs = getRandomKrausMap(1, numOps);
559  ComplexMatrix2 ops[numOps];
560  for (int i=0; i<numOps; i++)
561  ops[i] = toComplexMatrix2(matrs[i]);
562 
563  // make invalid
564  ops[GENERATE_REF( range(0,numOps) )].real[0][0] = 0;
565  REQUIRE_THROWS_WITH( mixKrausMap(qureg, 0, ops, numOps), Contains("trace preserving") );
566 
567  }
568  SECTION( "qubit index" ) {
569 
570  int target = GENERATE( -1, NUM_QUBITS );
571  REQUIRE_THROWS_WITH( mixKrausMap(qureg, target, NULL, 1), Contains("Invalid target qubit") );
572  }
573  SECTION( "density-matrix" ) {
574 
576  REQUIRE_THROWS_WITH( mixKrausMap(vec, 0, NULL, 1), Contains("density matrices") );
577  destroyQureg(vec, QUEST_ENV);
578  }
579  SECTION( "operators fit in node" ) {
580 
581  qureg.numAmpsPerChunk = 3; // min 4
582  REQUIRE_THROWS_WITH( mixKrausMap(qureg, 0, NULL, 1), Contains("targets too many qubits") );
583  }
584  }
585  destroyQureg(qureg, QUEST_ENV);
586 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomKrausMap(), getZeroMatrix(), mixKrausMap(), NUM_QUBITS, PREPARE_TEST, QUEST_ENV, ComplexMatrix2::real, and toComplexMatrix2().

◆ TEST_CASE() [74/106]

TEST_CASE ( "mixMultiQubitKrausMap"  ,
""  [decoherence] 
)
See also
mixMultiQubitKrausMap
Author
Tyson Jones

Definition at line 229 of file test_decoherence.cpp.

229  {
230 
231  PREPARE_TEST(qureg, ref);
232 
233  // figure out max-num (inclusive) targs allowed by hardware backend
234  // (each node must contain as 2^(2*numTargs) amps)
235  int maxNumTargs = calcLog2(qureg.numAmpsPerChunk) / 2;
236 
237  SECTION( "correctness" ) {
238 
239  /* note that this function incurs a stack overhead when numTargs < 4,
240  * and a heap overhead when numTargs >= 4
241  */
242 
243  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
244 
245  // note this is very expensive to try every arrangement (2 min runtime for numTargs=5 alone)
246  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
247 
248  // try the min and max number of operators, and 2 random numbers
249  // (there are way too many to try all!)
250  int maxNumOps = (2*numTargs)*(2*numTargs);
251  int numOps = GENERATE_COPY( 1, maxNumOps, take(2,random(1,maxNumOps)) );
252 
253  // use a new random map
254  std::vector<QMatrix> matrs = getRandomKrausMap(numTargs, numOps);
255 
256  // create map in QuEST datatypes
257  ComplexMatrixN ops[numOps];
258  for (int i=0; i<numOps; i++) {
259  ops[i] = createComplexMatrixN(numTargs);
260  toComplexMatrixN(matrs[i], ops[i]);
261  }
262 
263  mixMultiQubitKrausMap(qureg, targs, numTargs, ops, numOps);
264 
265  // set ref -> K_i ref K_i^dagger
266  QMatrix matrRefs[numOps];
267  for (int i=0; i<numOps; i++) {
268  matrRefs[i] = ref;
269  applyReferenceOp(matrRefs[i], targs, numTargs, matrs[i]);
270  }
271  ref = getZeroMatrix(ref.size());
272  for (int i=0; i<numOps; i++)
273  ref += matrRefs[i];
274 
275  REQUIRE( areEqual(qureg, ref, 1E2*REAL_EPS) );
276 
277  // cleanup QuEST datatypes
278  for (int i=0; i<numOps; i++)
279  destroyComplexMatrixN(ops[i]);
280  }
281  SECTION( "input validation" ) {
282 
283  SECTION( "repetition of target" ) {
284 
285  // make valid targets
286  int targs[NUM_QUBITS];
287  for (int i=0; i<NUM_QUBITS; i++)
288  targs[i] = i;
289 
290  // duplicate one
291  int badInd = GENERATE( range(0,NUM_QUBITS) );
292  int copyInd = GENERATE_COPY( filter([=](int i){ return i!=badInd; }, range(0,NUM_QUBITS)) );
293  targs[badInd] = targs[copyInd];
294 
295  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, NULL, 1), Contains("target qubits") && Contains("unique") );
296  }
297  SECTION( "qubit indices" ) {
298 
299  // make valid targets
300  int targs[NUM_QUBITS];
301  for (int i=0; i<NUM_QUBITS; i++)
302  targs[i] = i;
303 
304  // make one invalid
305  targs[GENERATE( range(0,NUM_QUBITS) )] = GENERATE( -1, NUM_QUBITS );
306 
307  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, NULL, 1), Contains("Invalid target qubit") );
308  }
309  SECTION( "number of operators" ) {
310 
311  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
312  int maxNumOps = (2*numTargs)*(2*numTargs);
313  int numOps = GENERATE_REF( -1, 0, maxNumOps + 1 );
314 
315  // make valid targets to avoid triggering target validation
316  int targs[numTargs];
317  for (int i=0; i<numTargs; i++)
318  targs[i] = i;
319  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, numTargs, NULL, numOps), Contains("operators may be specified") );
320  }
321  SECTION( "initialisation of operators" ) {
322 
323  /* compilers don't auto-initialise to NULL; the below circumstance
324  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
325  * which actually triggers its own validation. Hence this test is useless
326  * currently.
327  */
328 
329  int numTargs = NUM_QUBITS;
330  int numOps = (2*numTargs)*(2*numTargs);
331 
332  // no need to initialise ops, but set their attribs correct to avoid triggering other validation
333  ComplexMatrixN ops[numOps];
334  for (int i=0; i<numOps; i++)
335  ops[i].numQubits = numTargs;
336 
337  // make one of the max-ops explicitly NULL
338  ops[GENERATE_COPY( range(0,numTargs) )].real = NULL;
339 
340  // make valid targets to avoid triggering target validation
341  int targs[numTargs];
342  for (int i=0; i<numTargs; i++)
343  targs[i] = i;
344 
345  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, numTargs, ops, numOps), Contains("ComplexMatrixN") && Contains("created") );
346  }
347  SECTION( "dimension of operators" ) {
348 
349  // make valid (dimension-wise) max-qubits Kraus map
350  int numTargs = NUM_QUBITS;
351  int numOps = (2*numTargs)*(2*numTargs);
352  ComplexMatrixN ops[numOps];
353  for (int i=0; i<numOps; i++)
354  ops[i] = createComplexMatrixN(numTargs);
355 
356  // make one have wrong-dimensions
357  int badInd = GENERATE_COPY( range(0,numTargs) );
358  destroyComplexMatrixN(ops[badInd]);
359  ops[badInd] = createComplexMatrixN(numTargs - 1);
360 
361  // make valid targets to avoid triggering target validation
362  int targs[numTargs];
363  for (int i=0; i<numTargs; i++)
364  targs[i] = i;
365 
366  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, numTargs, ops, numOps), Contains("same number of qubits") );
367 
368  for (int i=0; i<numOps; i++)
369  destroyComplexMatrixN(ops[i]);
370  }
371  SECTION( "trace preserving" ) {
372 
373  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
374  int maxNumOps = (2*numTargs) * (2*numTargs);
375  int numOps = GENERATE_COPY( 1, 2, maxNumOps );
376 
377  // generate a valid map
378  std::vector<QMatrix> matrs = getRandomKrausMap(numTargs, numOps);
379  ComplexMatrixN ops[numOps];
380  for (int i=0; i<numOps; i++) {
381  ops[i] = createComplexMatrixN(numTargs);
382  toComplexMatrixN(matrs[i], ops[i]);
383  }
384 
385  // make only one invalid
386  ops[GENERATE_REF( range(0,numOps) )].real[0][0] = 0;
387 
388  // make valid targets to avoid triggering target validation
389  int targs[numTargs];
390  for (int i=0; i<numTargs; i++)
391  targs[i] = i;
392 
393  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, numTargs, ops, numOps), Contains("trace preserving") );
394 
395  for (int i=0; i<numOps; i++)
396  destroyComplexMatrixN(ops[i]);
397  }
398  SECTION( "density-matrix" ) {
399 
400  Qureg statevec = createQureg(NUM_QUBITS, QUEST_ENV);
401 
402  // make valid targets to avoid triggering target validation
403  int targs[NUM_QUBITS];
404  for (int i=0; i<NUM_QUBITS; i++)
405  targs[i] = i;
406 
407  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(statevec, targs, NUM_QUBITS, NULL, 1), Contains("valid only for density matrices") );
408  destroyQureg(statevec, QUEST_ENV);
409 
410  }
411  SECTION( "operator fits in node" ) {
412 
413  // each node requires (2 numTargs)^2 amplitudes
414  int minAmps = (2*NUM_QUBITS) * (2*NUM_QUBITS);
415 
416  // make valid targets to avoid triggering target validation
417  int targs[NUM_QUBITS];
418  for (int i=0; i<NUM_QUBITS; i++)
419  targs[i] = i;
420 
421  // make a simple Identity map
423  for (int i=0; i<(1<<NUM_QUBITS); i++)
424  ops[0].real[i][i] = 1;
425 
426  // fake a smaller qureg
427  qureg.numAmpsPerChunk = minAmps - 1;
428  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, ops, 1), Contains("targets too many qubits") && Contains("cannot all fit") );
429 
430  destroyComplexMatrixN(ops[0]);
431  }
432  }
433  destroyQureg(qureg, QUEST_ENV);
434 }

References applyReferenceOp(), areEqual(), calcLog2(), createComplexMatrixN(), createQureg(), destroyComplexMatrixN(), destroyQureg(), getRandomKrausMap(), getZeroMatrix(), mixMultiQubitKrausMap(), NUM_QUBITS, PREPARE_TEST, QUEST_ENV, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [75/106]

TEST_CASE ( "mixPauli"  ,
""  [decoherence] 
)
See also
mixPauli
Author
Tyson Jones

Definition at line 442 of file test_decoherence.cpp.

442  {
443 
444  PREPARE_TEST(qureg, ref);
445 
446  SECTION( "correctness" ) {
447 
448  int target = GENERATE( range(0,NUM_QUBITS) );
449 
450  // randomly generate valid pauli-error probabilities
451  qreal probs[3];
452  qreal max0 = 1/2.; // satisfies p1 < 1 - py
453  probs[0] = getRandomReal(0, max0);
454  qreal max1 = (max0 - probs[0])/2.; // p2 can use half of p1's "unused space"
455  probs[1] = getRandomReal(0, max1);
456  qreal max2 = (max1 - probs[1])/2.; // p3 can use half of p2's "unused space"
457  probs[2] = getRandomReal(0, max2);
458 
459  // uniformly randomly assign probs (bound to target)
460  int inds[3] = {0,1,2};
461  std::shuffle(inds,inds+3, std::default_random_engine(1E5 * target));
462  qreal probX = probs[inds[0]]; // seed:target shows no variation
463  qreal probY = probs[inds[1]];
464  qreal probZ = probs[inds[2]];
465 
466  mixPauli(qureg, target, probX, probY, probZ);
467 
468  QMatrix xRef = ref;
469  applyReferenceOp(xRef, target, QMatrix{{0,1},{1,0}}); // X ref X
470  QMatrix yRef = ref;
471  applyReferenceOp(yRef, target, QMatrix{{0,-1i},{1i,0}}); // Y ref Y
472  QMatrix zRef = ref;
473  applyReferenceOp(zRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
474  ref = ((1 - probX - probY - probZ) * ref) +
475  (probX * xRef) + (probY * yRef) + (probZ * zRef);
476 
477  REQUIRE( areEqual(qureg, ref) );
478  }
479  SECTION( "input validation" ) {
480 
481  SECTION( "qubit index" ) {
482 
483  int target = GENERATE( -1, NUM_QUBITS );
484  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, 0), Contains("Invalid target") );
485 
486  }
487  SECTION( "probability" ) {
488 
489  int target = 0;
490 
491  // probs clearly must be in [0, 1]
492  REQUIRE_THROWS_WITH( mixPauli(qureg, target, -.1, 0, 0), Contains("Probabilities") );
493  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, -.1, 0), Contains("Probabilities") );
494  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, -.1), Contains("Probabilities") );
495 
496  // max single-non-zero-prob is 0.5
497  REQUIRE_THROWS_WITH( mixPauli(qureg, target, .6, 0, 0), Contains("cannot exceed the probability") );
498  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, .6, 0), Contains("cannot exceed the probability") );
499  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, .6), Contains("cannot exceed the probability") );
500 
501  // must satisfy px, py, pz < 1 - px - py - pz
502  REQUIRE_THROWS_WITH( mixPauli(qureg, target, .3, .3, .3), Contains("cannot exceed the probability") );
503  }
504  SECTION( "density-matrix" ) {
505 
507  REQUIRE_THROWS_WITH( mixPauli(vec, 0, 0, 0, 0), Contains("density matrices") );
508  destroyQureg(vec, QUEST_ENV);
509  }
510  }
511  destroyQureg(qureg, QUEST_ENV);
512 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixPauli(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [76/106]

TEST_CASE ( "mixTwoQubitDephasing"  ,
""  [decoherence] 
)
See also
mixTwoQubitDephasing
Author
Tyson Jones

Definition at line 594 of file test_decoherence.cpp.

594  {
595 
596  PREPARE_TEST(qureg, ref);
597 
598  SECTION( "correctness" ) {
599 
600  int targ1 = GENERATE( range(0,NUM_QUBITS) );
601  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
602  qreal prob = getRandomReal(0, 3/4.);
603 
604  mixTwoQubitDephasing(qureg, targ1, targ2, prob);
605 
606  // ref -> (1 - prob) ref + prob/3 (Z1 ref Z1 + Z2 ref Z2 + Z1 Z2 ref Z1 Z2)
607  QMatrix zMatr{{1,0},{0,-1}};
608  QMatrix z1Ref = ref;
609  applyReferenceOp(z1Ref, targ1, zMatr); // Z1 ref Z1
610  QMatrix z2Ref = ref;
611  applyReferenceOp(z2Ref, targ2, zMatr); // Z2 ref Z2
612  QMatrix z1z2Ref = ref;
613  applyReferenceOp(z1z2Ref, targ1, zMatr);
614  applyReferenceOp(z1z2Ref, targ2, zMatr); // Z1 Z2 ref Z1 Z2
615  ref = ((1 - prob) * ref) + (prob/3.) * (z1Ref + z2Ref + z1z2Ref);
616 
617  REQUIRE( areEqual(qureg, ref) );
618  }
619  SECTION( "input validation" ) {
620 
621  SECTION( "qubit indices" ) {
622 
623  int targ = GENERATE( -1, NUM_QUBITS );
624  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, targ, 0), Contains("Invalid target") );
625  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, targ, 0, 0), Contains("Invalid target") );
626  }
627  SECTION( "target collision" ) {
628 
629  int targ = GENERATE( range(0,NUM_QUBITS) );
630  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, targ, targ, 0), Contains("target") && Contains("unique") );
631  }
632  SECTION( "probability" ) {
633 
634  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, 1, -.1), Contains("Probabilities") );
635  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, 1, 3/4. + .01), Contains("probability") && Contains("cannot exceed 3/4") );
636  }
637  SECTION( "density-matrix" ) {
638 
640  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(vec, 0, 1, 0), Contains("density matrices") );
641  destroyQureg(vec, QUEST_ENV);
642  }
643  }
644  destroyQureg(qureg, QUEST_ENV);
645 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixTwoQubitDephasing(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [77/106]

TEST_CASE ( "mixTwoQubitDepolarising"  ,
""  [decoherence] 
)
See also
mixTwoQubitDepolarising
Author
Tyson Jones

Definition at line 653 of file test_decoherence.cpp.

653  {
654 
655  PREPARE_TEST(qureg, ref);
656 
657  SECTION( "correctness" ) {
658 
659  int targ1 = GENERATE( range(0,NUM_QUBITS) );
660  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
661  qreal prob = getRandomReal(0, 15/16.);
662 
663  mixTwoQubitDepolarising(qureg, targ1, targ2, prob);
664 
665  QMatrix paulis[4] = {
666  QMatrix{{1,0},{0,1}}, // I
667  QMatrix{{0,1},{1,0}}, // X
668  QMatrix{{0,-1i},{1i,0}}, // Y
669  QMatrix{{1,0},{0,-1}} // Z
670  };
671 
672  int targs[2] = {targ1, targ2};
673  QMatrix refInit = ref;
674  ref = (1 - (16/15.)*prob) * ref;
675  for (int i=0; i<4; i++) {
676  for (int j=0; j<4; j++) {
677  QMatrix term = refInit;
678  applyReferenceOp(term, targs, 2,
679  getKroneckerProduct(paulis[i], paulis[j]));
680  ref += (prob/15.) * term;
681  }
682  }
683 
684  REQUIRE( areEqual(qureg, ref, 1E4*REAL_EPS) );
685  }
686  SECTION( "input validation" ) {
687 
688  SECTION( "qubit indices" ) {
689 
690  int targ = GENERATE( -1, NUM_QUBITS );
691  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, targ, 0), Contains("Invalid target") );
692  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, targ, 0, 0), Contains("Invalid target") );
693  }
694  SECTION( "target collision" ) {
695 
696  int targ = GENERATE( range(0,NUM_QUBITS) );
697  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, targ, targ, 0), Contains("target") && Contains("unique") );
698  }
699  SECTION( "probability" ) {
700 
701  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, 1, -.1), Contains("Probabilities") );
702  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, 1, 15/16. + .01), Contains("probability") && Contains("cannot exceed 15/16") );
703  }
704  SECTION( "density-matrix" ) {
705 
707  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(vec, 0, 1, 0), Contains("density matrices") );
708  destroyQureg(vec, QUEST_ENV);
709  }
710  }
711  destroyQureg(qureg, QUEST_ENV);
712 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getKroneckerProduct(), getRandomReal(), mixTwoQubitDepolarising(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [78/106]

TEST_CASE ( "mixTwoQubitKrausMap"  ,
""  [decoherence] 
)
See also
mixTwoQubitKrausMap
Author
Tyson Jones

Definition at line 720 of file test_decoherence.cpp.

720  {
721 
722  PREPARE_TEST(qureg, ref);
723 
724  SECTION( "correctness" ) {
725 
726  int targ1 = GENERATE( range(0,NUM_QUBITS) );
727  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
728  int numOps = GENERATE( range(1,17) ); // max 16 inclusive
729  std::vector<QMatrix> matrs = getRandomKrausMap(2, numOps);
730 
731  ComplexMatrix4 ops[numOps];
732  for (int i=0; i<numOps; i++)
733  ops[i] = toComplexMatrix4(matrs[i]);
734  mixTwoQubitKrausMap(qureg, targ1, targ2, ops, numOps);
735 
736  // set ref -> K_i ref K_i^dagger
737  int targs[2] = {targ1, targ2};
738  QMatrix matrRefs[numOps];
739  for (int i=0; i<numOps; i++) {
740  matrRefs[i] = ref;
741  applyReferenceOp(matrRefs[i], targs, 2, matrs[i]);
742  }
743  ref = getZeroMatrix(ref.size());
744  for (int i=0; i<numOps; i++)
745  ref += matrRefs[i];
746 
747  REQUIRE( areEqual(qureg, ref, 10*REAL_EPS) );
748  }
749  SECTION( "input validation" ) {
750 
751  SECTION( "number of operators" ) {
752 
753  int numOps = GENERATE( 0, 17 );
754  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, NULL, numOps), Contains("operators") );
755  }
756  SECTION( "trace preserving" ) {
757 
758  // valid Kraus map
759  int numOps = GENERATE( range(1,16) );
760  std::vector<QMatrix> matrs = getRandomKrausMap(2, numOps);
761  ComplexMatrix4 ops[numOps];
762  for (int i=0; i<numOps; i++)
763  ops[i] = toComplexMatrix4(matrs[i]);
764 
765  // make only one of the ops at a time invalid
766  ops[GENERATE_REF( range(0,numOps) )].real[0][0] = 0;
767  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, ops, numOps), Contains("trace preserving") );
768  }
769  SECTION( "target collision" ) {
770 
771  int target = GENERATE( range(0,NUM_QUBITS) );
772  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, target, target, NULL, 1), Contains("target qubits") && Contains("unique") );
773  }
774  SECTION( "qubit index" ) {
775 
776  int target = GENERATE( -1, NUM_QUBITS );
777  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,target, NULL, 1), Contains("Invalid target qubit") );
778  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, target,0, NULL, 1), Contains("Invalid target qubit") );
779  }
780  SECTION( "density-matrix" ) {
781 
783  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(vec, 0,1, NULL, 1), Contains("density matrices") );
784  destroyQureg(vec, QUEST_ENV);
785  }
786  SECTION( "operators fit in node" ) {
787 
788  qureg.numAmpsPerChunk = 15; // min 16
789  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, NULL, 1), Contains("targets too many qubits") );
790  }
791  }
792  destroyQureg(qureg, QUEST_ENV);
793 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomKrausMap(), getZeroMatrix(), mixTwoQubitKrausMap(), NUM_QUBITS, PREPARE_TEST, QUEST_ENV, ComplexMatrix4::real, and toComplexMatrix4().

◆ TEST_CASE() [79/106]

TEST_CASE ( "multiControlledMultiQubitUnitary"  ,
""  [unitaries] 
)
See also
multiControlledMultiQubitUnitary
Author
Tyson Jones

Definition at line 852 of file test_unitaries.cpp.

852  {
853 
854  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
855 
856  // figure out max-num targs (inclusive) allowed by hardware backend
857  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
858  if (maxNumTargs >= NUM_QUBITS)
859  maxNumTargs = NUM_QUBITS - 1; // leave room for min-number of control qubits
860 
861  SECTION( "correctness" ) {
862 
863  // try all possible numbers of targets and controls
864  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
865  int maxNumCtrls = NUM_QUBITS - numTargs;
866  int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
867 
868  // generate all possible valid qubit arrangements
869  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
870  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
871 
872  // for each qubit arrangement, use a new random unitary
873  QMatrix op = getRandomUnitary(numTargs);
874  ComplexMatrixN matr = createComplexMatrixN(numTargs);
875  toComplexMatrixN(op, matr);
876 
877  SECTION( "state-vector" ) {
878 
879  multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, numTargs, matr);
880  applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
881  REQUIRE( areEqual(quregVec, refVec) );
882  }
883  SECTION( "density-matrix" ) {
884 
885  multiControlledMultiQubitUnitary(quregMatr, ctrls, numCtrls, targs, numTargs, matr);
886  applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
887  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
888  }
889  destroyComplexMatrixN(matr);
890  }
891  SECTION( "input validation" ) {
892 
893  SECTION( "number of targets" ) {
894 
895  // there cannot be more targets than qubits in register
896  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
897  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
898  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
899  int ctrls[] = {0};
900  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
901  toComplexMatrixN(getRandomUnitary(NUM_QUBITS+1), matr); // ensure unitary
902 
903  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("Invalid number of target"));
904  destroyComplexMatrixN(matr);
905  }
906  SECTION( "repetition in targets" ) {
907 
908  int ctrls[] = {0};
909  int numTargs = 3;
910  int targs[] = {1,2,2};
911  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
912  toComplexMatrixN(getRandomUnitary(numTargs), matr); // ensure unitary
913 
914  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("target") && Contains("unique"));
915  destroyComplexMatrixN(matr);
916  }
917  SECTION( "number of controls" ) {
918 
919  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
920  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
921  int targs[1] = {0};
923  toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
924 
925  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, 1, matr), Contains("Invalid number of control"));
926  destroyComplexMatrixN(matr);
927  }
928  SECTION( "repetition in controls" ) {
929 
930  int ctrls[] = {0,1,1};
931  int targs[] = {3};
933  toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
934 
935  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 1, matr), Contains("control") && Contains("unique"));
936  destroyComplexMatrixN(matr);
937  }
938  SECTION( "control and target collision" ) {
939 
940  int ctrls[] = {0,1,2};
941  int targs[] = {3,1,4};
943  toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
944 
945  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 3, matr), Contains("Control") && Contains("target") && Contains("disjoint"));
946  destroyComplexMatrixN(matr);
947  }
948  SECTION( "qubit indices" ) {
949 
950  // valid inds
951  int numQb = 2;
952  int qb1[2] = {0,1};
953  int qb2[2] = {2,3};
954  ComplexMatrixN matr = createComplexMatrixN(numQb);
955  toComplexMatrixN(getRandomUnitary(numQb), matr); // ensure unitary
956 
957  // make qb1 invalid
958  int inv = GENERATE( -1, NUM_QUBITS );
959  qb1[GENERATE_COPY(range(0,numQb))] = inv;
960 
961  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb1, numQb, qb2, numQb, matr), Contains("Invalid control") );
962  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb2, numQb, qb1, numQb, matr), Contains("Invalid target") );
963  destroyComplexMatrixN(matr);
964  }
965  SECTION( "unitarity" ) {
966 
967  int ctrls[1] = {0};
968  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
969  int targs[numTargs];
970  for (int i=0; i<numTargs; i++)
971  targs[i] = i+1;
972 
973  ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
974  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("unitary") );
975  destroyComplexMatrixN(matr);
976  }
977  SECTION( "unitary creation" ) {
978 
979  int ctrls[1] = {0};
980  int targs[3] = {1,2,3};
981 
982  /* compilers don't auto-initialise to NULL; the below circumstance
983  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
984  * which actually triggers its own validation. Hence this test is useless
985  * currently.
986  */
987  ComplexMatrixN matr;
988  matr.real = NULL;
989  matr.imag = NULL;
990  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 3, matr), Contains("created") );
991  }
992  SECTION( "unitary dimensions" ) {
993 
994  int ctrls[1] = {0};
995  int targs[2] = {1,2};
996  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
997  toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
998 
999  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), Contains("matrix size"));
1000  destroyComplexMatrixN(matr);
1001  }
1002  SECTION( "unitary fits in node" ) {
1003 
1004  // pretend we have a very limited distributed memory (judged by matr size)
1005  quregVec.numAmpsPerChunk = 1;
1006  int ctrls[1] = {0};
1007  int targs[2] = {1,2};
1009  toComplexMatrixN(getRandomUnitary(2), matr); // ensure unitary
1010 
1011  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), Contains("targets too many qubits"));
1012  destroyComplexMatrixN(matr);
1013  }
1014  }
1015  CLEANUP_TEST( quregVec, quregMatr );
1016 }

References applyReferenceOp(), areEqual(), calcLog2(), CLEANUP_TEST, createComplexMatrixN(), destroyComplexMatrixN(), getRandomUnitary(), ComplexMatrixN::imag, multiControlledMultiQubitUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [80/106]

TEST_CASE ( "multiControlledPhaseFlip"  ,
""  [unitaries] 
)
See also
multiControlledPhaseFlip
Author
Tyson Jones

Definition at line 1024 of file test_unitaries.cpp.

1024  {
1025 
1026  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1027 
1028  // acts on the final control qubit
1029  QMatrix op{{1,0},{0,-1}};
1030 
1031  SECTION( "correctness" ) {
1032 
1033  // generate ALL valid qubit arrangements
1034  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1035  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1036 
1037  SECTION( "state-vector" ) {
1038 
1039  multiControlledPhaseFlip(quregVec, ctrls, numCtrls);
1040  applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1041  REQUIRE( areEqual(quregVec, refVec) );
1042  }
1043  SECTION( "density-matrix" ) {
1044 
1045  multiControlledPhaseFlip(quregMatr, ctrls, numCtrls);
1046  applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1047  REQUIRE( areEqual(quregMatr, refMatr) );
1048  }
1049  }
1050  SECTION( "input validation" ) {
1051 
1052  SECTION( "number of controls" ) {
1053 
1054  int numCtrls = GENERATE( -1, 0, NUM_QUBITS+1 );
1055  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1056  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("Invalid number of qubits"));
1057  }
1058  SECTION( "repetition of controls" ) {
1059 
1060  int numCtrls = 3;
1061  int ctrls[] = {0,1,1};
1062  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("qubits must be unique"));
1063  }
1064  SECTION( "qubit indices" ) {
1065 
1066  int numCtrls = 3;
1067  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1068  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("Invalid qubit") );
1069  }
1070  }
1071  CLEANUP_TEST( quregVec, quregMatr );
1072 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, multiControlledPhaseFlip(), NUM_QUBITS, PREPARE_TEST, and sublists().

◆ TEST_CASE() [81/106]

TEST_CASE ( "multiControlledPhaseShift"  ,
""  [unitaries] 
)
See also
multiControlledPhaseShift
Author
Tyson Jones

Definition at line 1080 of file test_unitaries.cpp.

1080  {
1081 
1082  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1083  qreal param = getRandomReal(-2*M_PI, 2*M_PI);
1084  QMatrix op{{1,0},{0,expI(param)}};
1085 
1086  SECTION( "correctness" ) {
1087 
1088  // generate ALL valid qubit arrangements
1089  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1090  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1091 
1092  SECTION( "state-vector" ) {
1093 
1094  multiControlledPhaseShift(quregVec, ctrls, numCtrls, param);
1095  applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1096  REQUIRE( areEqual(quregVec, refVec) );
1097  }
1098  SECTION( "density-matrix" ) {
1099 
1100  multiControlledPhaseShift(quregMatr, ctrls, numCtrls, param);
1101  applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1102  REQUIRE( areEqual(quregMatr, refMatr) );
1103  }
1104  }
1105  SECTION( "input validation" ) {
1106 
1107  SECTION( "number of controls" ) {
1108 
1109  int numCtrls = GENERATE( -1, 0, NUM_QUBITS+1 );
1110  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1111  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("Invalid number of qubits"));
1112  }
1113  SECTION( "repetition of controls" ) {
1114 
1115  int numCtrls = 3;
1116  int ctrls[] = {0,1,1};
1117  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("qubits must be unique"));
1118  }
1119  SECTION( "qubit indices" ) {
1120 
1121  int numCtrls = 3;
1122  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1123  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("Invalid qubit") );
1124  }
1125  }
1126  CLEANUP_TEST( quregVec, quregMatr );
1127 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getRandomReal(), multiControlledPhaseShift(), NUM_QUBITS, PREPARE_TEST, qreal, and sublists().

◆ TEST_CASE() [82/106]

TEST_CASE ( "multiControlledTwoQubitUnitary"  ,
""  [unitaries] 
)
See also
multiControlledTwoQubitUnitary
Author
Tyson Jones

Definition at line 1135 of file test_unitaries.cpp.

1135  {
1136 
1137  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1138 
1139  // in distributed mode, each node must be able to fit all amps modified by unitary
1140  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
1141 
1142  // every test will use a unique random matrix
1143  QMatrix op = getRandomUnitary(2);
1144  ComplexMatrix4 matr = toComplexMatrix4(op);
1145 
1146  SECTION( "correctness" ) {
1147 
1148  // generate ALL valid qubit arrangements
1149  int targ1 = GENERATE( range(0,NUM_QUBITS) );
1150  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
1151  int targs[] = {targ1, targ2};
1152  int numCtrls = GENERATE( range(1,NUM_QUBITS-1) ); // leave room for 2 targets (upper bound is exclusive)
1153  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, 2) );
1154 
1155  SECTION( "state-vector" ) {
1156 
1157  multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr);
1158  applyReferenceOp(refVec, ctrls, numCtrls, targ1, targ2, op);
1159  REQUIRE( areEqual(quregVec, refVec) );
1160  }
1161  SECTION( "density-matrix" ) {
1162 
1163  multiControlledTwoQubitUnitary(quregMatr, ctrls, numCtrls, targ1, targ2, matr);
1164  applyReferenceOp(refMatr, ctrls, numCtrls, targ1, targ2, op);
1165  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1166  }
1167  }
1168  SECTION( "input validation" ) {
1169 
1170  SECTION( "number of controls" ) {
1171 
1172  // numCtrls=(NUM_QUBITS-1) is ok since requires ctrl qubit inds are invalid
1173  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1174  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1175  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, 0, 1, matr), Contains("Invalid number of control"));
1176  }
1177  SECTION( "repetition of controls" ) {
1178 
1179  int numCtrls = 3;
1180  int ctrls[] = {0,1,1};
1181  int targ1 = 2;
1182  int targ2 = 3;
1183  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("control") && Contains("unique"));;
1184  }
1185  SECTION( "repetition of targets" ) {
1186 
1187  int numCtrls = 3;
1188  int ctrls[] = {0,1,2};
1189  int targ1 = 3;
1190  int targ2 = targ1;
1191  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("target") && Contains("unique"));
1192  }
1193  SECTION( "control and target collision" ) {
1194 
1195  int numCtrls = 3;
1196  int ctrls[] = {0,1,2};
1197  int targ1 = 3;
1198  int targ2 = ctrls[GENERATE_COPY( range(0,numCtrls) )];
1199  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("Control") && Contains("target") );
1200  }
1201  SECTION( "qubit indices" ) {
1202 
1203  // valid indices
1204  int targ1 = 0;
1205  int targ2 = 1;
1206  int numCtrls = 3;
1207  int ctrls[] = { 2, 3, 4 };
1208 
1209  int inv = GENERATE( -1, NUM_QUBITS );
1210  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, inv, targ2, matr), Contains("Invalid target") );
1211  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, inv, matr), Contains("Invalid target") );
1212 
1213  ctrls[numCtrls-1] = inv; // make ctrls invalid
1214  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("Invalid control") );
1215  }
1216  SECTION( "unitarity " ) {
1217 
1218  int ctrls[1] = {0};
1219  matr.real[0][0] = 0; // break unitarity
1220  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), Contains("unitary") );
1221  }
1222  SECTION( "unitary fits in node" ) {
1223 
1224  // pretend we have a very limited distributed memory
1225  quregVec.numAmpsPerChunk = 1;
1226  int ctrls[1] = {0};
1227  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), Contains("targets too many qubits"));
1228  }
1229  }
1230  CLEANUP_TEST( quregVec, quregMatr );
1231 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomUnitary(), multiControlledTwoQubitUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix4::real, sublists(), and toComplexMatrix4().

◆ TEST_CASE() [83/106]

TEST_CASE ( "multiControlledUnitary"  ,
""  [unitaries] 
)
See also
multiControlledUnitary
Author
Tyson Jones

Definition at line 1239 of file test_unitaries.cpp.

1239  {
1240 
1241  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1242 
1243  // every test will use a unique random matrix
1244  QMatrix op = getRandomUnitary(1);
1245  ComplexMatrix2 matr = toComplexMatrix2(op);
1246 
1247  SECTION( "correctness" ) {
1248 
1249  int target = GENERATE( range(0,NUM_QUBITS) );
1250  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
1251  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
1252 
1253  SECTION( "state-vector" ) {
1254 
1255  multiControlledUnitary(quregVec, ctrls, numCtrls, target, matr);
1256  applyReferenceOp(refVec, ctrls, numCtrls, target, op);
1257  REQUIRE( areEqual(quregVec, refVec) );
1258  }
1259  SECTION( "density-matrix" ) {
1260 
1261  multiControlledUnitary(quregMatr, ctrls, numCtrls, target, matr);
1262  applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
1263  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1264  }
1265  }
1266  SECTION( "input validation" ) {
1267 
1268  SECTION( "number of controls" ) {
1269 
1270  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1271  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1272  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, numCtrls, 0, matr), Contains("Invalid number of control"));
1273  }
1274  SECTION( "repetition of controls" ) {
1275 
1276  int ctrls[] = {0,1,1};
1277  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 2, matr), Contains("control") && Contains("unique"));
1278  }
1279  SECTION( "control and target collision" ) {
1280 
1281  int ctrls[] = {0,1,2};
1282  int targ = ctrls[GENERATE( range(0,3) )];
1283  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), Contains("Control") && Contains("target") );
1284  }
1285  SECTION( "qubit indices" ) {
1286 
1287  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1288  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 0, matr), Contains("Invalid control") );
1289 
1290  ctrls[2] = 3; // make ctrls valid
1291  int targ = GENERATE( -1, NUM_QUBITS );
1292  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), Contains("Invalid target") );
1293  }
1294  SECTION( "unitarity" ) {
1295 
1296  matr.real[0][0] = 0; // break matr unitarity
1297  int ctrls[] = {0};
1298  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 1, 1, matr), Contains("unitary") );
1299  }
1300  }
1301  CLEANUP_TEST( quregVec, quregMatr );
1302 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomUnitary(), multiControlledUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix2::real, sublists(), and toComplexMatrix2().

◆ TEST_CASE() [84/106]

TEST_CASE ( "multiQubitUnitary"  ,
""  [unitaries] 
)
See also
multiQubitUnitary
Author
Tyson Jones

Definition at line 1310 of file test_unitaries.cpp.

1310  {
1311 
1312  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1313 
1314  // figure out max-num (inclusive) targs allowed by hardware backend
1315  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
1316 
1317  SECTION( "correctness" ) {
1318 
1319  // generate all possible qubit arrangements
1320  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
1321  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1322 
1323  // for each qubit arrangement, use a new random unitary
1324  QMatrix op = getRandomUnitary(numTargs);
1325  ComplexMatrixN matr = createComplexMatrixN(numTargs);
1326  toComplexMatrixN(op, matr);
1327 
1328  SECTION( "state-vector" ) {
1329 
1330  multiQubitUnitary(quregVec, targs, numTargs, matr);
1331  applyReferenceOp(refVec, targs, numTargs, op);
1332  REQUIRE( areEqual(quregVec, refVec) );
1333  }
1334  SECTION( "density-matrix" ) {
1335 
1336  multiQubitUnitary(quregMatr, targs, numTargs, matr);
1337  applyReferenceOp(refMatr, targs, numTargs, op);
1338  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1339  }
1340  destroyComplexMatrixN(matr);
1341  }
1342  SECTION( "input validation" ) {
1343 
1344  SECTION( "number of targets" ) {
1345 
1346  // there cannot be more targets than qubits in register
1347  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1348  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1349  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
1350 
1351  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("Invalid number of target"));
1352  destroyComplexMatrixN(matr);
1353  }
1354  SECTION( "repetition in targets" ) {
1355 
1356  int numTargs = 3;
1357  int targs[] = {1,2,2};
1358  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1359 
1360  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("target") && Contains("unique"));
1361  destroyComplexMatrixN(matr);
1362  }
1363  SECTION( "qubit indices" ) {
1364 
1365  int numTargs = 3;
1366  int targs[] = {1,2,3};
1367  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1368 
1369  int inv = GENERATE( -1, NUM_QUBITS );
1370  targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
1371  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("Invalid target") );
1372 
1373  destroyComplexMatrixN(matr);
1374  }
1375  SECTION( "unitarity" ) {
1376 
1377  int numTargs = GENERATE_COPY( range(1,maxNumTargs) );
1378  int targs[numTargs];
1379  for (int i=0; i<numTargs; i++)
1380  targs[i] = i+1;
1381 
1382  ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
1383 
1384  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("unitary") );
1385  destroyComplexMatrixN(matr);
1386  }
1387  SECTION( "unitary creation" ) {
1388 
1389  int numTargs = 3;
1390  int targs[] = {1,2,3};
1391 
1392  /* compilers don't auto-initialise to NULL; the below circumstance
1393  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
1394  * which actually triggers its own validation. Hence this test is useless
1395  * currently.
1396  */
1397  ComplexMatrixN matr;
1398  matr.real = NULL;
1399  matr.imag = NULL;
1400  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("created") );
1401  }
1402  SECTION( "unitary dimensions" ) {
1403 
1404  int targs[2] = {1,2};
1405  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
1406 
1407  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, 2, matr), Contains("matrix size"));
1408  destroyComplexMatrixN(matr);
1409  }
1410  SECTION( "unitary fits in node" ) {
1411 
1412  // pretend we have a very limited distributed memory (judged by matr size)
1413  quregVec.numAmpsPerChunk = 1;
1414  int qb[] = {1,2};
1415  ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
1416  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, qb, 2, matr), Contains("targets too many qubits"));
1417  destroyComplexMatrixN(matr);
1418  }
1419  }
1420  CLEANUP_TEST( quregVec, quregMatr );
1421 }

References applyReferenceOp(), areEqual(), calcLog2(), CLEANUP_TEST, createComplexMatrixN(), destroyComplexMatrixN(), getRandomUnitary(), ComplexMatrixN::imag, multiQubitUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [85/106]

TEST_CASE ( "multiRotatePauli"  ,
""  [unitaries] 
)
See also
multiRotatePauli
Author
Tyson Jones

Definition at line 1429 of file test_unitaries.cpp.

1429  {
1430 
1431  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1432  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1433 
1434  SECTION( "correctness" ) {
1435 
1436  int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
1437  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1438 
1439  /* it's too expensive to try ALL Pauli sequences, via
1440  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
1441  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
1442  * Hence, we instead opt to repeatedlyrandomly generate pauliseqs
1443  */
1444  GENERATE( range(0,10) ); // gen 10 random pauli-codes for every targs
1445  pauliOpType paulis[numTargs];
1446  for (int i=0; i<numTargs; i++)
1447  paulis[i] = (pauliOpType) getRandomInt(0,4);
1448 
1449  // exclude identities from reference matrix exp (they apply unwanted global phase)
1450  int refTargs[numTargs];
1451  int numRefTargs = 0;
1452 
1453  QMatrix xMatr{{0,1},{1,0}};
1454  QMatrix yMatr{{0,-1i},{1i,0}};
1455  QMatrix zMatr{{1,0},{0,-1}};
1456 
1457  // build correct reference matrix by pauli-matrix exponentiation...
1458  QMatrix pauliProd{{1}};
1459  for (int i=0; i<numTargs; i++) {
1460  QMatrix fac;
1461  if (paulis[i] == PAULI_I) continue; // exclude I-targets from ref list
1462  if (paulis[i] == PAULI_X) fac = xMatr;
1463  if (paulis[i] == PAULI_Y) fac = yMatr;
1464  if (paulis[i] == PAULI_Z) fac = zMatr;
1465  pauliProd = getKroneckerProduct(fac, pauliProd);
1466 
1467  // include this target in ref list
1468  refTargs[numRefTargs++] = targs[i];
1469  }
1470 
1471  // produces exp(-i param/2 pauliProd), unless pauliProd = I
1472  QMatrix op;
1473  if (numRefTargs > 0)
1474  op = getExponentialOfPauliMatrix(param, pauliProd);
1475 
1476  SECTION( "state-vector" ) {
1477 
1478  multiRotatePauli(quregVec, targs, paulis, numTargs, param);
1479  if (numRefTargs > 0)
1480  applyReferenceOp(refVec, refTargs, numRefTargs, op);
1481  REQUIRE( areEqual(quregVec, refVec) );
1482  }
1483  SECTION( "density-matrix" ) {
1484 
1485  multiRotatePauli(quregMatr, targs, paulis, numTargs, param);
1486  if (numRefTargs > 0)
1487  applyReferenceOp(refMatr, refTargs, numRefTargs, op);
1488  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1489  }
1490  }
1491  SECTION( "input validation" ) {
1492 
1493  SECTION( "number of targets" ) {
1494 
1495  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1496  int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
1497  pauliOpType paulis[NUM_QUBITS+1] = {PAULI_I};
1498  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid number of target"));
1499 
1500  }
1501  SECTION( "repetition of targets" ) {
1502 
1503  int numTargs = 3;
1504  int targs[3] = {0, 1, 1};
1505  pauliOpType paulis[3] = {PAULI_I};
1506  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("target") && Contains("unique"));
1507  }
1508  SECTION( "qubit indices" ) {
1509 
1510  int numTargs = 3;
1511  int targs[3] = {0, 1, 2};
1512  targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
1513  pauliOpType paulis[3] = {PAULI_I};
1514  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid target"));
1515  }
1516  SECTION( "pauli codes" ) {
1517  int numTargs = 3;
1518  int targs[3] = {0, 1, 2};
1519  pauliOpType paulis[3] = {PAULI_I, PAULI_I, PAULI_I};
1520  paulis[GENERATE_COPY(range(0,numTargs))] = (pauliOpType) GENERATE( -1, 4 );
1521  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid Pauli code"));
1522  }
1523  }
1524  CLEANUP_TEST( quregVec, quregMatr );
1525 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getExponentialOfPauliMatrix(), getKroneckerProduct(), getRandomInt(), getRandomReal(), multiRotatePauli(), NUM_QUBITS, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, PREPARE_TEST, qreal, and sublists().

◆ TEST_CASE() [86/106]

TEST_CASE ( "multiRotateZ"  ,
""  [unitaries] 
)
See also
multiRotateZ
Author
Tyson Jones

Definition at line 1533 of file test_unitaries.cpp.

1533  {
1534 
1535  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1536  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1537 
1538  SECTION( "correctness" ) {
1539 
1540  int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
1541  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1542 
1543  // build correct reference matrix by diagonal-matrix exponentiation...
1544  QMatrix zMatr{{1,0},{0,-1}};
1545  QMatrix zProd = zMatr;
1546  for (int t=0; t<numTargs-1; t++)
1547  zProd = getKroneckerProduct(zMatr, zProd); // Z . Z ... Z
1548 
1549  // (-i param/2) Z . I . Z ...
1550  QMatrix expArg = (-1i * param / 2.) *
1551  getFullOperatorMatrix(NULL, 0, targs, numTargs, zProd, NUM_QUBITS);
1552 
1553  // exp( -i param/2 Z . I . Z ...)
1555 
1556  // all qubits to specify full operator matrix on reference structures
1557  int allQubits[NUM_QUBITS];
1558  for (int i=0; i<NUM_QUBITS; i++)
1559  allQubits[i] = i;
1560 
1561  SECTION( "state-vector" ) {
1562 
1563  multiRotateZ(quregVec, targs, numTargs, param);
1564  applyReferenceOp(refVec, allQubits, NUM_QUBITS, op);
1565  REQUIRE( areEqual(quregVec, refVec) );
1566 
1567  }
1568  SECTION( "density-matrix" ) {
1569 
1570  multiRotateZ(quregMatr, targs, numTargs, param);
1571  applyReferenceOp(refMatr, allQubits, NUM_QUBITS, op);
1572  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1573  }
1574  }
1575  SECTION( "input validation" ) {
1576 
1577  SECTION( "number of targets" ) {
1578 
1579  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1580  int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
1581  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("Invalid number of target"));
1582 
1583  }
1584  SECTION( "repetition of targets" ) {
1585 
1586  int numTargs = 3;
1587  int targs[3] = {0, 1, 1};
1588  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("target") && Contains("unique"));
1589  }
1590  SECTION( "qubit indices" ) {
1591 
1592  int numTargs = 3;
1593  int targs[3] = {0, 1, 2};
1594  targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
1595  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("Invalid target"));
1596  }
1597  }
1598  CLEANUP_TEST( quregVec, quregMatr );
1599 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getExponentialOfDiagonalMatrix(), getFullOperatorMatrix(), getKroneckerProduct(), getRandomReal(), multiRotateZ(), NUM_QUBITS, PREPARE_TEST, qreal, and sublists().

◆ TEST_CASE() [87/106]

TEST_CASE ( "multiStateControlledUnitary"  ,
""  [unitaries] 
)
See also
multiStateControlledUnitary
Author
Tyson Jones

Definition at line 1607 of file test_unitaries.cpp.

1607  {
1608 
1609  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1610 
1611  // every test will use a unique random matrix
1612  QMatrix op = getRandomUnitary(1);
1613  ComplexMatrix2 matr = toComplexMatrix2(op);
1614 
1615  // the zero-conditioned control qubits can be effected by notting before/after ctrls
1616  QMatrix notOp{{0,1},{1,0}};
1617 
1618  SECTION( "correctness" ) {
1619 
1620  int target = GENERATE( range(0,NUM_QUBITS) );
1621  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
1622  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
1623  int* ctrlState = GENERATE_COPY( bitsets(numCtrls) );
1624 
1625  SECTION( "state-vector" ) {
1626 
1627  multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, target, matr);
1628 
1629  // simulate controlled-state by notting before & after controls
1630  for (int i=0; i<numCtrls; i++)
1631  if (ctrlState[i] == 0)
1632  applyReferenceOp(refVec, ctrls[i], notOp);
1633  applyReferenceOp(refVec, ctrls, numCtrls, target, op);
1634  for (int i=0; i<numCtrls; i++)
1635  if (ctrlState[i] == 0)
1636  applyReferenceOp(refVec, ctrls[i], notOp);
1637 
1638  REQUIRE( areEqual(quregVec, refVec) );
1639  }
1640  SECTION( "density-matrix" ) {
1641 
1642  multiStateControlledUnitary(quregMatr, ctrls, ctrlState, numCtrls, target, matr);
1643 
1644  // simulate controlled-state by notting before & after controls
1645  for (int i=0; i<numCtrls; i++)
1646  if (ctrlState[i] == 0)
1647  applyReferenceOp(refMatr, ctrls[i], notOp);
1648  applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
1649  for (int i=0; i<numCtrls; i++)
1650  if (ctrlState[i] == 0)
1651  applyReferenceOp(refMatr, ctrls[i], notOp);
1652 
1653  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1654  }
1655  }
1656  SECTION( "input validation" ) {
1657 
1658  SECTION( "number of controls" ) {
1659 
1660  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1661  int ctrls[NUM_QUBITS+1];
1662  int ctrlState[NUM_QUBITS+1] = {0};
1663  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, 0, matr), Contains("Invalid number of control"));
1664  }
1665  SECTION( "repetition of controls" ) {
1666 
1667  int ctrls[] = {0,1,1};
1668  int ctrlState[] = {0, 1, 0};
1669  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 2, matr), Contains("control") && Contains("unique"));
1670  }
1671  SECTION( "control and target collision" ) {
1672 
1673  int ctrls[] = {0,1,2};
1674  int ctrlState[] = {0, 1, 0};
1675  int targ = ctrls[GENERATE( range(0,3) )];
1676  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("Control") && Contains("target") );
1677  }
1678  SECTION( "qubit indices" ) {
1679 
1680  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1681  int ctrlState[] = {0, 1, 0};
1682  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 0, matr), Contains("Invalid control") );
1683 
1684  ctrls[2] = 3; // make ctrls valid
1685  int targ = GENERATE( -1, NUM_QUBITS );
1686  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("Invalid target") );
1687  }
1688  SECTION( "unitarity" ) {
1689 
1690  matr.real[0][0] = 0; // break matr unitarity
1691  int ctrls[] = {0};
1692  int ctrlState[1] = {0};
1693  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 1, 1, matr), Contains("unitary") );
1694  }
1695  SECTION( "control state bits" ) {
1696 
1697  // valid qubits
1698  int ctrls[] = {0, 1, 2};
1699  int ctrlState[] = {0, 0, 0};
1700  int targ = 3;
1701 
1702  // make invalid
1703  ctrlState[2] = GENERATE(-1, 2);
1704  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("state") );
1705  }
1706  }
1707  CLEANUP_TEST( quregVec, quregMatr );
1708 }

References applyReferenceOp(), areEqual(), bitsets(), CLEANUP_TEST, getRandomUnitary(), multiStateControlledUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix2::real, sublists(), and toComplexMatrix2().

◆ TEST_CASE() [88/106]

TEST_CASE ( "pauliX"  ,
""  [unitaries] 
)
See also
pauliX
Author
Tyson Jones

Definition at line 1716 of file test_unitaries.cpp.

1716  {
1717 
1718  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1719  QMatrix op{{0,1},{1,0}};
1720 
1721  SECTION( "correctness" ) {
1722 
1723  int target = GENERATE( range(0,NUM_QUBITS) );
1724 
1725  SECTION( "state-vector" ) {
1726 
1727  pauliX(quregVec, target);
1728  applyReferenceOp(refVec, target, op);
1729  REQUIRE( areEqual(quregVec, refVec) );
1730  }
1731  SECTION( "density-matrix correctness" ) {
1732 
1733  pauliX(quregMatr, target);
1734  applyReferenceOp(refMatr, target, op);
1735  REQUIRE( areEqual(quregMatr, refMatr) );
1736  }
1737  }
1738  SECTION( "input validation" ) {
1739 
1740  SECTION( "qubit indices" ) {
1741 
1742  int target = GENERATE( -1, NUM_QUBITS );
1743  REQUIRE_THROWS_WITH( pauliX(quregVec, target), Contains("Invalid target") );
1744  }
1745  }
1746  CLEANUP_TEST( quregVec, quregMatr );
1747 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, pauliX(), and PREPARE_TEST.

◆ TEST_CASE() [89/106]

TEST_CASE ( "pauliY"  ,
""  [unitaries] 
)
See also
pauliY
Author
Tyson Jones

Definition at line 1755 of file test_unitaries.cpp.

1755  {
1756 
1757  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1758  QMatrix op{{0,-1i},{1i,0}};
1759 
1760  SECTION( "correctness" ) {
1761 
1762  int target = GENERATE( range(0,NUM_QUBITS) );
1763 
1764  SECTION( "state-vector" ) {
1765 
1766  pauliY(quregVec, target);
1767  applyReferenceOp(refVec, target, op);
1768  REQUIRE( areEqual(quregVec, refVec) );
1769  }
1770  SECTION( "density-matrix correctness" ) {
1771 
1772  pauliY(quregMatr, target);
1773  applyReferenceOp(refMatr, target, op);
1774  REQUIRE( areEqual(quregMatr, refMatr) );
1775  }
1776  }
1777  SECTION( "input validation" ) {
1778 
1779  SECTION( "qubit indices" ) {
1780 
1781  int target = GENERATE( -1, NUM_QUBITS );
1782  REQUIRE_THROWS_WITH( pauliY(quregVec, target), Contains("Invalid target") );
1783  }
1784  }
1785  CLEANUP_TEST( quregVec, quregMatr );
1786 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, pauliY(), and PREPARE_TEST.

◆ TEST_CASE() [90/106]

TEST_CASE ( "pauliZ"  ,
""  [unitaries] 
)
See also
pauliZ
Author
Tyson Jones

Definition at line 1794 of file test_unitaries.cpp.

1794  {
1795 
1796  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1797  QMatrix op{{1,0},{0,-1}};
1798 
1799  SECTION( "correctness" ) {
1800 
1801  int target = GENERATE( range(0,NUM_QUBITS) );
1802 
1803  SECTION( "state-vector" ) {
1804 
1805  pauliZ(quregVec, target);
1806  applyReferenceOp(refVec, target, op);
1807  REQUIRE( areEqual(quregVec, refVec) );
1808  }
1809  SECTION( "density-matrix correctness" ) {
1810 
1811  pauliZ(quregMatr, target);
1812  applyReferenceOp(refMatr, target, op);
1813  REQUIRE( areEqual(quregMatr, refMatr) );
1814  }
1815  }
1816  SECTION( "input validation" ) {
1817 
1818  SECTION( "qubit indices" ) {
1819 
1820  int target = GENERATE( -1, NUM_QUBITS );
1821  REQUIRE_THROWS_WITH( pauliZ(quregVec, target), Contains("Invalid target") );
1822  }
1823  }
1824  CLEANUP_TEST( quregVec, quregMatr );
1825 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, pauliZ(), and PREPARE_TEST.

◆ TEST_CASE() [91/106]

TEST_CASE ( "phaseShift"  ,
""  [unitaries] 
)
See also
phaseShift
Author
Tyson Jones

Definition at line 1833 of file test_unitaries.cpp.

1833  {
1834 
1835  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1836  qreal param = getRandomReal(-2*M_PI, 2*M_PI);
1837  QMatrix op{{1,0},{0,expI(param)}};
1838 
1839  SECTION( "correctness" ) {
1840 
1841  int target = GENERATE( range(0,NUM_QUBITS) );
1842 
1843  SECTION( "state-vector ") {
1844 
1845  phaseShift(quregVec, target, param);
1846  applyReferenceOp(refVec, target, op);
1847  REQUIRE( areEqual(quregVec, refVec) );
1848  }
1849  SECTION( "density-matrix" ) {
1850 
1851  phaseShift(quregMatr, target, param);
1852  applyReferenceOp(refMatr, target, op);
1853  REQUIRE( areEqual(quregMatr, refMatr) );
1854  }
1855  }
1856  SECTION( "input validation" ) {
1857 
1858  SECTION( "qubit indices" ) {
1859 
1860  int target = GENERATE( -1, NUM_QUBITS );
1861  REQUIRE_THROWS_WITH( phaseShift(quregVec, target, param), Contains("Invalid target") );
1862  }
1863  }
1864  CLEANUP_TEST( quregVec, quregMatr );
1865 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getRandomReal(), NUM_QUBITS, phaseShift(), PREPARE_TEST, and qreal.

◆ TEST_CASE() [92/106]

TEST_CASE ( "rotateAroundAxis"  ,
""  [unitaries] 
)
See also
rotateAroundAxis
Author
Tyson Jones

Definition at line 1873 of file test_unitaries.cpp.

1873  {
1874 
1875  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1876 
1877  // each test will use a random parameter and axis vector
1878  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1879  Vector vec = {.x=getRandomReal(-1,1), .y=getRandomReal(-1,1), .z=getRandomReal(-1,1)};
1880 
1881  // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
1882  // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
1883  qreal c = cos(param/2);
1884  qreal s = sin(param/2);
1885  qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
1886  QMatrix op{{c - 1i*vec.z*s/m, -(vec.y + 1i*vec.x)*s/m},
1887  {(vec.y - 1i*vec.x)*s/m, c + 1i*vec.z*s/m}};
1888 
1889  SECTION( "correctness" ) {
1890 
1891  int target = GENERATE( range(0,NUM_QUBITS) );
1892 
1893  SECTION( "state-vector ") {
1894 
1895  rotateAroundAxis(quregVec, target, param, vec);
1896  applyReferenceOp(refVec, target, op);
1897  REQUIRE( areEqual(quregVec, refVec) );
1898  }
1899  SECTION( "density-matrix" ) {
1900 
1901  rotateAroundAxis(quregMatr, target, param, vec);
1902  applyReferenceOp(refMatr, target, op);
1903  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1904  }
1905  }
1906  SECTION( "input validation" ) {
1907 
1908  SECTION( "qubit indices" ) {
1909 
1910  int target = GENERATE( -1, NUM_QUBITS );
1911  REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), Contains("Invalid target") );
1912  }
1913  SECTION( "zero rotation axis" ) {
1914 
1915  int target = 0;
1916  vec = {.x=0, .y=0, .z=0};
1917  REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), Contains("Invalid axis") && Contains("zero") );
1918  }
1919  }
1920  CLEANUP_TEST( quregVec, quregMatr );
1921 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomReal(), NUM_QUBITS, PREPARE_TEST, qreal, rotateAroundAxis(), Vector::x, Vector::y, and Vector::z.

◆ TEST_CASE() [93/106]

TEST_CASE ( "rotateX"  ,
""  [unitaries] 
)
See also
rotateX
Author
Tyson Jones

Definition at line 1929 of file test_unitaries.cpp.

1929  {
1930 
1931  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1932  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1933  QMatrix op{{cos(param/2), -1i*sin(param/2)}, {-1i*sin(param/2), cos(param/2)}};
1934 
1935  SECTION( "correctness" ) {
1936 
1937  int target = GENERATE( range(0,NUM_QUBITS) );
1938 
1939  SECTION( "state-vector ") {
1940 
1941  rotateX(quregVec, target, param);
1942  applyReferenceOp(refVec, target, op);
1943  REQUIRE( areEqual(quregVec, refVec) );
1944  }
1945  SECTION( "density-matrix" ) {
1946 
1947  rotateX(quregMatr, target, param);
1948  applyReferenceOp(refMatr, target, op);
1949  REQUIRE( areEqual(quregMatr, refMatr) );
1950  }
1951  }
1952  SECTION( "input validation" ) {
1953 
1954  SECTION( "qubit indices" ) {
1955 
1956  int target = GENERATE( -1, NUM_QUBITS );
1957  REQUIRE_THROWS_WITH( rotateX(quregVec, target, param), Contains("Invalid target") );
1958  }
1959  }
1960  CLEANUP_TEST( quregVec, quregMatr );
1961 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomReal(), NUM_QUBITS, PREPARE_TEST, qreal, and rotateX().

◆ TEST_CASE() [94/106]

TEST_CASE ( "rotateY"  ,
""  [unitaries] 
)
See also
rotateY
Author
Tyson Jones

Definition at line 1969 of file test_unitaries.cpp.

1969  {
1970 
1971  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1972  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1973  QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
1974 
1975  SECTION( "correctness" ) {
1976 
1977  int target = GENERATE( range(0,NUM_QUBITS) );
1978 
1979  SECTION( "state-vector ") {
1980 
1981  rotateY(quregVec, target, param);
1982  applyReferenceOp(refVec, target, op);
1983  REQUIRE( areEqual(quregVec, refVec) );
1984  }
1985  SECTION( "density-matrix" ) {
1986 
1987  rotateY(quregMatr, target, param);
1988  applyReferenceOp(refMatr, target, op);
1989  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1990  }
1991  }
1992  SECTION( "input validation" ) {
1993 
1994  SECTION( "qubit indices" ) {
1995 
1996  int target = GENERATE( -1, NUM_QUBITS );
1997  REQUIRE_THROWS_WITH( rotateY(quregVec, target, param), Contains("Invalid target") );
1998  }
1999  }
2000  CLEANUP_TEST( quregVec, quregMatr );
2001 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomReal(), NUM_QUBITS, PREPARE_TEST, qreal, and rotateY().

◆ TEST_CASE() [95/106]

TEST_CASE ( "rotateZ"  ,
""  [unitaries] 
)
See also
rotateZ
Author
Tyson Jones

Definition at line 2009 of file test_unitaries.cpp.

2009  {
2010 
2011  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2012  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2013  QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
2014 
2015  SECTION( "correctness" ) {
2016 
2017  int target = GENERATE( range(0,NUM_QUBITS) );
2018 
2019  SECTION( "state-vector ") {
2020 
2021  rotateZ(quregVec, target, param);
2022  applyReferenceOp(refVec, target, op);
2023  REQUIRE( areEqual(quregVec, refVec) );
2024  }
2025  SECTION( "density-matrix" ) {
2026 
2027  rotateZ(quregMatr, target, param);
2028  applyReferenceOp(refMatr, target, op);
2029  REQUIRE( areEqual(quregMatr, refMatr) );
2030  }
2031  }
2032  SECTION( "input validation" ) {
2033 
2034  SECTION( "qubit indices" ) {
2035 
2036  int target = GENERATE( -1, NUM_QUBITS );
2037  REQUIRE_THROWS_WITH( rotateZ(quregVec, target, param), Contains("Invalid target") );
2038  }
2039  }
2040  CLEANUP_TEST( quregVec, quregMatr );
2041 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getRandomReal(), NUM_QUBITS, PREPARE_TEST, qreal, and rotateZ().

◆ TEST_CASE() [96/106]

TEST_CASE ( "setAmps"  ,
""  [state_initialisations] 
)
See also
setAmps
Author
Tyson Jones

Definition at line 368 of file test_state_initialisations.cpp.

368  {
369 
371 
372  int maxInd = vec.numAmpsTotal;
373  qreal reals[maxInd];
374  qreal imags[maxInd];
375 
376  SECTION( "correctness" ) {
377 
378  SECTION( "state-vector" ) {
379 
380  // all valid number of amplitudes and offsets
381  int startInd = GENERATE_COPY( range(0,maxInd) );
382  int numAmps = GENERATE_COPY( range(0,1+maxInd-startInd) ); // upper-bound allows all amps specified
383 
384  // generate random amplitudes
385  for (int i=0; i<numAmps; i++) {
386  reals[i] = getRandomReal(-5,5);
387  imags[i] = getRandomReal(-5,5);
388  }
389 
390  // check both specified and un-specified amplitudes are correctly handled
391  initDebugState(vec);
392  QVector vecRef = toQVector(vec);
393 
394  setAmps(vec, startInd, reals, imags, numAmps);
395  for (int i=0; i<numAmps; i++)
396  vecRef[startInd+i] = reals[i] + 1i*(imags[i]);
397 
398  REQUIRE( areEqual(vec, vecRef) );
399  }
400  }
401  SECTION( "input validation" ) {
402 
403  SECTION( "start index" ) {
404 
405  int startInd = GENERATE_COPY( -1, maxInd );
406  int numAmps = 0;
407  REQUIRE_THROWS_WITH( setAmps(vec, startInd, reals, imags, numAmps), Contains("Invalid amplitude index") );
408  }
409 
410  SECTION( "number of amplitudes" ) {
411 
412  // independent
413  int startInd = 0;
414  int numAmps = GENERATE_COPY( -1, maxInd+1 );
415  REQUIRE_THROWS_WITH( setAmps(vec, startInd, reals, imags, numAmps), Contains("Invalid number of amplitudes") );
416 
417  // invalid considering start-index
418  startInd = maxInd - 1;
419  numAmps = 2;
420  REQUIRE_THROWS_WITH( setAmps(vec, startInd, reals, imags, numAmps), Contains("More amplitudes given than exist") );
421  }
422  SECTION( "density-matrix" ) {
423 
425  REQUIRE_THROWS_WITH( setAmps(mat, 0, reals, imags, 0), Contains("valid only for state-vectors") );
426  destroyQureg(mat, QUEST_ENV);
427  }
428  }
429  destroyQureg(vec, QUEST_ENV);
430 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getRandomReal(), initDebugState(), NUM_QUBITS, Qureg::numAmpsTotal, qreal, QUEST_ENV, setAmps(), and toQVector().

◆ TEST_CASE() [97/106]

TEST_CASE ( "setDiagonalOpElems"  ,
""  [data_structures] 
)
See also
setDiagonalOpElems
Author
Tyson Jones

Definition at line 721 of file test_data_structures.cpp.

721  {
722 
723  // must be at least one amplitude per node
724  int minNumQb = calcLog2(QUEST_ENV.numRanks);
725  if (minNumQb == 0)
726  minNumQb = 1;
727 
728  // try 10 valid number of qubits (even for validation)
729  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
731 
732  SECTION( "correctness" ) {
733 
734  // make entire array on every node
735  long long int len = (1LL << numQb);
736  qreal reals[len];
737  qreal imags[len];
738  long long int n;
739  for (n=0; n<len; n++) {
740  reals[n] = (qreal) n;
741  imags[n] = (qreal) -2*n; // (n - 2n i)
742  }
743 
744  // set one value at a time (only relevant nodes will update)
745  for (n=0; n<len; n++)
746  setDiagonalOpElems(op, n, &reals[n], &imags[n], 1);
747 
748  // check op.real and op.imag updated correctly
749  REQUIRE( areEqual(toQVector(op), reals, imags) );
750 
751  // no check that GPU values updated (occurs in initDiagonalOp)
752  }
753  SECTION( "input validation" ) {
754 
755  long long int maxInd = (1LL << numQb);
756  qreal *reals;
757  qreal *imags;
758 
759  SECTION( "start index" ) {
760 
761  int startInd = GENERATE_COPY( -1, maxInd );
762  int numAmps = 1;
763  REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("Invalid element index") );
764  }
765 
766  SECTION( "number of amplitudes" ) {
767 
768  // independent
769  int startInd = 0;
770  int numAmps = GENERATE_COPY( -1, maxInd+1 );
771  REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("Invalid number of elements") );
772 
773  // invalid considering start-index
774  startInd = maxInd - 1;
775  numAmps = 2;
776  REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("More elements given than exist") );
777  }
778  }
779 
781 }

References areEqual(), calcLog2(), createDiagonalOp(), destroyDiagonalOp(), QuESTEnv::numRanks, qreal, QUEST_ENV, setDiagonalOpElems(), and toQVector().

◆ TEST_CASE() [98/106]

TEST_CASE ( "setWeightedQureg"  ,
""  [state_initialisations] 
)
See also
setWeightedQureg
Author
Tyson Jones

Definition at line 438 of file test_state_initialisations.cpp.

438  {
439 
440  SECTION( "correctness" ) {
441 
442  // repeat each test below 10 times
443  GENERATE( range(0,10) );
444 
445  /* note tolerance in areEqual increases with tests, since
446  * small differences propogate in vecC which is not re-initialised
447  */
448 
449  SECTION( "state-vector" ) {
450 
451  // make three random vectors
455  for (int j=0; j<vecA.numAmpsPerChunk; j++) {
456  vecA.stateVec.real[j] = getRandomReal(-5,5); vecA.stateVec.imag[j] = getRandomReal(-5,5);
457  vecB.stateVec.real[j] = getRandomReal(-5,5); vecB.stateVec.imag[j] = getRandomReal(-5,5);
458  vecC.stateVec.real[j] = getRandomReal(-5,5); vecC.stateVec.imag[j] = getRandomReal(-5,5);
459  }
460  copyStateToGPU(vecA); copyStateToGPU(vecB); copyStateToGPU(vecC);
461  QVector refA = toQVector(vecA);
462  QVector refB = toQVector(vecB);
463  QVector refC = toQVector(vecC);
464  QVector refOut;
465 
466  // get three random factors
467  qcomp numA = getRandomReal(-5,5) + 1i*getRandomReal(-5,5);
468  qcomp numB = getRandomReal(-5,5) + 1i*getRandomReal(-5,5);
469  qcomp numC = getRandomReal(-5,5) + 1i*getRandomReal(-5,5);
470  Complex facA = toComplex(numA);
471  Complex facB = toComplex(numB);
472  Complex facC = toComplex(numC);
473 
474  // check out-qureg is correct, when all quregs are unique...
475  setWeightedQureg(facA, vecA, facB, vecB, facC, vecC);
476  refOut = numA*refA + numB*refB + numC*refC;
477  REQUIRE( areEqual(vecC, refOut) );
478 
479  // ... and that other qureg's aren't modified
480  REQUIRE( areEqual(vecA, refA) );
481  REQUIRE( areEqual(vecB, refB) );
482 
483  // check quregOut correct, when it's also qureg2
484  refC = toQVector(vecC);
485  setWeightedQureg(facB, vecB, facC, vecC, facA, vecC);
486  refOut = numB*refB + numC*refC + numA*refC;
487  REQUIRE( areEqual(vecC, refOut, 10*REAL_EPS) );
488 
489  // ... and that the remaining qureg is not modified
490  REQUIRE( areEqual(vecB, refB) );
491 
492  // check quregOut correct, when it's also qureg1
493  refC = toQVector(vecC);
494  setWeightedQureg(facC, vecC, facB, vecB, facA, vecC);
495  refOut = numC*refC + numB*refB + numA*refC;
496  REQUIRE( areEqual(vecC, refOut, 10*REAL_EPS) );
497 
498  // ... and that the remaining qureg is not modified
499  REQUIRE( areEqual(vecB, refB) );
500 
501  // check quregOut is correct when it's both input quregs
502  refC = toQVector(vecC);
503  setWeightedQureg(facA, vecC, facB, vecC, facC, vecC);
504  refOut = numA*refC + numB*refC + numC*refC;
505  REQUIRE( areEqual(vecC, refOut, 1E3*REAL_EPS) );
506 
507  // cleanup
508  destroyQureg(vecA, QUEST_ENV);
509  destroyQureg(vecB, QUEST_ENV);
510  destroyQureg(vecC, QUEST_ENV);
511  }
512  SECTION( "density-matrix" ) {
513 
514  // make three random matrices
518  for (int j=0; j<matA.numAmpsPerChunk; j++) {
519  matA.stateVec.real[j] = getRandomReal(-5,5); matA.stateVec.imag[j] = getRandomReal(-5,5);
520  matB.stateVec.real[j] = getRandomReal(-5,5); matB.stateVec.imag[j] = getRandomReal(-5,5);
521  matC.stateVec.real[j] = getRandomReal(-5,5); matC.stateVec.imag[j] = getRandomReal(-5,5);
522  }
523  copyStateToGPU(matA); copyStateToGPU(matB); copyStateToGPU(matC);
524  QMatrix refA = toQMatrix(matA);
525  QMatrix refB = toQMatrix(matB);
526  QMatrix refC = toQMatrix(matC);
527  QMatrix refOut;
528 
529  // get three random factors
530  qcomp numA = getRandomReal(-5,5) + 1i*getRandomReal(-5,5);
531  qcomp numB = getRandomReal(-5,5) + 1i*getRandomReal(-5,5);
532  qcomp numC = getRandomReal(-5,5) + 1i*getRandomReal(-5,5);
533  Complex facA = toComplex(numA);
534  Complex facB = toComplex(numB);
535  Complex facC = toComplex(numC);
536 
537  // check out-qureg is correct, when all quregs are unique...
538  setWeightedQureg(facA, matA, facB, matB, facC, matC);
539  refOut = numA*refA + numB*refB + numC*refC;
540  REQUIRE( areEqual(matC, refOut) );
541 
542  // ... and that other qureg's aren't modified
543  REQUIRE( areEqual(matA, refA) );
544  REQUIRE( areEqual(matB, refB) );
545 
546  // check quregOut correct, when it's also qureg2
547  refC = toQMatrix(matC);
548  setWeightedQureg(facB, matB, facC, matC, facA, matC);
549  refOut = numB*refB + numC*refC + numA*refC;
550  REQUIRE( areEqual(matC, refOut, 10*REAL_EPS) );
551 
552  // ... and that the remaining qureg is not modified
553  REQUIRE( areEqual(matB, refB) );
554 
555  // check quregOut correct, when it's also qureg1
556  refC = toQMatrix(matC);
557  setWeightedQureg(facC, matC, facB, matB, facA, matC);
558  refOut = numC*refC + numB*refB + numA*refC;
559  REQUIRE( areEqual(matC, refOut, 1E2*REAL_EPS) );
560 
561  // ... and that the remaining qureg is not modified
562  REQUIRE( areEqual(matB, refB) );
563 
564  // check quregOut is correct when it's both input quregs
565  refC = toQMatrix(matC);
566  setWeightedQureg(facA, matC, facB, matC, facC, matC);
567  refOut = numA*refC + numB*refC + numC*refC;
568  REQUIRE( areEqual(matC, refOut, 1E3*REAL_EPS) );
569 
570  // cleanup
571  destroyQureg(matA, QUEST_ENV);
572  destroyQureg(matB, QUEST_ENV);
573  destroyQureg(matC, QUEST_ENV);
574  }
575  }
576  SECTION( "input validation" ) {
577 
578  SECTION( "qureg types" ) {
579 
582  Complex f = {.real=0, .imag=0};
583 
584  // two state-vecs, one density-matrix
585  REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, vec, f, vec), Contains("state-vectors or") && Contains("density matrices") );
586  REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, mat, f, vec), Contains("state-vectors or") && Contains("density matrices") );
587  REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, vec, f, mat), Contains("state-vectors or") && Contains("density matrices") );
588 
589  // one state-vec, two density-matrices
590  REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, mat, f, mat), Contains("state-vectors or") && Contains("density matrices") );
591  REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, vec, f, mat), Contains("state-vectors or") && Contains("density matrices") );
592  REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, mat, f, vec), Contains("state-vectors or") && Contains("density matrices") );
593 
594  destroyQureg(vec, QUEST_ENV);
595  destroyQureg(mat, QUEST_ENV);
596  }
597  SECTION( "qureg dimensions" ) {
598 
600  Qureg vecB = createQureg(NUM_QUBITS + 1, QUEST_ENV);
603  Complex f = {.real=0, .imag=0};
604 
605  // state-vecs
606  REQUIRE_THROWS_WITH( setWeightedQureg(f, vecA, f, vecB, f, vecB), Contains("Dimensions") );
607  REQUIRE_THROWS_WITH( setWeightedQureg(f, vecB, f, vecA, f, vecB), Contains("Dimensions") );
608  REQUIRE_THROWS_WITH( setWeightedQureg(f, vecB, f, vecB, f, vecA), Contains("Dimensions") );
609 
610  // density-matrices
611  REQUIRE_THROWS_WITH( setWeightedQureg(f, matA, f, matB, f, matB), Contains("Dimensions") );
612  REQUIRE_THROWS_WITH( setWeightedQureg(f, matB, f, matA, f, matB), Contains("Dimensions") );
613  REQUIRE_THROWS_WITH( setWeightedQureg(f, matB, f, matB, f, matA), Contains("Dimensions") );
614 
615  destroyQureg(vecA, QUEST_ENV);
616  destroyQureg(vecB, QUEST_ENV);
617  destroyQureg(matA, QUEST_ENV);
618  destroyQureg(matB, QUEST_ENV);
619  }
620  }
621 }

References areEqual(), copyStateToGPU(), createDensityQureg(), createQureg(), destroyQureg(), getRandomReal(), NUM_QUBITS, Qureg::numAmpsPerChunk, qcomp, QUEST_ENV, Complex::real, setWeightedQureg(), Qureg::stateVec, toComplex, toQMatrix(), and toQVector().

◆ TEST_CASE() [99/106]

TEST_CASE ( "sGate"  ,
""  [unitaries] 
)
See also
sGate
Author
Tyson Jones

Definition at line 2049 of file test_unitaries.cpp.

2049  {
2050 
2051  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2052  QMatrix op{{1,0},{0,1i}};
2053 
2054  SECTION( "correctness" ) {
2055 
2056  int target = GENERATE( range(0,NUM_QUBITS) );
2057 
2058  SECTION( "state-vector ") {
2059 
2060  sGate(quregVec, target);
2061  applyReferenceOp(refVec, target, op);
2062  REQUIRE( areEqual(quregVec, refVec) );
2063  }
2064  SECTION( "density-matrix" ) {
2065 
2066  sGate(quregMatr, target);
2067  applyReferenceOp(refMatr, target, op);
2068  REQUIRE( areEqual(quregMatr, refMatr) );
2069  }
2070  }
2071  SECTION( "input validation" ) {
2072 
2073  SECTION( "qubit indices" ) {
2074 
2075  int target = GENERATE( -1, NUM_QUBITS );
2076  REQUIRE_THROWS_WITH( sGate(quregVec, target), Contains("Invalid target") );
2077  }
2078  }
2079  CLEANUP_TEST( quregVec, quregMatr );
2080 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, PREPARE_TEST, and sGate().

◆ TEST_CASE() [100/106]

TEST_CASE ( "sqrtSwapGate"  ,
""  [unitaries] 
)
See also
sqrtSwapGate
Author
Tyson Jones

Definition at line 2088 of file test_unitaries.cpp.

2088  {
2089 
2090  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2091  qcomp a = (1. + 1i)/2.;
2092  qcomp b = (1. - 1i)/2.;
2093  QMatrix op{{1,0,0,0},{0,a,b,0},{0,b,a,0},{0,0,0,1}};
2094 
2095  SECTION( "correctness" ) {
2096 
2097  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2098  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2099  int targs[] = {targ1, targ2};
2100 
2101  SECTION( "state-vector" ) {
2102 
2103  sqrtSwapGate(quregVec, targ1, targ2);
2104  applyReferenceOp(refVec, targs, 2, op);
2105  REQUIRE( areEqual(quregVec, refVec) );
2106  }
2107  SECTION( "density-matrix" ) {
2108 
2109  sqrtSwapGate(quregMatr, targ1, targ2);
2110  applyReferenceOp(refMatr, targs, 2, op);
2111  REQUIRE( areEqual(quregMatr, refMatr) );
2112  }
2113  }
2114  SECTION( "input validation" ) {
2115 
2116  SECTION( "qubit indices" ) {
2117 
2118  int targ1 = GENERATE( -1, NUM_QUBITS );
2119  int targ2 = 0;
2120  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ1, targ2), Contains("Invalid target") );
2121  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ2, targ1), Contains("Invalid target") );
2122  }
2123  SECTION( "repetition of targets" ) {
2124 
2125  int qb = 0;
2126  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, qb, qb), Contains("target") && Contains("unique") );
2127  }
2128  }
2129  CLEANUP_TEST( quregVec, quregMatr );
2130 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, PREPARE_TEST, qcomp, and sqrtSwapGate().

◆ TEST_CASE() [101/106]

TEST_CASE ( "swapGate"  ,
""  [unitaries] 
)
See also
swapGate
Author
Tyson Jones

Definition at line 2138 of file test_unitaries.cpp.

2138  {
2139 
2140  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2141  QMatrix op{{1,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1}};
2142 
2143  SECTION( "correctness" ) {
2144 
2145  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2146  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2147  int targs[] = {targ1, targ2};
2148 
2149  SECTION( "state-vector" ) {
2150 
2151  swapGate(quregVec, targ1, targ2);
2152  applyReferenceOp(refVec, targs, 2, op);
2153  REQUIRE( areEqual(quregVec, refVec) );
2154  }
2155  SECTION( "density-matrix" ) {
2156 
2157  swapGate(quregMatr, targ1, targ2);
2158  applyReferenceOp(refMatr, targs, 2, op);
2159  REQUIRE( areEqual(quregMatr, refMatr) );
2160  }
2161  }
2162  SECTION( "input validation" ) {
2163 
2164  SECTION( "qubit indices" ) {
2165 
2166  int targ1 = GENERATE( -1, NUM_QUBITS );
2167  int targ2 = 0;
2168  REQUIRE_THROWS_WITH( swapGate(quregVec, targ1, targ2), Contains("Invalid target") );
2169  REQUIRE_THROWS_WITH( swapGate(quregVec, targ2, targ1), Contains("Invalid target") );
2170  }
2171  SECTION( "repetition of targets" ) {
2172 
2173  int qb = 0;
2174  REQUIRE_THROWS_WITH( swapGate(quregVec, qb, qb), Contains("target") && Contains("unique") );
2175  }
2176  }
2177  CLEANUP_TEST( quregVec, quregMatr );
2178 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, PREPARE_TEST, and swapGate().

◆ TEST_CASE() [102/106]

TEST_CASE ( "syncDiagonalOp"  ,
""  [data_structures] 
)
See also
syncDiagonalOp
Author
Tyson Jones

Definition at line 789 of file test_data_structures.cpp.

789  {
790 
791  // must be at least one amplitude per node
792  int minNumQb = calcLog2(QUEST_ENV.numRanks);
793  if (minNumQb == 0)
794  minNumQb = 1;
795 
796  SECTION( "correctness" ) {
797 
798  // try 10 valid number of qubits
799  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
801 
802  // check that changes get sync'd to the GPU...
803  long long int n;
804  for (n=0; n<op.numElemsPerChunk; n++) {
805  op.real[n] = (qreal) n;
806  op.imag[n] = (qreal) -2*n; // (n - 2n i)
807  }
808  syncDiagonalOp(op);
809 
810  // via if it modifies an all-unity state-vec correctly
811  Qureg qureg = createQureg(numQb, QUEST_ENV);
812  for (long long int i=0; i<qureg.numAmpsPerChunk; i++) {
813  qureg.stateVec.real[i] = 1;
814  qureg.stateVec.imag[i] = 1;
815  }
816  copyStateToGPU(qureg);
817 
818  // (n - 2n i) * (1 + 1i) = 3n - n*i
819  applyDiagonalOp(qureg, op);
820  copyStateFromGPU(qureg);
821  for (n=0; n<qureg.numAmpsPerChunk; n++) {
822  REQUIRE( qureg.stateVec.real[n] == 3*n );
823  REQUIRE( qureg.stateVec.imag[n] == -n );
824  }
825 
826  destroyQureg(qureg, QUEST_ENV);
828  }
829 }

References applyDiagonalOp(), calcLog2(), copyStateFromGPU(), copyStateToGPU(), createDiagonalOp(), createQureg(), destroyDiagonalOp(), destroyQureg(), DiagonalOp::imag, Qureg::numAmpsPerChunk, DiagonalOp::numElemsPerChunk, QuESTEnv::numRanks, qreal, QUEST_ENV, DiagonalOp::real, Qureg::stateVec, and syncDiagonalOp().

◆ TEST_CASE() [103/106]

TEST_CASE ( "tGate"  ,
""  [unitaries] 
)
See also
tGate
Author
Tyson Jones

Definition at line 2186 of file test_unitaries.cpp.

2186  {
2187 
2188  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2189  QMatrix op{{1,0},{0,expI(M_PI/4.)}};
2190 
2191  SECTION( "correctness" ) {
2192 
2193  int target = GENERATE( range(0,NUM_QUBITS) );
2194 
2195  SECTION( "state-vector ") {
2196 
2197  tGate(quregVec, target);
2198  applyReferenceOp(refVec, target, op);
2199  REQUIRE( areEqual(quregVec, refVec) );
2200  }
2201  SECTION( "density-matrix" ) {
2202 
2203  tGate(quregMatr, target);
2204  applyReferenceOp(refMatr, target, op);
2205  REQUIRE( areEqual(quregMatr, refMatr) );
2206  }
2207  }
2208  SECTION( "input validation" ) {
2209 
2210  SECTION( "qubit indices" ) {
2211 
2212  int target = GENERATE( -1, NUM_QUBITS );
2213  REQUIRE_THROWS_WITH( tGate(quregVec, target), Contains("Invalid target") );
2214  }
2215  }
2216  CLEANUP_TEST( quregVec, quregMatr );
2217 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), NUM_QUBITS, PREPARE_TEST, and tGate().

◆ TEST_CASE() [104/106]

TEST_CASE ( "toComplex"  ,
""  [data_structures] 
)
See also
toComplex
Author
Tyson Jones

Definition at line 42 of file test_data_structures.cpp.

42  {
43 
44  qcomp a = .5 - .2i;
45  Complex b = toComplex(a);
46 
47  REQUIRE( real(a) == b.real );
48  REQUIRE( imag(a) == b.imag );
49 }

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

◆ TEST_CASE() [105/106]

TEST_CASE ( "twoQubitUnitary"  ,
""  [unitaries] 
)
See also
twoQubitUnitary
Author
Tyson Jones

Definition at line 2225 of file test_unitaries.cpp.

2225  {
2226 
2227  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2228 
2229  // in distributed mode, each node must be able to fit all amps modified by unitary
2230  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
2231 
2232  // every test will use a unique random matrix
2233  QMatrix op = getRandomUnitary(2);
2234  ComplexMatrix4 matr = toComplexMatrix4(op);
2235 
2236  SECTION( "correctness" ) {
2237 
2238  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2239  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2240  int targs[] = {targ1, targ2};
2241 
2242  SECTION( "state-vector" ) {
2243 
2244  twoQubitUnitary(quregVec, targ1, targ2, matr);
2245  applyReferenceOp(refVec, targs, 2, op);
2246  REQUIRE( areEqual(quregVec, refVec) );
2247  }
2248  SECTION( "density-matrix" ) {
2249 
2250  twoQubitUnitary(quregMatr, targ1, targ2, matr);
2251  applyReferenceOp(refMatr, targs, 2, op);
2252  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2253  }
2254  }
2255  SECTION( "input validation" ) {
2256 
2257  SECTION( "qubit indices" ) {
2258 
2259  int targ1 = GENERATE( -1, NUM_QUBITS );
2260  int targ2 = 0;
2261  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ1, targ2, matr), Contains("Invalid target") );
2262  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ2, targ1, matr), Contains("Invalid target") );
2263  }
2264  SECTION( "repetition of targets" ) {
2265 
2266  int qb = 0;
2267  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, qb, qb, matr), Contains("target") && Contains("unique") );
2268  }
2269  SECTION( "unitarity" ) {
2270 
2271  matr.real[0][0] = 0; // break matr unitarity
2272  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), Contains("unitary") );
2273  }
2274  SECTION( "unitary fits in node" ) {
2275 
2276  // pretend we have a very limited distributed memory
2277  quregVec.numAmpsPerChunk = 1;
2278  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), Contains("targets too many qubits"));
2279  }
2280  }
2281  CLEANUP_TEST( quregVec, quregMatr );
2282 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix4::real, toComplexMatrix4(), and twoQubitUnitary().

◆ TEST_CASE() [106/106]

TEST_CASE ( "unitary"  ,
""  [unitaries] 
)
See also
unitary
Author
Tyson Jones

Definition at line 2290 of file test_unitaries.cpp.

2290  {
2291 
2292  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2293 
2294  // every test will use a unique random matrix
2295  QMatrix op = getRandomUnitary(1);
2296  ComplexMatrix2 matr = toComplexMatrix2(op);
2297 
2298  SECTION( "correctness" ) {
2299 
2300  int target = GENERATE( range(0,NUM_QUBITS) );
2301 
2302  SECTION( "state-vector" ) {
2303 
2304  unitary(quregVec, target, matr);
2305  applyReferenceOp(refVec, target, op);
2306  REQUIRE( areEqual(quregVec, refVec) );
2307  }
2308  SECTION( "density-matrix" ) {
2309 
2310  unitary(quregMatr, target, matr);
2311  applyReferenceOp(refMatr, target, op);
2312  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2313  }
2314  }
2315  SECTION( "input validation" ) {
2316 
2317  SECTION( "qubit indices" ) {
2318 
2319  int target = GENERATE( -1, NUM_QUBITS );
2320  REQUIRE_THROWS_WITH( unitary(quregVec, target, matr), Contains("Invalid target") );
2321  }
2322  SECTION( "unitarity" ) {
2323 
2324  matr.real[0][0] = 0; // break matr unitarity
2325  REQUIRE_THROWS_WITH( unitary(quregVec, 0, matr), Contains("unitary") );
2326  }
2327  }
2328  CLEANUP_TEST( quregVec, quregMatr );
2329 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix2::real, toComplexMatrix2(), and unitary().

void controlledRotateZ(Qureg qureg, int controlQubit, int targetQubit, qreal angle)
Applies a controlled rotation by a given angle around the Z-axis of the Bloch-sphere.
Definition: QuEST.c:245
void mixDephasing(Qureg qureg, int targetQubit, qreal prob)
Mixes a density matrix qureg to induce single-qubit dephasing noise.
Definition: QuEST.c:1001
qreal getProbAmp(Qureg qureg, long long int index)
Get the probability of a state-vector at an index in the full state vector.
Definition: QuEST.c:692
void initBlankState(Qureg qureg)
Initialises a qureg to have all-zero-amplitudes.
Definition: QuEST.c:119
Represents a 3-vector of real numbers.
Definition: QuEST.h:148
pauliOpType
Codes for specifying Pauli operators.
Definition: QuEST.h:96
QMatrix getFullOperatorMatrix(int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op, int numQubits)
Takes a 2^numTargs-by-2^numTargs matrix op and a returns a 2^numQubits-by-2^numQubits matrix where op...
Definition: utilities.cpp:293
void applyMultiControlledMatrixN(Qureg qureg, int *ctrls, int numCtrls, int *targs, int numTargs, ComplexMatrixN u)
Apply a general N-by-N matrix, which may be non-unitary, with additional controlled qubits.
Definition: QuEST.c:874
void twoQubitUnitary(Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general two-qubit unitary (including a global phase factor).
Definition: QuEST.c:257
void controlledRotateX(Qureg qureg, int controlQubit, int targetQubit, qreal angle)
Applies a controlled rotation by a given angle around the X-axis of the Bloch-sphere.
Definition: QuEST.c:221
void copyStateFromGPU(Qureg qureg)
In GPU mode, this copies the state-vector (or density matrix) from GPU memory (qureg....
Definition: QuEST_cpu.c:39
void initPauliHamil(PauliHamil hamil, qreal *coeffs, enum pauliOpType *codes)
Initialise a PauliHamil instance with the given term coefficients and Pauli codes (one for every qubi...
Definition: QuEST.c:1253
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
qreal real[4][4]
Definition: QuEST.h:127
#define fromComplex(comp)
void initPureState(Qureg qureg, Qureg pure)
Initialise a set of qubits, which can be a state vector or density matrix, to a given pure state.
Definition: QuEST.c:145
#define CLEANUP_TEST(quregVec, quregMatr)
Destroys the data structures made by PREPARE_TEST.
@ PAULI_Z
Definition: QuEST.h:96
void rotateAroundAxis(Qureg qureg, int rotQubit, qreal angle, Vector axis)
Rotate a single qubit by a given angle around a given Vector on the Bloch-sphere.
Definition: QuEST.c:575
void mixDepolarising(Qureg qureg, int targetQubit, qreal prob)
Mixes a density matrix qureg to induce single-qubit homogeneous depolarising noise.
Definition: QuEST.c:1023
int rank
Definition: QuEST.h:244
qreal calcTotalProb(Qureg qureg)
A debugging function which calculates the probability of the qubits in qureg being in any state,...
Definition: QuEST.c:903
void mixDamping(Qureg qureg, int targetQubit, qreal prob)
Mixes a density matrix qureg to induce single-qubit amplitude damping (decay to 0 state).
Definition: QuEST.c:1034
void destroyComplexMatrixN(ComplexMatrixN m)
Destroy a ComplexMatrixN instance created with createComplexMatrixN()
Definition: QuEST.c:1120
int numChunks
The number of nodes between which the elements of this operator are split.
Definition: QuEST.h:185
@ PAULI_I
Definition: QuEST.h:96
Complex getDensityAmp(Qureg qureg, long long int row, long long int col)
Get an amplitude from a density matrix at a given row and column.
Definition: QuEST.c:709
int getRandomInt(int min, int max)
Returns a random integer between min (inclusive) and max (exclusive), from the uniform distribution.
Definition: utilities.cpp:481
std::vector< QMatrix > getRandomKrausMap(int numQb, int numOps)
Returns a random Kraus map of #numOps 2^numQb-by-2^numQb operators, from an undisclosed distribution.
Definition: utilities.cpp:533
ComplexMatrixN createComplexMatrixN(int numQubits)
Create (dynamically) a square complex matrix which can be passed to the multi-qubit general unitary f...
Definition: QuEST.c:1099
qreal getImagAmp(Qureg qureg, long long int index)
Get the imaginary component of the complex probability amplitude at an index in the state vector.
Definition: QuEST.c:685
void controlledRotateAroundAxis(Qureg qureg, int controlQubit, int targetQubit, qreal angle, Vector axis)
Applies a controlled rotation by a given angle around a given vector on the Bloch-sphere.
Definition: QuEST.c:588
void mixKrausMap(Qureg qureg, int target, ComplexMatrix2 *ops, int numOps)
Apply a general single-qubit Kraus map to a density matrix, as specified by at most four Kraus operat...
Definition: QuEST.c:1065
void syncDiagonalOp(DiagonalOp op)
Copy the elements in DiagonalOp op.real and op.imag to the persisent GPU memory.
Definition: QuEST.c:1280
void destroyDiagonalOp(DiagonalOp op, QuESTEnv env)
Destroys a DiagonalOp created with createDiagonalOp(), freeing its memory.
Definition: QuEST.c:1273
qreal z
Definition: QuEST.h:150
void multiControlledTwoQubitUnitary(Qureg qureg, int *controlQubits, int numControlQubits, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general multi-controlled two-qubit unitary (including a global phase factor).
Definition: QuEST.c:283
#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:726
#define CLEANUP_TEST(quregVec, quregMatr)
Destroys the data structures made by PREPARE_TEST.
qreal calcPurity(Qureg qureg)
Calculates the purity of a density matrix, by the trace of the density matrix squared.
Definition: QuEST.c:936
qreal calcProbOfOutcome(Qureg qureg, int measureQubit, int outcome)
Gives the probability of a specified qubit being measured in the given outcome (0 or 1).
Definition: QuEST.c:926
int measure(Qureg qureg, int measureQubit)
Measures a single qubit, collapsing it randomly to 0 or 1.
Definition: QuEST.c:758
QMatrix getRandomUnitary(int numQb)
Returns a uniformly random (under Haar) 2^numQb-by-2^numQb unitary matrix.
Definition: utilities.cpp:485
qreal calcFidelity(Qureg qureg, Qureg pureState)
Calculates the fidelity of qureg (a statevector or density matrix) against a reference pure state (ne...
Definition: QuEST.c:942
qreal getRandomReal(qreal min, qreal max)
Returns a random real between min (inclusive) and max (exclusive), from the uniform distribution.
Definition: utilities.cpp:410
void unitary(Qureg qureg, int targetQubit, ComplexMatrix2 u)
Apply a general single-qubit unitary (including a global phase factor).
Definition: QuEST.c:349
int chunkId
The position of the chunk of the operator held by this process in the full operator.
Definition: QuEST.h:187
QMatrix getKetBra(QVector ket, QVector bra)
Returns the matrix |ket><bra|, with ith-jth element ket(i) conj(bra(j)), since |ket><bra| = sum_i a_i...
Definition: utilities.cpp:159
void mixTwoQubitDepolarising(Qureg qureg, int qubit1, int qubit2, qreal prob)
Mixes a density matrix qureg to induce two-qubit homogeneous depolarising noise.
Definition: QuEST.c:1042
Complex calcExpecDiagonalOp(Qureg qureg, DiagonalOp op)
Computes the expected value of the diagonal operator op for state qureg.
Definition: QuEST.c:979
void sGate(Qureg qureg, int targetQubit)
Apply the single-qubit S gate.
Definition: QuEST.c:466
void cloneQureg(Qureg targetQureg, Qureg copyQureg)
Set targetQureg to be a clone of copyQureg.
Definition: QuEST.c:165
Represents a 4x4 matrix of complex numbers.
Definition: QuEST.h:125
void rotateY(Qureg qureg, int targetQubit, qreal angle)
Rotate a single qubit by a given angle around the Y-axis of the Bloch-sphere.
Definition: QuEST.c:199
void applyPauliHamil(Qureg inQureg, PauliHamil hamil, Qureg outQureg)
Modifies outQureg to be the result of applying PauliHamil (a Hermitian but not necessarily unitary op...
Definition: QuEST.c:819
Information about the environment the program is running in.
Definition: QuEST.h:242
PauliHamil createPauliHamilFromFile(char *fn)
Create a PauliHamil instance, a real-weighted sum of products of Pauli operators, populated with the ...
Definition: QuEST.c:1169
void multiControlledPhaseShift(Qureg qureg, int *controlQubits, int numControlQubits, qreal angle)
Introduce a phase factor on state of the passed qubits.
Definition: QuEST.c:511
void setDiagonalOpElems(DiagonalOp op, long long int startInd, qreal *real, qreal *imag, long long int numElems)
Modifies a subset (starting at index startInd) of the elements in DiagonalOp op with the given elemen...
Definition: QuEST.c:1292
Represents a general 2^N by 2^N matrix of complex numbers.
Definition: QuEST.h:136
#define qreal
void multiRotatePauli(Qureg qureg, int *targetQubits, enum pauliOpType *targetPaulis, int numTargets, qreal angle)
Apply a multi-qubit multi-Pauli rotation on a selected number of qubits.
Definition: QuEST.c:642
QMatrix toQMatrix(ComplexMatrix2 src)
Returns a copy of the given 2-by-2 matrix.
Definition: utilities.cpp:869
void toQureg(Qureg qureg, QVector vec)
Initialises the state-vector qureg to have the same amplitudes as vec.
Definition: utilities.cpp:1026
void setAmps(Qureg qureg, long long int startInd, qreal *reals, qreal *imags, long long int numAmps)
Overwrites a subset of the amplitudes in qureg, with those passed in reals and imags.
Definition: QuEST.c:781
unsigned int calcLog2(long unsigned int num)
returns log2 of numbers which must be gauranteed to be 2^n
void multiControlledPhaseFlip(Qureg qureg, int *controlQubits, int numControlQubits)
Apply the multiple-qubit controlled phase flip gate, also known as the multiple-qubit controlled paul...
Definition: QuEST.c:561
void multiQubitUnitary(Qureg qureg, int *targs, int numTargs, ComplexMatrixN u)
Apply a general multi-qubit unitary (including a global phase factor) with any number of target qubit...
Definition: QuEST.c:297
#define PREPARE_TEST(quregVec, quregMatr, refVec, refMatr)
Prepares the needed data structures for unit testing unitaries.
@ PAULI_X
Definition: QuEST.h:96
Complex getAmp(Qureg qureg, long long int index)
Get the complex amplitude at a given index in the state vector.
Definition: QuEST.c:699
void controlledPauliY(Qureg qureg, int controlQubit, int targetQubit)
Apply the controlled pauliY (single control, single target) gate, also known as the c-Y and c-sigma-Y...
Definition: QuEST.c:537
QMatrix getExponentialOfPauliMatrix(qreal angle, QMatrix a)
Returns the matrix exponential of a kronecker product of pauli matrices (or of any involutory matrice...
Definition: utilities.cpp:205
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:745
int numQubitsInStateVec
Number of qubits in the state-vector - this is double the number represented for mixed states.
Definition: QuEST.h:210
qreal calcExpecPauliHamil(Qureg qureg, PauliHamil hamil, Qureg workspace)
Computes the expected value of qureg under Hermitian operator hamil.
Definition: QuEST.c:970
void multiControlledMultiQubitUnitary(Qureg qureg, int *ctrls, int numCtrls, int *targs, int numTargs, ComplexMatrixN u)
Apply a general multi-controlled multi-qubit unitary (including a global phase factor).
Definition: QuEST.c:331
void setRandomPauliSum(qreal *coeffs, pauliOpType *codes, int numQubits, int numTerms)
Populates the coeffs array with random qreals in (-5, 5), and populates codes with random Pauli codes...
Definition: utilities.cpp:1054
void toComplexMatrixN(QMatrix qm, ComplexMatrixN cm)
Initialises cm with the values of qm.
Definition: utilities.cpp:858
void rotateX(Qureg qureg, int targetQubit, qreal angle)
Rotate a single qubit by a given angle around the X-axis of the Bloch-sphere.
Definition: QuEST.c:188
void setWeightedQureg(Complex fac1, Qureg qureg1, Complex fac2, Qureg qureg2, Complex facOut, Qureg out)
Modifies qureg out to the result of (facOut out + fac1 qureg1 + fac2 qureg2), imposing no constraints...
Definition: QuEST.c:797
qreal calcHilbertSchmidtDistance(Qureg a, Qureg b)
Computes the Hilbert Schmidt distance between two density matrices a and b, defined as the Frobenius ...
Definition: QuEST.c:988
qreal y
Definition: QuEST.h:150
qcomp expI(qreal phase)
Returns the unit-norm complex number exp(i*phase).
Definition: utilities.cpp:406
std::vector< qcomp > QVector
A complex vector, which can be zero-initialised with QVector(numAmps).
Definition: utilities.hpp:60
qreal * imag
The imaginary values of the 2^numQubits complex elements.
Definition: QuEST.h:191
qreal x
Definition: QuEST.h:150
void pauliZ(Qureg qureg, int targetQubit)
Apply the single-qubit Pauli-Z (also known as the Z, sigma-Z or phase-flip) gate.
Definition: QuEST.c:455
QVector toQVector(Qureg qureg)
Returns an equal-size copy of the given state-vector qureg.
Definition: utilities.cpp:938
long long int numAmpsPerChunk
Number of probability amplitudes held in stateVec by this process In the non-MPI version,...
Definition: QuEST.h:213
void applyDiagonalOp(Qureg qureg, DiagonalOp op)
Apply a diagonal complex operator, which is possibly non-unitary and non-Hermitian,...
Definition: QuEST.c:887
qreal * termCoeffs
The coefficient of each Pauli product. This is a length numSumTerms array.
Definition: QuEST.h:164
void applyMatrix4(Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general 4-by-4 matrix, which may be non-unitary.
Definition: QuEST.c:853
void swapGate(Qureg qureg, int qb1, int qb2)
Performs a SWAP gate between qubit1 and qubit2.
Definition: QuEST.c:601
#define qcomp
enum pauliOpType * pauliCodes
The Pauli operators acting on each qubit, flattened over every operator.
Definition: QuEST.h:162
void initStateFromAmps(Qureg qureg, qreal *reals, qreal *imags)
Initialise qureg by specifying the complete statevector.
Definition: QuEST.c:157
ComplexMatrix4 toComplexMatrix4(QMatrix qm)
Returns a ComplexMatrix4 copy of QMatix qm.
Definition: utilities.cpp:852
void copyStateToGPU(Qureg qureg)
In GPU mode, this copies the state-vector (or density matrix) from RAM (qureg.stateVec) to VRAM / GPU...
Definition: QuEST_cpu.c:36
#define toComplex(scalar)
int numRanks
Definition: QuEST.h:245
qreal getRealAmp(Qureg qureg, long long int index)
Get the real component of the complex probability amplitude at an index in the state vector.
Definition: QuEST.c:678
void controlledPhaseFlip(Qureg qureg, int idQubit1, int idQubit2)
Apply the (two-qubit) controlled phase flip gate, also known as the controlled pauliZ gate.
Definition: QuEST.c:549
int numQubits
The number of qubits this operator can act on (informing its size)
Definition: QuEST.h:181
int numSumTerms
The number of terms in the weighted sum, or the number of Pauli products.
Definition: QuEST.h:166
Represents a diagonal complex operator on the full Hilbert state of a Qureg.
Definition: QuEST.h:178
@ PAULI_Y
Definition: QuEST.h:96
Represents a weighted sum of pauli products.
Definition: QuEST.h:158
int getNumQubits(Qureg qureg)
Get the number of qubits in a qureg object.
Definition: QuEST.c:668
Complex calcInnerProduct(Qureg bra, Qureg ket)
Computes the inner product of two equal-size state vectors, given by.
Definition: QuEST.c:910
void destroyQureg(Qureg qureg, QuESTEnv env)
Deallocate a Qureg object representing a set of qubits.
Definition: QuEST.c:77
void controlledMultiQubitUnitary(Qureg qureg, int ctrl, int *targs, int numTargs, ComplexMatrixN u)
Apply a general controlled multi-qubit unitary (including a global phase factor).
Definition: QuEST.c:314
QVector getRandomStateVector(int numQb)
Returns a random numQb-length L2-normalised state-vector from an undisclosed distribution.
Definition: utilities.cpp:453
void mixTwoQubitKrausMap(Qureg qureg, int target1, int target2, ComplexMatrix4 *ops, int numOps)
Apply a general two-qubit Kraus map to a density matrix, as specified by at most sixteen Kraus operat...
Definition: QuEST.c:1075
qreal ** real
Definition: QuEST.h:139
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:1308
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:808
QMatrix getRandomQMatrix(int dim)
Returns a dim-by-dim complex matrix, where the real and imaginary value of each element are independe...
Definition: utilities.cpp:368
void applyMatrixN(Qureg qureg, int *targs, int numTargs, ComplexMatrixN u)
Apply a general N-by-N matrix, which may be non-unitary, on any number of target qubits.
Definition: QuEST.c:863
void compactUnitary(Qureg qureg, int targetQubit, Complex alpha, Complex beta)
Apply a single-qubit unitary parameterised by two given complex scalars.
Definition: QuEST.c:405
void initClassicalState(Qureg qureg, long long int stateInd)
Initialise a set of qubits to the classical state (also known as a "computational basis state") with...
Definition: QuEST.c:134
void pauliY(Qureg qureg, int targetQubit)
Apply the single-qubit Pauli-Y (also known as the Y or sigma-Y) gate.
Definition: QuEST.c:444
Represents a system of qubits.
Definition: QuEST.h:203
void controlledPhaseShift(Qureg qureg, int idQubit1, int idQubit2, qreal angle)
Introduce a phase factor on state of qubits idQubit1 and idQubit2.
Definition: QuEST.c:499
void mixTwoQubitDephasing(Qureg qureg, int qubit1, int qubit2, qreal prob)
Mixes a density matrix qureg to induce two-qubit dephasing noise.
Definition: QuEST.c:1011
void controlledUnitary(Qureg qureg, int controlQubit, int targetQubit, ComplexMatrix2 u)
Apply a general controlled unitary (single control, single target), which can include a global phase ...
Definition: QuEST.c:361
qreal ** imag
Definition: QuEST.h:140
void initDiagonalOp(DiagonalOp op, qreal *real, qreal *imag)
Updates the entire DiagonalOp op with the given elements, of which there must be 2^op....
Definition: QuEST.c:1286
void phaseShift(Qureg qureg, int targetQubit, qreal angle)
Shift the phase between and of a single qubit by a given angle.
Definition: QuEST.c:488
ComplexArray stateVec
Computational state amplitudes - a subset thereof in the MPI version.
Definition: QuEST.h:222
void controlledNot(Qureg qureg, int controlQubit, int targetQubit)
Apply the controlled not (single control, single target) gate, also known as the c-X,...
Definition: QuEST.c:525
qreal real[2][2]
Definition: QuEST.h:116
long long int getNumAmps(Qureg qureg)
Get the number of probability amplitudes in a qureg object, given by 2^numQubits.
Definition: QuEST.c:672
long long int numElemsPerChunk
The number of the 2^numQubits amplitudes stored on each distributed node.
Definition: QuEST.h:183
int isDensityMatrix
Whether this instance is a density-state representation.
Definition: QuEST.h:206
void pauliX(Qureg qureg, int targetQubit)
Apply the single-qubit Pauli-X (also known as the X, sigma-X, NOT or bit-flip) gate.
Definition: QuEST.c:433
Qureg createCloneQureg(Qureg qureg, QuESTEnv env)
Create a new Qureg which is an exact clone of the passed qureg, which can be either a statevector or ...
Definition: QuEST.c:64
#define PREPARE_TEST(qureg, ref)
Prepares a density matrix in the debug state, and the reference QMatrix.
std::vector< std::vector< qcomp > > QMatrix
A complex square matrix.
Definition: utilities.hpp:49
qreal calcExpecPauliSum(Qureg qureg, enum pauliOpType *allPauliCodes, qreal *termCoeffs, int numSumTerms, Qureg workspace)
Computes the expected value of a sum of products of Pauli operators.
Definition: QuEST.c:961
void controlledTwoQubitUnitary(Qureg qureg, int controlQubit, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general controlled two-qubit unitary (including a global phase factor).
Definition: QuEST.c:270
ComplexMatrix2 toComplexMatrix2(QMatrix qm)
Returns a ComplexMatrix2 copy of QMatix qm.
Definition: utilities.cpp:846
int numQubits
The number of qubits for which this Hamiltonian is defined.
Definition: QuEST.h:168
Catch::Generators::GeneratorWrapper< int * > sublists(int *list, int len, int sublen)
Returns a Catch2 generator of every length-sublen sublist of length-len list, in increasing lexograph...
Definition: utilities.cpp:1199
int numQubitsRepresented
The number of qubits represented in either the state-vector or density matrix.
Definition: QuEST.h:208
long long int numAmpsTotal
Total number of amplitudes, which are possibly distributed among machines.
Definition: QuEST.h:215
qreal * real
The real values of the 2^numQubits complex elements.
Definition: QuEST.h:189
qreal real
Definition: QuEST.h:105
void mixDensityMatrix(Qureg combineQureg, qreal otherProb, Qureg otherQureg)
Modifies combineQureg to become (1-prob)combineProb + prob otherQureg.
Definition: QuEST.c:772
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:36
void destroyPauliHamil(PauliHamil h)
Destroy a PauliHamil instance, created with either createPauliHamil() or createPauliHamilFromFile().
Definition: QuEST.c:1163
void tGate(Qureg qureg, int targetQubit)
Apply the single-qubit T gate.
Definition: QuEST.c:477
void multiRotateZ(Qureg qureg, int *qubits, int numQubits, qreal angle)
Apply a multi-qubit Z rotation on a selected number of qubits.
Definition: QuEST.c:626
qreal imag
Definition: QuEST.h:106
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 getRandomDensityMatrix(int numQb)
Returns a random numQb-by-numQb density matrix, from an undisclosed distribution, in a very mixed sta...
Definition: utilities.cpp:457
QMatrix getExponentialOfDiagonalMatrix(QMatrix a)
Returns the matrix exponential of a diagonal, square, complex matrix.
Definition: utilities.cpp:187
void mixPauli(Qureg qureg, int qubit, qreal probX, qreal probY, qreal probZ)
Mixes a density matrix qureg to induce general single-qubit Pauli noise.
Definition: QuEST.c:1054
QMatrix getZeroMatrix(size_t dim)
Returns a dim-by-dim square complex matrix, initialised to all zeroes.
Definition: utilities.cpp:143
void hadamard(Qureg qureg, int targetQubit)
Apply the single-qubit Hadamard gate.
Definition: QuEST.c:177
Represents one complex number.
Definition: QuEST.h:103
void applyMatrix2(Qureg qureg, int targetQubit, ComplexMatrix2 u)
Apply a general 2-by-2 matrix, which may be non-unitary.
Definition: QuEST.c:844
#define PREPARE_TEST(quregVec, quregMatr, refVec, refMatr)
Prepares the needed data structures for unit testing some operators.
void rotateZ(Qureg qureg, int targetQubit, qreal angle)
Rotate a single qubit by a given angle around the Z-axis of the Bloch-sphere (also known as a phase s...
Definition: QuEST.c:210
QVector getRandomQVector(int dim)
Returns a dim-length vector with random complex amplitudes in the square joining {-1-i,...
Definition: utilities.cpp:420
void multiControlledUnitary(Qureg qureg, int *controlQubits, int numControlQubits, int targetQubit, ComplexMatrix2 u)
Apply a general multiple-control single-target unitary, which can include a global phase factor.
Definition: QuEST.c:374
void applyReferenceMatrix(QVector &state, int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op)
Modifies the state-vector state to be the result of left-multiplying the multi-target operator matrix...
Definition: utilities.cpp:686
void initZeroState(Qureg qureg)
Initialise a set of qubits to the classical zero state .
Definition: QuEST.c:113
qreal calcDensityInnerProduct(Qureg rho1, Qureg rho2)
Computes the Hilbert-Schmidt scalar product (which is equivalent to the Frobenius inner product of ma...
Definition: QuEST.c:918
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:50
void applyReferenceOp(QVector &state, int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op)
Modifies the state-vector state to be the result of applying the multi-target operator matrix op,...
Definition: utilities.cpp:573
void applyTrotterCircuit(Qureg qureg, PauliHamil hamil, qreal time, int order, int reps)
Applies a trotterisation of unitary evolution to qureg.
Definition: QuEST.c:830
PauliHamil createPauliHamil(int numQubits, int numSumTerms)
Create a PauliHamil instance, which is a Hamiltonian expressed as a real-weighted sum of products of ...
Definition: QuEST.c:1147
Catch::Generators::GeneratorWrapper< int * > bitsets(int numBits)
Returns a Catch2 generator of every numBits-length bit-set, in increasing lexographic order,...
Definition: utilities.cpp:1268
void initPlusState(Qureg qureg)
Initialise a set of qubits to the plus state (and similarly for density matrices).
Definition: QuEST.c:125
qreal calcExpecPauliProd(Qureg qureg, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets, Qureg workspace)
Computes the expected value of a product of Pauli operators.
Definition: QuEST.c:952
void controlledCompactUnitary(Qureg qureg, int controlQubit, int targetQubit, Complex alpha, Complex beta)
Apply a controlled unitary (single control, single target) parameterised by two given complex scalars...
Definition: QuEST.c:418
void multiStateControlledUnitary(Qureg qureg, int *controlQubits, int *controlState, int numControlQubits, int targetQubit, ComplexMatrix2 u)
Apply a general multiple-control, conditioned on a specific bit sequence, single-target unitary,...
Definition: QuEST.c:389
void sqrtSwapGate(Qureg qureg, int qb1, int qb2)
Performs a sqrt SWAP gate between qubit1 and qubit2.
Definition: QuEST.c:613
void mixMultiQubitKrausMap(Qureg qureg, int *targets, int numTargets, ComplexMatrixN *ops, int numOps)
Apply a general N-qubit Kraus map to a density matrix, as specified by at most (2N)^2 Kraus operators...
Definition: QuEST.c:1085
DiagonalOp createDiagonalOp(int numQubits, QuESTEnv env)
Creates a DiagonalOp representing a diagonal operator on the full Hilbert space of a Qureg.
Definition: QuEST.c:1267
Represents a 2x2 matrix of complex numbers.
Definition: QuEST.h:114
void controlledRotateY(Qureg qureg, int controlQubit, int targetQubit, qreal angle)
Applies a controlled rotation by a given angle around the Y-axis of the Bloch-sphere.
Definition: QuEST.c:233