The Quantum Exact Simulation Toolkit v4.2.0
Loading...
Searching...
No Matches
Deprecated tests

Unit tests of QuEST's deprecated v3 API functions. More...

Functions

 TEST_CASE ("applyDiagonalOp", "[operators]")
 
 TEST_CASE ("applyFullQFT", "[operators]")
 
 TEST_CASE ("applyGateMatrixN", "[operators]")
 
 TEST_CASE ("applyGateSubDiagonalOp", "[operators]")
 
 TEST_CASE ("applyMatrix2", "[operators]")
 
 TEST_CASE ("applyMatrix4", "[operators]")
 
 TEST_CASE ("applyMatrixN", "[operators]")
 
 TEST_CASE ("applyMultiControlledGateMatrixN", "[operators]")
 
 TEST_CASE ("applyProjector", "[operators]")
 
 TEST_CASE ("applyQFT", "[operators]")
 
 TEST_CASE ("applySubDiagonalOp", "[operators]")
 
 TEST_CASE ("calcDensityInnerProduct", "[calculations]")
 
 TEST_CASE ("calcExpecDiagonalOp", "[calculations]")
 
 TEST_CASE ("calcExpecPauliProd", "[calculations]")
 
 TEST_CASE ("calcExpecPauliSum", "[calculations]")
 
 TEST_CASE ("calcFidelity", "[calculations]")
 
 TEST_CASE ("calcHilbertSchmidtDistance", "[calculations]")
 
 TEST_CASE ("calcInnerProduct", "[calculations]")
 
 TEST_CASE ("calcProbOfAllOutcomes", "[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 ("createQuESTEnv", "[data_structures]")
 
 TEST_CASE ("createQureg", "[data_structures]")
 
 TEST_CASE ("createSubDiagonalOp", "[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 ("destroySubDiagonalOp", "[data_structures]")
 
 TEST_CASE ("diagonalUnitary", "[unitaries]")
 
 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 ("hadamard", "[unitaries]")
 
 TEST_CASE ("initArbitraryPureState", "[state_initialisations]")
 
 TEST_CASE ("initBlankState", "[state_initialisations]")
 
 TEST_CASE ("initClassicalState", "[state_initialisations]")
 
 TEST_CASE ("initPlusState", "[state_initialisations]")
 
 TEST_CASE ("initPureState", "[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 ("mixNonTPKrausMap", "[decoherence]")
 
 TEST_CASE ("mixNonTPMultiQubitKrausMap", "[decoherence]")
 
 TEST_CASE ("mixNonTPTwoQubitKrausMap", "[decoherence]")
 
 TEST_CASE ("mixPauli", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitDephasing", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitDepolarising", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitKrausMap", "[decoherence]")
 
 TEST_CASE ("multiControlledMultiQubitNot", "[unitaries]")
 
 TEST_CASE ("multiControlledMultiQubitUnitary", "[unitaries]")
 
 TEST_CASE ("multiControlledMultiRotatePauli", "[unitaries]")
 
 TEST_CASE ("multiControlledMultiRotateZ", "[unitaries]")
 
 TEST_CASE ("multiControlledPhaseFlip", "[unitaries]")
 
 TEST_CASE ("multiControlledPhaseShift", "[unitaries]")
 
 TEST_CASE ("multiControlledTwoQubitUnitary", "[unitaries]")
 
 TEST_CASE ("multiControlledUnitary", "[unitaries]")
 
 TEST_CASE ("multiQubitNot", "[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 ("setQuregAmps", "[state_initialisations]")
 
 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 ("twoQubitUnitary", "[unitaries]")
 
 TEST_CASE ("unitary", "[unitaries]")
 

Detailed Description

Unit tests of QuEST's deprecated v3 API functions.

Function Documentation

◆ TEST_CASE() [1/110]

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

Definition at line 49 of file test_operators.cpp.

49 {
50
51 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
52
53 SECTION( "correctness" ) {
54
55 // try 10 random operators
56 GENERATE( range(0,10) );
57
58 // make a totally random (non-Hermitian) diagonal oeprator
59 DiagonalOp op = createDiagonalOp(NUM_QUBITS, getQuESTEnv());
60 for (long long int i=0; i<op.numElemsPerNode; i++)
61 op.cpuElems[i] = getRandomComplex();
62 syncDiagonalOp(op);
63
64 SECTION( "state-vector" ) {
65
66 QVector ref = toQMatrix(op) * refVec;
67 applyDiagonalOp(quregVec, op);
68 REQUIRE( areEqual(quregVec, ref) );
69 }
70 SECTION( "density-matrix" ) {
71
72 QMatrix ref = toQMatrix(op) * refMatr;
73 applyDiagonalOp(quregMatr, op);
74 REQUIRE( areEqual(quregMatr, ref, 100*REAL_EPS) );
75 }
76
77 destroyDiagonalOp(op, getQuESTEnv());
78 }
79 SECTION( "input validation" ) {
80
81 SECTION( "mismatching size" ) {
82
83 DiagonalOp op = createDiagonalOp(NUM_QUBITS + 1, getQuESTEnv());
84
85 REQUIRE_THROWS_WITH( applyDiagonalOp(quregVec, op), ContainsSubstring("different number of qubits"));
86 REQUIRE_THROWS_WITH( applyDiagonalOp(quregMatr, op), ContainsSubstring("different number of qubits"));
87
88 destroyDiagonalOp(op, getQuESTEnv());
89 }
90 }
91 CLEANUP_TEST( quregVec, quregMatr );
92}
bool areEqual(QVector a, QVector b)
vector< vector< qcomp > > QMatrix
QMatrix toQMatrix(CompMatr1 src)
vector< qcomp > QVector
QuESTEnv getQuESTEnv()
qcomp getRandomComplex()
Definition random.cpp:107

◆ TEST_CASE() [2/110]

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

Definition at line 98 of file test_operators.cpp.

98 {
99
100 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
101
102 SECTION( "correctness" ) {
103
104 // try 10 times for each kind of input
105 GENERATE( range(0,10) );
106
107 SECTION( "state-vector" ) {
108
109 SECTION( "normalised" ) {
110
111 refVec = getRandomStateVector(NUM_QUBITS);
112 toQureg(quregVec, refVec);
113 refVec = getDFT(refVec);
114
115 applyFullQFT(quregVec);
116 REQUIRE( areEqual(quregVec, refVec) );
117 }
118 SECTION( "unnormalised" ) {
119
120 refVec = getRandomQVector(1 << NUM_QUBITS);
121 toQureg(quregVec, refVec);
122 refVec = getDFT(refVec);
123
124 applyFullQFT(quregVec);
125 REQUIRE( areEqual(quregVec, refVec) );
126 }
127 }
128 SECTION( "density-matrix" ) {
129
130 SECTION( "pure" ) {
131
132 /* a pure density matrix should be mapped to a pure state
133 * corresponding to the state-vector DFT
134 */
135
136 refVec = getRandomStateVector(NUM_QUBITS);
137 refMatr = getPureDensityMatrix(refVec);
138
139 toQureg(quregMatr, refMatr);
140 applyFullQFT(quregMatr);
141
142 refVec = getDFT(refVec);
143 refMatr = getPureDensityMatrix(refVec);
144
145 REQUIRE( areEqual(quregMatr, refMatr) );
146 }
147 SECTION( "mixed" ) {
148
149 /* a mixed density matrix, conceptualised as a mixture of orthogonal
150 * state-vectors, should be mapped to an equally weighted mixture
151 * of DFTs of each state-vector (because QFT is unitary and hence
152 * maintains state orthogonality)
153 */
154
155 int numStates = (1 << NUM_QUBITS)/4; // quarter as many states as possible
156 std::vector<QVector> states = getRandomOrthonormalVectors(NUM_QUBITS, numStates);
157 std::vector<qreal> probs = getRandomProbabilities(numStates);
158
159 // set qureg to random mixture
160 refMatr = getMixedDensityMatrix(probs, states);
161 toQureg(quregMatr, refMatr);
162
163 // apply QFT to mixture
164 applyFullQFT(quregMatr);
165
166 // compute dft of mixture, via dft of each state
167 refMatr = getZeroMatrix(1 << NUM_QUBITS);
168 for (int i=0; i<numStates; i++)
169 refMatr += probs[i] * getPureDensityMatrix(getDFT(states[i]));
170
171 REQUIRE( areEqual(quregMatr, refMatr) );
172 }
173 SECTION( "unnormalised" ) {
174
175 /* repeat method above, except that we use unnormalised vectors,
176 * and mix them with arbitrary complex numbers instead of probabilities,
177 * yielding an unnormalised density matrix
178 */
179
180 int numVecs = (1 << NUM_QUBITS)/4; // quarter as many states as possible
181 std::vector<QVector> vecs;
182 std::vector<qcomp> coeffs;
183 for (int i=0; i<numVecs; i++) {
184 vecs.push_back(getRandomQVector(1 << NUM_QUBITS));
185 coeffs.push_back(getRandomComplex());
186 }
187
188 // produce unnormalised matrix
189 refMatr = getZeroMatrix(1 << NUM_QUBITS);
190 for (int i=0; i<numVecs; i++)
191 refMatr += coeffs[i] * getPureDensityMatrix(vecs[i]);
192
193 toQureg(quregMatr, refMatr);
194 applyFullQFT(quregMatr);
195
196 // compute target matrix via dft of each unnormalised vector
197 refMatr = getZeroMatrix(1 << NUM_QUBITS);
198 for (int i=0; i<numVecs; i++)
199 refMatr += coeffs[i] * getPureDensityMatrix(getDFT(vecs[i]));
200
201 REQUIRE( areEqual(quregMatr, refMatr) );
202 }
203 }
204 }
205 SECTION( "input validation" ) {
206
207 SUCCEED( );
208 }
209 CLEANUP_TEST( quregVec, quregMatr );
210}
QVector getRandomQVector(int dim)
QMatrix getMixedDensityMatrix(vector< qreal > probs, vector< QVector > states)
QVector getDFT(QVector in)
QMatrix getPureDensityMatrix(QVector state)
void toQureg(Qureg qureg, QVector vec)
qmatrix getZeroMatrix(size_t dim)
Definition qmatrix.cpp:18
qvector getRandomStateVector(int numQb)
Definition random.cpp:296
vector< qreal > getRandomProbabilities(int numProbs)
Definition random.cpp:160

◆ TEST_CASE() [3/110]

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

Definition at line 218 of file test_operators.cpp.

218 {
219
220 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
221
222 // figure out max-num (inclusive) targs allowed by hardware backend
223 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
224
225 SECTION( "correctness" ) {
226
227 // generate all possible qubit arrangements
228 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
229 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
230
231 // for each qubit arrangement, use a new random unitary
232 QMatrix op = getRandomQMatrix(1 << numTargs);
233 ComplexMatrixN matr = createComplexMatrixN(numTargs);
234 toComplexMatrixN(op, matr);
235
236 SECTION( "state-vector" ) {
237
238 applyGateMatrixN(quregVec, targs, numTargs, matr);
239 applyReferenceOp(refVec, targs, numTargs, op);
240 REQUIRE( areEqual(quregVec, refVec) );
241 }
242 SECTION( "density-matrix" ) {
243
244 applyGateMatrixN(quregMatr, targs, numTargs, matr);
245 applyReferenceOp(refMatr, targs, numTargs, op);
246 REQUIRE( areEqual(quregMatr, refMatr, 1E4*REAL_EPS) );
247 }
248 destroyComplexMatrixN(matr);
249 }
250 SECTION( "input validation" ) {
251
252 SECTION( "number of targets" ) {
253
254 // there cannot be more targets than qubits in register
255 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
256 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
257 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
258 syncCompMatr(matr);
259
260 REQUIRE_THROWS_WITH( applyGateMatrixN(quregVec, targs, numTargs, matr), ContainsSubstring("number of target qubits") );
261 destroyComplexMatrixN(matr);
262 }
263 SECTION( "repetition in targets" ) {
264
265 int numTargs = 3;
266 int targs[] = {1,2,2};
267 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
268 syncCompMatr(matr);
269
270 REQUIRE_THROWS_WITH( applyGateMatrixN(quregVec, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique") );
271 destroyComplexMatrixN(matr);
272 }
273 SECTION( "qubit indices" ) {
274
275 int numTargs = 3;
276 int targs[] = {1,2,3};
277 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
278 syncCompMatr(matr);
279
280 int inv = GENERATE( -1, NUM_QUBITS );
281 targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
282 REQUIRE_THROWS_WITH( applyGateMatrixN(quregVec, targs, numTargs, matr), ContainsSubstring("Invalid target") );
283
284 destroyComplexMatrixN(matr);
285 }
286 SECTION( "matrix creation" ) {
287
288 int numTargs = 3;
289 int targs[] = {1,2,3};
290
291 ComplexMatrixN matr;
292 matr.cpuElems = NULL;
293 REQUIRE_THROWS_WITH( applyGateMatrixN(quregVec, targs, numTargs, matr), ContainsSubstring("created") );
294 }
295 SECTION( "matrix dimensions" ) {
296
297 int targs[2] = {1,2};
298 ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
299 syncCompMatr(matr);
300
301 REQUIRE_THROWS_WITH( applyGateMatrixN(quregVec, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size"));
302 destroyComplexMatrixN(matr);
303 }
304 SECTION( "matrix fits in node" ) {
305
306 // pretend we have a very limited distributed memory (judged by matr size)
307 quregVec.isDistributed = 1;
308 quregVec.numAmpsPerNode = 1;
309 quregVec.logNumAmpsPerNode = 0;
310
311 int qb[] = {1,2};
312 ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
313 syncCompMatr(matr);
314
315 REQUIRE_THROWS_WITH( applyGateMatrixN(quregVec, qb, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("cannot simultaneously store") );
316
317 destroyComplexMatrixN(matr);
318 }
319 }
320 CLEANUP_TEST( quregVec, quregMatr );
321}
unsigned int calcLog2(long unsigned int res)
void applyReferenceOp(QVector &state, int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op)
void toComplexMatrixN(QMatrix qm, ComplexMatrixN cm)
QMatrix getRandomQMatrix(int dim)
void syncCompMatr(CompMatr matr)
Definition matrices.cpp:373

◆ TEST_CASE() [4/110]

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

Definition at line 329 of file test_operators.cpp.

329 {
330
331 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
332
333 SECTION( "correctness" ) {
334
335 // generate all possible targets
336 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
337 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
338
339 // initialise a random non-unitary diagonal op
340 SubDiagonalOp op = createSubDiagonalOp(numTargs);
341 for (long long int i=0; i<op.numElems; i++)
342 op.cpuElems[i] = getRandomComplex();
343 syncDiagMatr(op);
344 QMatrix opMatr = toQMatrix(op);
345
346 SECTION( "state-vector" ) {
347
348 applyGateSubDiagonalOp(quregVec, targs, numTargs, op);
349 applyReferenceOp(refVec, targs, numTargs, opMatr);
350 REQUIRE( areEqual(quregVec, refVec) );
351 }
352 SECTION( "density-matrix" ) {
353
354 applyGateSubDiagonalOp(quregMatr, targs, numTargs, op);
355 applyReferenceOp(refMatr, targs, numTargs, opMatr);
356 REQUIRE( areEqual(quregMatr, refMatr, 1E4*REAL_EPS) );
357 }
358
359 destroySubDiagonalOp(op);
360 }
361 SECTION( "input validation" ) {
362
363 SECTION( "diagonal dimension" ) {
364
365 int numTargs = 3;
366 SubDiagonalOp op = createSubDiagonalOp(numTargs);
367 syncDiagMatr(op);
368
369 int badNumTargs = GENERATE_COPY( numTargs-1, numTargs+1 );
370 int badTargs[NUM_QUBITS+1];
371 for (int i=0; i<NUM_QUBITS+1; i++)
372 badTargs[i] = i;
373
374 REQUIRE_THROWS_WITH( applyGateSubDiagonalOp(quregVec, badTargs, badNumTargs, op), ContainsSubstring("inconsistent size") );
375 destroySubDiagonalOp(op);
376 }
377 SECTION( "number of targets" ) {
378
379 // make too many targets (which are otherwise valid)
380 SubDiagonalOp badOp = createSubDiagonalOp(NUM_QUBITS + 1);
381 int targs[NUM_QUBITS + 1];
382 for (int t=0; t<badOp.numQubits; t++)
383 targs[t] = t;
384 for (int i=0; i<badOp.numElems; i++)
385 badOp.cpuElems[i] = qcomp(1, 0);
386 syncDiagMatr(badOp);
387
388 REQUIRE_THROWS_WITH( applyGateSubDiagonalOp(quregVec, targs, badOp.numQubits, badOp), ContainsSubstring("number of target qubits") && ContainsSubstring("exceeds") );
389 destroySubDiagonalOp(badOp);
390 }
391 SECTION( "repetition in targets" ) {
392
393 // make a valid unitary diagonal op
394 SubDiagonalOp op = createSubDiagonalOp(3);
395 for (int i=0; i<op.numElems; i++)
396 op.cpuElems[i] = qcomp(1, 0);
397 syncDiagMatr(op);
398
399 // make a repetition in the target list
400 int targs[] = {2,1,2};
401
402 REQUIRE_THROWS_WITH( applyGateSubDiagonalOp(quregVec, targs, op.numQubits, op), ContainsSubstring("target qubits contained duplicates") );
403 destroySubDiagonalOp(op);
404 }
405 SECTION( "qubit indices" ) {
406
407 // make a valid unitary diagonal op
408 SubDiagonalOp op = createSubDiagonalOp(3);
409 for (int i=0; i<op.numElems; i++)
410 op.cpuElems[i] = qcomp(1,0);
411 syncDiagMatr(op);
412
413 int targs[] = {0,1,2};
414
415 // make each target in-turn invalid
416 int badIndex = GENERATE( range(0,3) );
417 int badValue = GENERATE( -1, NUM_QUBITS );
418 targs[badIndex] = badValue;
419
420 REQUIRE_THROWS_WITH( applyGateSubDiagonalOp(quregVec, targs, op.numQubits, op), ContainsSubstring("Invalid target qubit") );
421 destroySubDiagonalOp(op);
422 }
423 }
424 CLEANUP_TEST( quregVec, quregMatr );
425}
void syncDiagMatr(DiagMatr matr)
Definition matrices.cpp:374

◆ TEST_CASE() [5/110]

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

Definition at line 433 of file test_operators.cpp.

433 {
434
435 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
436
437 // every test will use a unique random matrix
438 QMatrix op = getRandomQMatrix(2); // 2-by-2
440
441 SECTION( "correctness" ) {
442
443 int target = GENERATE( range(0,NUM_QUBITS) );
444
445 // reference boilerplate
446 int* ctrls = NULL;
447 int numCtrls = 0;
448 int targs[] = {target};
449 int numTargs = 1;
450
451 SECTION( "state-vector" ) {
452
453 applyMatrix2(quregVec, target, matr);
454 applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
455
456 REQUIRE( areEqual(quregVec, refVec) );
457 }
458 SECTION( "density-matrix" ) {
459
460 applyMatrix2(quregMatr, target, matr);
461 applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
462
463 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
464 }
465 }
466 SECTION( "input validation" ) {
467
468 SECTION( "qubit indices" ) {
469
470 int target = GENERATE( -1, NUM_QUBITS );
471 REQUIRE_THROWS_WITH( applyMatrix2(quregVec, target, matr), ContainsSubstring("Invalid target") );
472 }
473 }
474 CLEANUP_TEST( quregVec, quregMatr );
475}
void applyReferenceMatrix(QVector &state, int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op)
ComplexMatrix2 toComplexMatrix2(QMatrix qm)

◆ TEST_CASE() [6/110]

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

Definition at line 483 of file test_operators.cpp.

483 {
484
485 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
486
487 // in distributed mode, each node must be able to fit all amps modified by matrix
488 REQUIRE( quregVec.numAmpsPerNode >= 4 );
489
490 // every test will use a unique random matrix
491 QMatrix op = getRandomQMatrix(4); // 4-by-4
493
494 SECTION( "correctness" ) {
495
496 int targ1 = GENERATE( range(0,NUM_QUBITS) );
497 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
498
499 // reference boilerplate
500 int* ctrls = NULL;
501 int numCtrls = 0;
502 int targs[] = {targ1, targ2};
503 int numTargs = 2;
504
505 SECTION( "state-vector" ) {
506
507 applyMatrix4(quregVec, targ1, targ2, matr);
508 applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
509 REQUIRE( areEqual(quregVec, refVec) );
510 }
511 SECTION( "density-matrix" ) {
512
513 applyMatrix4(quregMatr, targ1, targ2, matr);
514 applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
515 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
516 }
517 }
518 SECTION( "input validation" ) {
519
520 SECTION( "qubit indices" ) {
521
522 int targ1 = GENERATE( -1, NUM_QUBITS );
523 int targ2 = 0;
524 REQUIRE_THROWS_WITH( applyMatrix4(quregVec, targ1, targ2, matr), ContainsSubstring("Invalid target") );
525 REQUIRE_THROWS_WITH( applyMatrix4(quregVec, targ2, targ1, matr), ContainsSubstring("Invalid target") );
526 }
527 SECTION( "repetition of targets" ) {
528
529 int qb = 0;
530 REQUIRE_THROWS_WITH( applyMatrix4(quregVec, qb, qb, matr), ContainsSubstring("target") && ContainsSubstring("unique") );
531 }
532 SECTION( "matrix fits in node" ) {
533
534 // pretend we have a very limited distributed memory
535 quregVec.isDistributed = 1;
536 quregVec.numAmpsPerNode = 1;
537 quregVec.logNumAmpsPerNode = 0;
538 REQUIRE_THROWS_WITH( applyMatrix4(quregVec, 0, 1, matr), ContainsSubstring("communication buffer") && ContainsSubstring("cannot simultaneously store") );
539 }
540 }
541 CLEANUP_TEST( quregVec, quregMatr );
542}
ComplexMatrix4 toComplexMatrix4(QMatrix qm)

◆ TEST_CASE() [7/110]

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

Definition at line 550 of file test_operators.cpp.

550 {
551
552 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
553
554 // figure out max-num (inclusive) targs allowed by hardware backend
555 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
556
557 SECTION( "correctness" ) {
558
559 // generate all possible qubit arrangements
560 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
561 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
562
563 // for each qubit arrangement, use a new random matrix
564 QMatrix op = getRandomQMatrix(1 << numTargs);
565 ComplexMatrixN matr = createComplexMatrixN(numTargs);
566 toComplexMatrixN(op, matr);
567
568 // reference boilerplate
569 int* ctrls = NULL;
570 int numCtrls = 0;
571
572 SECTION( "state-vector" ) {
573
574 applyMatrixN(quregVec, targs, numTargs, matr);
575 applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
576 REQUIRE( areEqual(quregVec, refVec) );
577 }
578 SECTION( "density-matrix" ) {
579
580 applyMatrixN(quregMatr, targs, numTargs, matr);
581 applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
582 REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
583 }
584 destroyComplexMatrixN(matr);
585 }
586 SECTION( "input validation" ) {
587
588 SECTION( "number of targets" ) {
589
590 // there cannot be more targets than qubits in register
591 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
592 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
593 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
594 syncCompMatr(matr);
595
596 REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), ContainsSubstring("number of target qubits") );
597 destroyComplexMatrixN(matr);
598 }
599 SECTION( "repetition in targets" ) {
600
601 int numTargs = 3;
602 int targs[] = {1,2,2};
603 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
604 syncCompMatr(matr);
605
606 REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique") );
607 destroyComplexMatrixN(matr);
608 }
609 SECTION( "qubit indices" ) {
610
611 int numTargs = 3;
612 int targs[] = {1,2,3};
613 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
614 syncCompMatr(matr);
615
616 int inv = GENERATE( -1, NUM_QUBITS );
617 targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
618 REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), ContainsSubstring("Invalid target") );
619
620 destroyComplexMatrixN(matr);
621 }
622 SECTION( "matrix creation" ) {
623
624 int numTargs = 3;
625 int targs[] = {1,2,3};
626
627 ComplexMatrixN matr;
628 matr.cpuElems = NULL;
629 REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), ContainsSubstring("created") );
630 }
631 SECTION( "matrix dimensions" ) {
632
633 int targs[2] = {1,2};
634 ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
635 syncCompMatr(matr);
636
637 REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size") );
638 destroyComplexMatrixN(matr);
639 }
640 SECTION( "matrix fits in node" ) {
641
642 // pretend we have a very limited distributed memory (judged by matr size)
643 quregVec.isDistributed = 1;
644 quregVec.numAmpsPerNode = 1;
645 quregVec.logNumAmpsPerNode = 0;
646 int qb[] = {1,2};
647 ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
648 syncCompMatr(matr);
649
650 REQUIRE_THROWS_WITH( applyMatrixN(quregVec, qb, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("cannot simultaneously store") );
651
652 destroyComplexMatrixN(matr);
653 }
654 }
655 CLEANUP_TEST( quregVec, quregMatr );
656}

◆ TEST_CASE() [8/110]

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

Definition at line 664 of file test_operators.cpp.

664 {
665
666 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
667
668 // figure out max-num targs (inclusive) allowed by hardware backend
669 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
670 if (maxNumTargs >= NUM_QUBITS)
671 maxNumTargs = NUM_QUBITS - 1; // leave room for min-number of control qubits
672
673 SECTION( "correctness" ) {
674
675 // try all possible numbers of targets and controls
676 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
677 int maxNumCtrls = NUM_QUBITS - numTargs;
678 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
679
680 // generate all possible valid qubit arrangements
681 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
682 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
683
684 // for each qubit arrangement, use a new random unitary
685 QMatrix op = getRandomQMatrix(1 << numTargs);
686 ComplexMatrixN matr = createComplexMatrixN(numTargs);
687 toComplexMatrixN(op, matr);
688
689 SECTION( "state-vector" ) {
690
691 applyMultiControlledGateMatrixN(quregVec, ctrls, numCtrls, targs, numTargs, matr);
692 applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
693 REQUIRE( areEqual(quregVec, refVec) );
694 }
695 SECTION( "density-matrix" ) {
696
697 applyMultiControlledGateMatrixN(quregMatr, ctrls, numCtrls, targs, numTargs, matr);
698 applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
699 REQUIRE( areEqual(quregMatr, refMatr, 1E4*REAL_EPS) );
700 }
701 destroyComplexMatrixN(matr);
702 }
703 SECTION( "input validation" ) {
704
705 SECTION( "number of targets" ) {
706
707 // there cannot be more targets than qubits in register
708 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
709 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
710 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
711 int ctrls[] = {0};
712 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
713 toComplexMatrixN(getRandomUnitary(NUM_QUBITS+1), matr); // ensure unitary
714
715 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, ctrls, 1, targs, numTargs, matr), ContainsSubstring("number of target qubits") );
716 destroyComplexMatrixN(matr);
717 }
718 SECTION( "repetition in targets" ) {
719
720 int ctrls[] = {0};
721 int numTargs = 3;
722 int targs[] = {1,2,2};
723 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
724 toComplexMatrixN(getRandomUnitary(numTargs), matr); // ensure unitary
725
726 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, ctrls, 1, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
727 destroyComplexMatrixN(matr);
728 }
729 SECTION( "number of controls" ) {
730
731 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
732 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
733 int targs[1] = {0};
734 ComplexMatrixN matr = createComplexMatrixN(1);
735 toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
736
737 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, ctrls, numCtrls, targs, 1, matr), ContainsSubstring("number of control qubits") );
738 destroyComplexMatrixN(matr);
739 }
740 SECTION( "repetition in controls" ) {
741
742 int ctrls[] = {0,1,1};
743 int targs[] = {3};
744 ComplexMatrixN matr = createComplexMatrixN(1);
745 toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
746
747 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, ctrls, 3, targs, 1, matr), ContainsSubstring("control") && ContainsSubstring("unique") );
748 destroyComplexMatrixN(matr);
749 }
750 SECTION( "control and target collision" ) {
751
752 int ctrls[] = {1};
753 int targs[] = {3,1,0};
754 ComplexMatrixN matr = createComplexMatrixN(3);
755 toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
756
757 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, ctrls, 1, targs, 3, matr), ContainsSubstring("control and target qubits") );
758 destroyComplexMatrixN(matr);
759 }
760 SECTION( "qubit indices" ) {
761
762 // valid inds
763 int numQb = 2;
764 int qb1[2] = {0,1};
765 int qb2[2] = {2,3};
766 ComplexMatrixN matr = createComplexMatrixN(numQb);
767 toComplexMatrixN(getRandomUnitary(numQb), matr); // ensure unitary
768
769 // make qb1 invalid
770 int inv = GENERATE( -1, NUM_QUBITS );
771 qb1[GENERATE_COPY(range(0,numQb))] = inv;
772
773 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, qb1, numQb, qb2, numQb, matr), ContainsSubstring("Invalid control") );
774 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, qb2, numQb, qb1, numQb, matr), ContainsSubstring("Invalid target") );
775 destroyComplexMatrixN(matr);
776 }
777 SECTION( "matrix creation" ) {
778
779 int ctrls[1] = {0};
780 int targs[3] = {1,2,3};
781
782 ComplexMatrixN matr;
783 matr.cpuElems = NULL;
784 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, ctrls, 1, targs, 3, matr), ContainsSubstring("created") );
785 }
786 SECTION( "matrix dimensions" ) {
787
788 int ctrls[1] = {0};
789 int targs[2] = {1,2};
790 ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
791 toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
792
793 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, ctrls, 1, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size"));
794 destroyComplexMatrixN(matr);
795 }
796 SECTION( "matrix fits in node" ) {
797
798 // pretend we have a very limited distributed memory (judged by matr size)
799 quregVec.isDistributed = 1;
800 quregVec.numAmpsPerNode = 1;
801 quregVec.logNumAmpsPerNode = 0;
802 int ctrls[1] = {0};
803 int targs[2] = {1,2};
804 ComplexMatrixN matr = createComplexMatrixN(2);
805 toComplexMatrixN(getRandomUnitary(2), matr); // ensure unitary
806
807 REQUIRE_THROWS_WITH( applyMultiControlledGateMatrixN(quregVec, ctrls, 1, targs, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("cannot simultaneously store") );
808 destroyComplexMatrixN(matr);
809 }
810 }
811 CLEANUP_TEST( quregVec, quregMatr );
812}
qmatrix getRandomUnitary(int numQb)
Definition random.cpp:348

◆ TEST_CASE() [9/110]

TEST_CASE ( "applyProjector" ,
"" [operators] )
See also
applyMultiControlledMatrixN
Author
Tyson Jones
See also
applyMultiVarPhaseFunc
Author
Tyson Jones
See also
applyMultiVarPhaseFuncOverrides
Author
Tyson Jones
See also
applyNamedPhaseFunc
Author
Tyson Jones
See also
applyNamedPhaseFuncOverrides
Author
Tyson Jones
See also
applyParamNamedPhaseFunc
Author
Tyson Jones
See also
applyParamNamedPhaseFuncOverrides
Author
Tyson Jones
See also
applyPauliHamil
Author
Tyson Jones
See also
applyPauliSum
Author
Tyson Jones
See also
applyPhaseFunc
Author
Tyson Jones
See also
applyPhaseFuncOverrides
Author
Tyson Jones
See also
applyProjector
Author
Tyson Jones

Definition at line 3765 of file test_operators.cpp.

3765 {
3766
3767 Qureg vec = createForcedQureg(NUM_QUBITS);
3768 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
3769
3770 SECTION( "correctness" ) {
3771
3772 int qubit = GENERATE( range(0,NUM_QUBITS) );
3773 int outcome = GENERATE( 0, 1 );
3774
3775 // repeat these random tests 10 times on every qubit, and for both outcomes
3776 GENERATE( range(0,10) );
3777
3778 SECTION( "state-vector" ) {
3779
3780 SECTION( "normalised" ) {
3781
3782 // use a random L2 state for every qubit & outcome
3783 QVector vecRef = getRandomStateVector(NUM_QUBITS);
3784 toQureg(vec, vecRef);
3785
3786 // zero non-outcome reference amps
3787 for (size_t ind=0; ind<vecRef.size(); ind++) {
3788 int bit = (ind >> qubit) & 1; // target-th bit
3789 if (bit != outcome)
3790 vecRef[ind] = 0;
3791 }
3792
3793 applyProjector(vec, qubit, outcome);
3794 REQUIRE( areEqual(vec, vecRef) );
3795 }
3796 SECTION( "unnormalised" ) {
3797
3798 // use a random non-physical state for every qubit & outcome
3799 QVector vecRef = getRandomQVector(1 << NUM_QUBITS);
3800 toQureg(vec, vecRef);
3801
3802 // zero non-outcome reference amps
3803 for (size_t ind=0; ind<vecRef.size(); ind++) {
3804 int bit = (ind >> qubit) & 1; // target-th bit
3805 if (bit != outcome)
3806 vecRef[ind] = 0;
3807 }
3808
3809 applyProjector(vec, qubit, outcome);
3810 REQUIRE( areEqual(vec, vecRef) );
3811 }
3812 }
3813 SECTION( "density-matrix" ) {
3814
3815 SECTION( "pure" ) {
3816
3817 QVector vecRef = getRandomStateVector(NUM_QUBITS);
3818 QMatrix matRef = getPureDensityMatrix(vecRef);
3819
3820 toQureg(mat, matRef);
3821 applyProjector(mat, qubit, outcome);
3822
3823 // zero any amplitudes that aren't |outcome><outcome|
3824 for (size_t r=0; r<matRef.size(); r++) {
3825 for (size_t c=0; c<matRef.size(); c++) {
3826 int ketBit = (c >> qubit) & 1;
3827 int braBit = (r >> qubit) & 1;
3828 if (!(ketBit == outcome && braBit == outcome))
3829 matRef[r][c] = 0;
3830 }
3831 }
3832
3833 REQUIRE( areEqual(mat, matRef) );
3834 }
3835 SECTION( "mixed" ) {
3836
3837 QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
3838
3839 toQureg(mat, matRef);
3840 applyProjector(mat, qubit, outcome);
3841
3842 // zero any amplitudes that aren't |outcome><outcome|
3843 for (size_t r=0; r<matRef.size(); r++) {
3844 for (size_t c=0; c<matRef.size(); c++) {
3845 int ketBit = (c >> qubit) & 1;
3846 int braBit = (r >> qubit) & 1;
3847 if (!(ketBit == outcome && braBit == outcome))
3848 matRef[r][c] = 0;
3849 }
3850 }
3851
3852 REQUIRE( areEqual(mat, matRef) );
3853 }
3854 SECTION( "unnormalised" ) {
3855
3856 QMatrix matRef = getRandomQMatrix(1 << NUM_QUBITS);
3857
3858 toQureg(mat, matRef);
3859 applyProjector(mat, qubit, outcome);
3860
3861 // zero any amplitudes that aren't |outcome><outcome|
3862 for (size_t r=0; r<matRef.size(); r++) {
3863 for (size_t c=0; c<matRef.size(); c++) {
3864 int ketBit = (c >> qubit) & 1;
3865 int braBit = (r >> qubit) & 1;
3866 if (!(ketBit == outcome && braBit == outcome))
3867 matRef[r][c] = 0;
3868 }
3869 }
3870
3871 REQUIRE( areEqual(mat, matRef) );
3872 }
3873 }
3874 }
3875 SECTION( "input validation" ) {
3876
3877 SECTION( "qubit index" ) {
3878
3879 int qubit = GENERATE( -1, NUM_QUBITS );
3880 int outcome = 0;
3881 REQUIRE_THROWS_WITH( applyProjector(mat, qubit, outcome), ContainsSubstring("Invalid target qubit") );
3882 }
3883 SECTION( "outcome value" ) {
3884
3885 int qubit = 0;
3886 int outcome = GENERATE( -1, 2 );
3887 REQUIRE_THROWS_WITH( applyProjector(mat, qubit, outcome), ContainsSubstring("measurement outcome") && ContainsSubstring("is invalid") );
3888 }
3889 }
3890 destroyQureg(vec);
3891 destroyQureg(mat);
3892}
Qureg createForcedQureg(int numQubits)
Definition qureg.cpp:299
Qureg createForcedDensityQureg(int numQubits)
Definition qureg.cpp:309
void destroyQureg(Qureg qureg)
Definition qureg.cpp:334
qmatrix getRandomDensityMatrix(int numQb)
Definition random.cpp:308
Definition qureg.h:49

◆ TEST_CASE() [10/110]

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

Definition at line 3900 of file test_operators.cpp.

3900 {
3901
3902 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
3903
3904 SECTION( "correctness" ) {
3905
3906 // try every sub-register size
3907 int numQubits = GENERATE_COPY( range(1,NUM_QUBITS+1) );
3908
3909 // try every possible sub-register
3910 int* qubits = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numQubits) );
3911
3912 SECTION( "state-vector" ) {
3913
3914 SECTION( "normalised" ) {
3915
3916 QVector refVec = getRandomStateVector(NUM_QUBITS);
3917 toQureg(quregVec, refVec);
3918
3919 applyQFT(quregVec, qubits, numQubits);
3920 refVec = getDFT(refVec, qubits, numQubits);
3921
3922 REQUIRE( areEqual(quregVec, refVec) );
3923 }
3924 SECTION( "unnormalised" ) {
3925
3926 QVector refVec = getRandomQVector(1 << NUM_QUBITS);
3927 toQureg(quregVec, refVec);
3928
3929 applyQFT(quregVec, qubits, numQubits);
3930 refVec = getDFT(refVec, qubits, numQubits);
3931
3932 REQUIRE( areEqual(quregVec, refVec) );
3933 }
3934 }
3935 SECTION( "density-matrix" ) {
3936
3937 SECTION( "pure" ) {
3938
3939 /* a pure density matrix should be mapped to a pure state
3940 * corresponding to the state-vector DFT
3941 */
3942
3943 refVec = getRandomStateVector(NUM_QUBITS);
3944 refMatr = getPureDensityMatrix(refVec);
3945 toQureg(quregMatr, refMatr);
3946
3947 applyQFT(quregMatr, qubits, numQubits);
3948 refVec = getDFT(refVec, qubits, numQubits);
3949 refMatr = getPureDensityMatrix(refVec);
3950
3951 REQUIRE( areEqual(quregMatr, refMatr) );
3952 }
3953 SECTION( "mixed" ) {
3954
3955 /* a mixed density matrix, conceptualised as a mixture of orthogonal
3956 * state-vectors, should be mapped to an equally weighted mixture
3957 * of DFTs of each state-vector (because QFT is unitary and hence
3958 * maintains state orthogonality)
3959 */
3960
3961 int numStates = (1 << NUM_QUBITS)/4; // a quarter of as many states as are possible
3962 std::vector<QVector> states = getRandomOrthonormalVectors(NUM_QUBITS, numStates);
3963 std::vector<qreal> probs = getRandomProbabilities(numStates);
3964
3965 // set qureg to random mixture of state-vectors
3966 refMatr = getMixedDensityMatrix(probs, states);
3967 toQureg(quregMatr, refMatr);
3968
3969 // apply QFT to mixture
3970 applyQFT(quregMatr, qubits, numQubits);
3971
3972 // compute dft of mixture, via dft of each state
3973 refMatr = getZeroMatrix(1 << NUM_QUBITS);
3974 for (int i=0; i<numStates; i++) {
3975 QVector dft = getDFT(states[i], qubits, numQubits);
3976 refMatr += probs[i] * getPureDensityMatrix(dft);
3977 }
3978
3979 REQUIRE( areEqual(quregMatr, refMatr) );
3980 }
3981 SECTION( "unnormalised" ) {
3982
3983 /* repeat method above, except that we use unnormalised vectors,
3984 * and mix them with arbitrary complex numbers instead of probabilities,
3985 * yielding an unnormalised density matrix
3986 */
3987
3988 int numVecs = (1 << NUM_QUBITS)/4; // a quarter of as many states as are possible
3989 std::vector<QVector> vecs;
3990 std::vector<qcomp> coeffs;
3991 for (int i=0; i<numVecs; i++) {
3992 vecs.push_back(getRandomQVector(1 << NUM_QUBITS));
3993 coeffs.push_back(getRandomComplex());
3994 }
3995
3996 // produce unnormalised matrix via random complex sum of random unnormalised vectors
3997 refMatr = getZeroMatrix(1 << NUM_QUBITS);
3998 for (int i=0; i<numVecs; i++)
3999 refMatr += coeffs[i] * getPureDensityMatrix(vecs[i]);
4000
4001 toQureg(quregMatr, refMatr);
4002 applyQFT(quregMatr, qubits, numQubits);
4003
4004 // compute target matrix via dft of each unnormalised vector
4005 refMatr = getZeroMatrix(1 << NUM_QUBITS);
4006 for (int i=0; i<numVecs; i++) {
4007 QVector dft = getDFT(vecs[i], qubits, numQubits);
4008 refMatr += coeffs[i] * getPureDensityMatrix(dft);
4009 }
4010
4011 REQUIRE( areEqual(quregMatr, refMatr) );
4012 }
4013 }
4014 }
4015 SECTION( "input validation" ) {
4016
4017 SECTION( "number of targets" ) {
4018
4019 // there cannot be more targets than qubits in register
4020 int numQubits = GENERATE( -1, 0);
4021 int qubits[NUM_QUBITS+1];
4022
4023 REQUIRE_THROWS_WITH( applyQFT(quregVec, qubits, numQubits), ContainsSubstring("number of target qubits") && ContainsSubstring("invalid") );
4024 REQUIRE_THROWS_WITH( applyQFT(quregVec, qubits, NUM_QUBITS+1), ContainsSubstring("number of target qubits") && ContainsSubstring("exceeds") && ContainsSubstring("Qureg") );
4025
4026 }
4027 SECTION( "repetition in targets" ) {
4028
4029 int numQubits = 3;
4030 int qubits[] = {1,2,2};
4031
4032 REQUIRE_THROWS_WITH( applyQFT(quregVec, qubits, numQubits), ContainsSubstring("target") && ContainsSubstring("unique") );
4033 }
4034 SECTION( "qubit indices" ) {
4035
4036 int numQubits = 3;
4037 int qubits[] = {1,2,3};
4038
4039 int inv = GENERATE( -1, NUM_QUBITS );
4040 qubits[GENERATE_COPY( range(0,numQubits) )] = inv; // make invalid target
4041 REQUIRE_THROWS_WITH( applyQFT(quregVec, qubits, numQubits), ContainsSubstring("Invalid target") );
4042 }
4043 }
4044 CLEANUP_TEST( quregVec, quregMatr );
4045}

◆ TEST_CASE() [11/110]

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

Definition at line 4053 of file test_operators.cpp.

4053 {
4054
4055 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
4056
4057 SECTION( "correctness" ) {
4058
4059 // generate all possible targets
4060 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
4061 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
4062
4063 // initialise a random non-unitary diagonal op
4064 SubDiagonalOp op = createSubDiagonalOp(numTargs);
4065 for (long long int i=0; i<op.numElems; i++)
4066 op.cpuElems[i] = getRandomComplex();
4067 syncDiagMatr(op);
4068
4069 QMatrix opMatr = toQMatrix(op);
4070
4071 SECTION( "state-vector" ) {
4072
4073 applySubDiagonalOp(quregVec, targs, numTargs, op);
4074 applyReferenceMatrix(refVec, targs, numTargs, opMatr);
4075 REQUIRE( areEqual(quregVec, refVec) );
4076 }
4077 SECTION( "density-matrix" ) {
4078
4079 applySubDiagonalOp(quregMatr, targs, numTargs, op);
4080 applyReferenceMatrix(refMatr, targs, numTargs, opMatr);
4081 REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
4082 }
4083
4084 destroySubDiagonalOp(op);
4085 }
4086 SECTION( "input validation" ) {
4087
4088 SECTION( "diagonal dimension" ) {
4089
4090 int numTargs = 3;
4091 SubDiagonalOp op = createSubDiagonalOp(numTargs);
4092 syncDiagMatr(op);
4093
4094 int badNumTargs = GENERATE_COPY( numTargs-1, numTargs+1 );
4095 int badTargs[NUM_QUBITS+1];
4096 for (int i=0; i<NUM_QUBITS+1; i++)
4097 badTargs[i] = i;
4098
4099 REQUIRE_THROWS_WITH( applySubDiagonalOp(quregVec, badTargs, badNumTargs, op), ContainsSubstring("inconsistent size") );
4100 destroySubDiagonalOp(op);
4101 }
4102 SECTION( "number of targets" ) {
4103
4104 // make too many targets (which are otherwise valid)
4105 SubDiagonalOp badOp = createSubDiagonalOp(NUM_QUBITS + 1);
4106 int targs[NUM_QUBITS + 1];
4107 for (int t=0; t<badOp.numQubits; t++)
4108 targs[t] = t;
4109 for (int i=0; i<badOp.numElems; i++)
4110 badOp.cpuElems[i] = qcomp(1,0);
4111 syncDiagMatr(badOp);
4112
4113 REQUIRE_THROWS_WITH( applySubDiagonalOp(quregVec, targs, badOp.numQubits, badOp), ContainsSubstring("number of target qubits") && ContainsSubstring("exceeds") );
4114 destroySubDiagonalOp(badOp);
4115 }
4116 SECTION( "repetition in targets" ) {
4117
4118 // make a valid unitary diagonal op
4119 SubDiagonalOp op = createSubDiagonalOp(3);
4120 for (int i=0; i<op.numElems; i++)
4121 op.cpuElems[i] = qcomp(1,0);
4122 syncDiagMatr(op);
4123
4124 // make a repetition in the target list
4125 int targs[] = {2,1,2};
4126
4127 REQUIRE_THROWS_WITH( applySubDiagonalOp(quregVec, targs, op.numQubits, op), ContainsSubstring("target qubits contained duplicates") );
4128 destroySubDiagonalOp(op);
4129 }
4130 SECTION( "qubit indices" ) {
4131
4132 // make a valid unitary diagonal op
4133 SubDiagonalOp op = createSubDiagonalOp(3);
4134 for (int i=0; i<op.numElems; i++)
4135 op.cpuElems[i] = qcomp(1,0);
4136 syncDiagMatr(op);
4137
4138 int targs[] = {0,1,2};
4139
4140 // make each target in-turn invalid
4141 int badIndex = GENERATE( range(0,3) );
4142 int badValue = GENERATE( -1, NUM_QUBITS );
4143 targs[badIndex] = badValue;
4144
4145 REQUIRE_THROWS_WITH( applySubDiagonalOp(quregVec, targs, op.numQubits, op), ContainsSubstring("Invalid target qubit") );
4146 destroySubDiagonalOp(op);
4147 }
4148 }
4149 CLEANUP_TEST( quregVec, quregMatr );
4150}

◆ TEST_CASE() [12/110]

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

Definition at line 30 of file test_calculations.cpp.

30 {
31
32 Qureg mat1 = createForcedDensityQureg(NUM_QUBITS);
33 Qureg mat2 = createForcedDensityQureg(NUM_QUBITS);
34
35 SECTION( "correctness" ) {
36
37 // repeat these random tests 10 times
38 GENERATE( range(0,10) );
39
40 SECTION( "density-matrix" ) {
41
42 SECTION( "pure" ) {
43
44 // mat1 = |r1><r1|
45 QVector r1 = getRandomStateVector(NUM_QUBITS);
46 toQureg(mat1, getKetBra(r1,r1));
47
48 // mat2 = |r2><r2|
49 QVector r2 = getRandomStateVector(NUM_QUBITS);
50 toQureg(mat2, getKetBra(r2,r2));
51
52 // prod( |r1><r1|, |r2><r2| ) = |<r1|r2>|^2
53 qcomp prod = 0;
54 for (size_t i=0; i<r1.size(); i++)
55 prod += conj(r1[i]) * r2[i];
56 qreal densProd = pow(abs(prod),2);
57
58 REQUIRE( real(calcDensityInnerProduct(mat1,mat2)) == Approx(densProd).margin(100 * REAL_EPS) );
59 }
60 SECTION( "mixed" ) {
61
62 QMatrix ref1 = getRandomDensityMatrix(NUM_QUBITS);
63 QMatrix ref2 = getRandomDensityMatrix(NUM_QUBITS);
64 toQureg(mat1, ref1);
65 toQureg(mat2, ref2);
66
67 // prod(mat1, mat2) = sum_{ij} conj(mat1_{ij}) * mat2_{ij}
68 qcomp refProd = 0;
69 for (size_t i=0; i<ref1.size(); i++)
70 for (size_t j=0; j<ref1.size(); j++)
71 refProd += conj(ref1[i][j]) * ref2[i][j];
72 REQUIRE( imag(refProd) == Approx(0).margin(REAL_EPS) );
73
74 REQUIRE( real(calcDensityInnerProduct(mat1,mat2)) == Approx(real(refProd)).margin(100 * REAL_EPS) );
75
76 // should be invariant under ordering
77 REQUIRE( real(calcDensityInnerProduct(mat1,mat2)) == Approx(real(calcDensityInnerProduct(mat2,mat1))).margin(100 * REAL_EPS) );
78 }
79 SECTION( "unnormalised" ) {
80
81 // set both to random (non-Hermitian) complex matrices
82 QMatrix ref1 = getRandomQMatrix(1<<NUM_QUBITS);
83 QMatrix ref2 = getRandomQMatrix(1<<NUM_QUBITS);
84 toQureg(mat1, ref1);
85 toQureg(mat2, ref2);
86
87 // prod(mat1, mat2) = real(sum_{ij} conj(mat1_{ij}) * mat2_{ij})
88 qcomp refProd = 0;
89 for (size_t i=0; i<ref1.size(); i++)
90 for (size_t j=0; j<ref1.size(); j++)
91 refProd += conj(ref1[i][j]) * ref2[i][j];
92
93 REQUIRE( real(calcDensityInnerProduct(mat1,mat2)) == Approx(real(refProd)).margin(100 * REAL_EPS) );
94 }
95 }
96 }
97 SECTION( "input validation" ) {
98
99 SECTION( "dimensions" ) {
100
101 Qureg mat3 = createDensityQureg(NUM_QUBITS + 1);
102 REQUIRE_THROWS_WITH( calcDensityInnerProduct(mat1,mat3), ContainsSubstring("differing numbers of qubits") );
103 destroyQureg(mat3);
104 }
105
106 // in v4, calcDensityInnerProduct() redirects to calcInnerProduct() which is
107 // valid for both statevectors and density matrices (and combinations thereof!)
108
109 // SECTION( "state-vectors" ) {
110
111 // Qureg vec = createForcedQureg(NUM_QUBITS);
112
113 // REQUIRE_THROWS_WITH( calcDensityInnerProduct(mat1,vec), ContainsSubstring("valid only for density matrices") );
114 // REQUIRE_THROWS_WITH( calcDensityInnerProduct(vec,mat1), ContainsSubstring("valid only for density matrices") );
115 // REQUIRE_THROWS_WITH( calcDensityInnerProduct(vec,vec), ContainsSubstring("valid only for density matrices") );
116
117 // destroyQureg(vec);
118 // }
119 }
120 destroyQureg(mat1);
121 destroyQureg(mat2);
122}
QMatrix getKetBra(QVector ket, QVector bra)
Qureg createDensityQureg(int numQubits)
Definition qureg.cpp:291

◆ TEST_CASE() [13/110]

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

Definition at line 130 of file test_calculations.cpp.

130 {
131
132 Qureg vec = createForcedQureg(NUM_QUBITS);
133 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
134 initDebugState(vec);
135 initDebugState(mat);
136 QVector vecRef = toQVector(vec);
137 QMatrix matRef = toQMatrix(mat);
138
139 SECTION( "correctness" ) {
140
141 // try 10 random operators
142 GENERATE( range(0,10) );
143
144 // make a totally random (non-Hermitian) diagonal oeprator
145 DiagonalOp op = createDiagonalOp(NUM_QUBITS, getQuESTEnv());
146 for (long long int i=0; i<op.numElemsPerNode; i++)
147 op.cpuElems[i] = getRandomComplex();
148 syncDiagonalOp(op);
149
150 SECTION( "state-vector" ) {
151
152 /* calcExpecDiagOp calculates <qureg|diag|qureg> */
153
154 QVector sumRef = toQMatrix(op) * vecRef;
155 qcomp prod = 0;
156 for (size_t i=0; i<vecRef.size(); i++)
157 prod += conj(vecRef[i]) * sumRef[i];
158
159 qcomp res = calcExpecDiagonalOp(vec, op);
160 REQUIRE( real(res) == Approx(real(prod)).margin(REAL_EPS) );
161 REQUIRE( imag(res) == Approx(imag(prod)).margin(REAL_EPS) );
162 }
163 SECTION( "density-matrix" ) {
164
165 /* calcExpecDiagOp calculates Trace( diag * qureg ) */
166 matRef = toQMatrix(op) * matRef;
167 qcomp tr = 0;
168 for (size_t i=0; i<matRef.size(); i++)
169 tr += matRef[i][i];
170
171 qcomp res = calcExpecDiagonalOp(mat, op);
172 REQUIRE( real(res) == Approx(real(tr)).margin(100*REAL_EPS) );
173 REQUIRE( imag(res) == Approx(imag(tr)).margin(100*REAL_EPS) );
174 }
175
176 destroyDiagonalOp(op, getQuESTEnv());
177 }
178 SECTION( "input validation" ) {
179
180 SECTION( "mismatching size" ) {
181
182 DiagonalOp op = createDiagonalOp(NUM_QUBITS + 1, getQuESTEnv());
183
184 REQUIRE_THROWS_WITH( calcExpecDiagonalOp(vec, op), ContainsSubstring("different number of qubits"));
185 REQUIRE_THROWS_WITH( calcExpecDiagonalOp(mat, op), ContainsSubstring("different number of qubits"));
186
187 destroyDiagonalOp(op, getQuESTEnv());
188 }
189 }
190 destroyQureg(vec);
191 destroyQureg(mat);
192}
QVector toQVector(Qureg qureg)
void initDebugState(Qureg qureg)

◆ TEST_CASE() [14/110]

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

Definition at line 316 of file test_calculations.cpp.

316 {
317
318 QuESTEnv env = getQuESTEnv();
319 Qureg vec = createCustomQureg(NUM_QUBITS, 0, env.isDistributed, env.isGpuAccelerated, env.isMultithreaded);
320 Qureg mat = createCustomQureg(NUM_QUBITS, 1, env.isDistributed, env.isGpuAccelerated, env.isMultithreaded);
321
322 initDebugState(vec);
323 initDebugState(mat);
324 QVector vecRef = toQVector(vec);
325 QMatrix matRef = toQMatrix(mat);
326
327 Qureg vecWork = createForcedQureg(NUM_QUBITS);
328 Qureg matWork = createForcedDensityQureg(NUM_QUBITS);
329
330 SECTION( "correctness" ) {
331
332 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
333 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
334
335 /* it's too expensive to try ALL Pauli sequences, via
336 * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
337 * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
338 * Hence, we instead opt to repeatedlyrandomly generate pauliseqs
339 */
340 GENERATE( range(0,10) ); // gen 10 random pauli-codes for every targs
341 vector<pauliOpType> paulis(numTargs);
342 for (int i=0; i<numTargs; i++)
343 paulis[i] = (pauliOpType) getRandomInt(0,4);
344
345 // produce a numTargs-big matrix 'pauliProd' by pauli-matrix tensoring
346 QMatrix iMatr{{1,0},{0,1}};
347 QMatrix xMatr{{0,1},{1,0}};
348 QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
349 QMatrix zMatr{{1,0},{0,-1}};
350 QMatrix pauliProd{{1}};
351 for (int i=0; i<numTargs; i++) {
352 QMatrix fac;
353 if (paulis[i] == PAULI_I) fac = iMatr;
354 if (paulis[i] == PAULI_X) fac = xMatr;
355 if (paulis[i] == PAULI_Y) fac = yMatr;
356 if (paulis[i] == PAULI_Z) fac = zMatr;
357 pauliProd = getKroneckerProduct(fac, pauliProd);
358 }
359
360 SECTION( "state-vector" ) {
361
362 /* calcExpecPauliProd calculates <qureg|pauliProd|qureg> */
363
364 QVector prodRef = vecRef;
365 applyReferenceOp(prodRef, targs, numTargs, pauliProd);
366 qcomp prod = 0;
367 for (size_t i=0; i<vecRef.size(); i++)
368 prod += conj(vecRef[i]) * prodRef[i];
369 REQUIRE( imag(prod) == Approx(0).margin(REAL_EPS) );
370
371 qreal res = calcExpecPauliProd(vec, targs, paulis.data(), numTargs, vecWork);
372 REQUIRE( res == Approx(real(prod)).margin(REAL_EPS) );
373 }
374 SECTION( "density-matrix" ) {
375
376 /* calcExpecPauliProd calculates Trace( pauliProd * qureg ) */
377
378 // produce (pauliProd * mat)
379 QMatrix fullOp = getFullOperatorMatrix(NULL, 0, targs, numTargs, pauliProd, NUM_QUBITS);
380 matRef = fullOp * matRef;
381
382 // compute real(trace(pauliProd * mat))
383 qreal tr = 0;
384 for (size_t i=0; i<matRef.size(); i++)
385 tr += real(matRef[i][i]);
386 // (get real, since we start in a non-Hermitian state, hence diagonal isn't real)
387
388 // disable validation during call, because result is non-real and will upset post-check
390 qreal res = calcExpecPauliProd(mat, targs, paulis.data(), numTargs, matWork);
392
393 REQUIRE( res == Approx(tr).margin(10*REAL_EPS) );
394 }
395 }
396 SECTION( "input validation" ) {
397
398 pauliOpType pauliOpsToAvoidDeprecSegFault[100];
399 for (int i=0; i<100; i++)
400 pauliOpsToAvoidDeprecSegFault[i] = PAULI_X;
401
402 SECTION( "number of targets" ) {
403
404 int targs[NUM_QUBITS+1];
405 for (int i=0; i<NUM_QUBITS+1; i++)
406 targs[i] = i;
407
408 // too few
409 int numTargs = GENERATE( -1, 0 );
410 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring("Invalid number of Paulis") );
411
412 // too many
413 numTargs = NUM_QUBITS + 1;
414 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring("highest-index non-identity Pauli operator") && ContainsSubstring("exceeds the maximum target") );
415 }
416 SECTION( "target indices" ) {
417
418 int numTargs = 3;
419 int targs[3] = {0, 1, 2};
420
421 int badInd = GENERATE( range(0,3) );
422
423 // make one index too small
424 targs[badInd] = -1;
425 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring("Pauli indices must be non-negative") );
426
427 // make one index too big
428 targs[badInd] = NUM_QUBITS;
429 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring("highest-index non-identity Pauli operator") );
430
431 // make one index WAY too big
432 targs[badInd] = 65;
433 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring("exceed the maximum number of representable Pauli operators") );
434 }
435 SECTION( "repetition in targets" ) {
436
437 int numTargs = 3;
438 int targs[3] = {0, 1, 1};
439 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring("Indices must be unique") );
440 }
441 SECTION( "pauli codes" ) {
442
443 int numTargs = 3;
444 int targs[3] = {0, 1, 2};
445 pauliOpType codes[3] = {PAULI_X, PAULI_Y, PAULI_Z};
446
447 // make one pauli wrong
448 codes[GENERATE( range(0,3) )] = (pauliOpType) GENERATE( -1, 4 );
449 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, vecWork), ContainsSubstring("invalid Pauli code") );
450 }
451
452 // workspace is no longer needed; argument is ignored
453
454 // SECTION( "workspace type" ) {
455
456 // int numTargs = 1;
457 // int targs[1] = {0};
458 // pauliOpType codes[1] = {PAULI_I};
459
460 // REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, matWork), ContainsSubstring("Registers must both be state-vectors or both be density matrices") );
461 // REQUIRE_THROWS_WITH( calcExpecPauliProd(mat, targs, codes, numTargs, vecWork), ContainsSubstring("Registers must both be state-vectors or both be density matrices") );
462 // }
463 // SECTION( "workspace dimensions" ) {
464
465 // int numTargs = 1;
466 // int targs[1] = {0};
467 // pauliOpType codes[1] = {PAULI_I};
468
469 // Qureg vec2 = createQureg(NUM_QUBITS + 1);
470 // REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, vec2), ContainsSubstring("Dimensions") && ContainsSubstring("don't match") );
471 // destroyQureg(vec2);
472
473 // Qureg mat2 = createDensityQureg(NUM_QUBITS + 1);
474 // REQUIRE_THROWS_WITH( calcExpecPauliProd(mat, targs, codes, numTargs, mat2), ContainsSubstring("Dimensions") && ContainsSubstring("don't match") );
475 // destroyQureg(mat2);
476 // }
477 }
478 destroyQureg(vec);
479 destroyQureg(mat);
480 destroyQureg(vecWork);
481 destroyQureg(matWork);
482}
void setValidationOff()
Definition debug.cpp:86
void setValidationOn()
Definition debug.cpp:80
QMatrix getFullOperatorMatrix(int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op, int numQubits)
Qureg createCustomQureg(int numQubits, int isDensMatr, int useDistrib, int useGpuAccel, int useMultithread)
Definition qureg.cpp:277
qmatrix getKroneckerProduct(qmatrix a, qmatrix b)
Definition linalg.cpp:523
int getRandomInt(int min, int maxExcl)
Definition random.cpp:90

◆ TEST_CASE() [15/110]

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

Definition at line 490 of file test_calculations.cpp.

490 {
491
492 Qureg vec = createForcedQureg(NUM_QUBITS);
493 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
494
495 QVector vecRef = getRandomStateVector(NUM_QUBITS);
496 QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
497 toQureg(vec, vecRef);
498 toQureg(mat, matRef);
499
500 // accepted by v3 deprecated API but discarded by v4
501 Qureg vecWork = createForcedQureg(NUM_QUBITS);
502 Qureg matWork = createForcedDensityQureg(NUM_QUBITS);
503
504 SECTION( "correctness" ) {
505
506 int numSumTerms = GENERATE( 1, 2, 10, 15 );
507
508 /* it's too expensive to try every possible Pauli configuration, so
509 * we'll try 10 random codes, and for each, random coefficients
510 */
511 GENERATE( range(0,10) );
512 int totNumCodes = numSumTerms * NUM_QUBITS;
513 vector<pauliOpType> paulis(totNumCodes);
514 vector<qreal> coeffs(numSumTerms);
515 setRandomPauliSum(coeffs.data(), paulis.data(), NUM_QUBITS, numSumTerms);
516
517 // produce a numTargs-big matrix 'pauliSum' by pauli-matrix tensoring and summing
518 QMatrix pauliSum = toQMatrix(coeffs.data(), paulis.data(), NUM_QUBITS, numSumTerms);
519
520 SECTION( "state-vector" ) {
521
522 /* calcExpecPauliSum calculates <qureg|pauliSum|qureg> */
523
524 QVector sumRef = pauliSum * vecRef;
525 qcomp prod = 0;
526 for (size_t i=0; i<vecRef.size(); i++)
527 prod += conj(vecRef[i]) * sumRef[i];
528 REQUIRE( imag(prod) == Approx(0).margin(10*REAL_EPS) );
529
530 qreal res = calcExpecPauliSum(vec, paulis.data(), coeffs.data(), numSumTerms, vecWork);
531 REQUIRE( res == Approx(real(prod)).margin(10*REAL_EPS) );
532 }
533 SECTION( "density-matrix" ) {
534
535 /* calcExpecPauliSum calculates Trace( pauliSum * qureg ) */
536 matRef = pauliSum * matRef;
537 qreal tr = 0;
538 for (size_t i=0; i<matRef.size(); i++)
539 tr += real(matRef[i][i]);
540 // (get real, since we start in a non-Hermitian state, hence diagonal isn't real)
541
542 qreal res = calcExpecPauliSum(mat, paulis.data(), coeffs.data(), numSumTerms, matWork);
543 REQUIRE( res == Approx(tr).margin(1E2*REAL_EPS) );
544 }
545 }
546 SECTION( "input validation" ) {
547
548 // cannot be validated; deprecated API copies before validating numSumTerms, causing segfault
549
550 // SECTION( "number of sum terms" ) {
551
552 // int numSumTerms = GENERATE( -1, 0 );
553 // REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, NULL, NULL, numSumTerms, vecWork), ContainsSubstring("The number of terms must be a positive integer") );
554 // }
555
556 SECTION( "pauli codes" ) {
557
558 // make valid params
559 int numSumTerms = 3;
560 vector<qreal> coeffs(numSumTerms);
561 vector<pauliOpType> codes(numSumTerms*NUM_QUBITS);
562 for (int i=0; i<numSumTerms*NUM_QUBITS; i++)
563 codes[i] = PAULI_I;
564
565 // make one pauli wrong
566 codes[GENERATE_COPY( range(0,numSumTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
567 REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes.data(), coeffs.data(), numSumTerms, vecWork), ContainsSubstring("invalid Pauli code") );
568 }
569
570 // the v4 API does not use a workspace, so it is discarded by the v3 deprecation layer
571
572 // SECTION( "workspace type" ) {
573
574 // // make valid params
575 // int numSumTerms = 1;
576 // qreal coeffs[1] = {0};
577 // pauliOpType codes[NUM_QUBITS];
578 // for (int i=0; i<NUM_QUBITS; i++)
579 // codes[i] = PAULI_I;
580
581 // REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes, coeffs, numSumTerms, mat), ContainsSubstring("Registers must both be state-vectors or both be density matrices") );
582 // REQUIRE_THROWS_WITH( calcExpecPauliSum(mat, codes, coeffs, numSumTerms, vec), ContainsSubstring("Registers must both be state-vectors or both be density matrices") );
583 // }
584
585 // SECTION( "workspace dimensions" ) {
586
587 // // make valid params
588 // int numSumTerms = 1;
589 // qreal coeffs[1] = {0};
590 // pauliOpType codes[NUM_QUBITS];
591 // for (int i=0; i<NUM_QUBITS; i++)
592 // codes[i] = PAULI_I;
593
594 // Qureg vec2 = createQureg(NUM_QUBITS + 1);
595 // REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes, coeffs, numSumTerms, vec2), ContainsSubstring("Dimensions") && ContainsSubstring("don't match") );
596 // destroyQureg(vec2);
597
598 // Qureg mat2 = createDensityQureg(NUM_QUBITS + 1);
599 // REQUIRE_THROWS_WITH( calcExpecPauliSum(mat, codes, coeffs, numSumTerms, mat2), ContainsSubstring("Dimensions") && ContainsSubstring("don't match") );
600 // destroyQureg(mat2);
601 // }
602 }
603 destroyQureg(vec);
604 destroyQureg(mat);
605 destroyQureg(vecWork);
606 destroyQureg(matWork);
607}
void setRandomPauliSum(qreal *coeffs, pauliOpType *codes, int numQubits, int numTerms)

◆ TEST_CASE() [16/110]

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

Definition at line 615 of file test_calculations.cpp.

615 {
616
617 Qureg vec = createForcedQureg(NUM_QUBITS);
618 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
619 Qureg pure = createForcedQureg(NUM_QUBITS);
620
621 SECTION( "correctness" ) {
622
623 // repeat the below random tests 10 times
624 GENERATE( range(0,10) );
625
626 SECTION( "state-vector" ) {
627
628 /* calcFidelity computes |<vec|pure>|^2 */
629
630 SECTION( "normalised" ) {
631
632 // random L2 vectors
633 QVector vecRef = getRandomStateVector(NUM_QUBITS);
634 QVector pureRef = getRandomStateVector(NUM_QUBITS);
635 toQureg(vec, vecRef);
636 toQureg(pure, pureRef);
637
638 // |<vec|vec>|^2 = |1|^2 = 1
639 REQUIRE( calcFidelity(vec,vec) == Approx(1) );
640
641 // |<vec|pure>|^2 = |sum_j conj(vec_j) * pure_j|^2
642 qcomp dotProd = 0;
643 for (size_t i=0; i<vecRef.size(); i++)
644 dotProd += conj(vecRef[i]) * pureRef[i];
645 qreal refFid = pow(abs(dotProd), 2);
646
647 REQUIRE( calcFidelity(vec,pure) == Approx(refFid) );
648 }
649
650 // unnormalised test is no longer supported, since v4 calcFidelity
651 // validates thet the fidelity is correctly approximately real
652
653 // SECTION( "unnormalised" ) {
654
655 // // random unnormalised vectors
656 // QVector vecRef = getRandomQVector(1<<NUM_QUBITS);
657 // QVector pureRef = getRandomQVector(1<<NUM_QUBITS);
658 // toQureg(vec, vecRef);
659 // toQureg(pure, pureRef);
660
661 // // Let nv be magnitude of vec, hence |unit-vec> = 1/sqrt(nv)|vec>
662 // qreal nv = 0;
663 // for (size_t i=0; i<vecRef.size(); i++)
664 // nv += pow(abs(vecRef[i]), 2);
665 // // then <vec|vec> = sqrt(nv)*sqrt(nv) <unit-vec|unit-vec> = nv,
666 // // hence |<vec|vec>|^2 = nv*nv
667 // REQUIRE( calcFidelity(vec,vec) == Approx( nv*nv ) );
668
669 // qcomp dotProd = 0;
670 // for (size_t i=0; i<vecRef.size(); i++)
671 // dotProd += conj(vecRef[i]) * pureRef[i];
672 // qreal refFid = pow(abs(dotProd), 2);
673
674 // REQUIRE( calcFidelity(vec,pure) == Approx(refFid) );
675 // }
676 }
677 SECTION( "density-matrix" ) {
678
679 /* calcFidelity computes <pure|mat|pure> */
680
681 SECTION( "pure" ) {
682
683 QVector pureRef = getRandomStateVector(NUM_QUBITS);
684 toQureg(pure, pureRef);
685
686 // test when density matrix is the same pure state
687 QMatrix matRef = getKetBra(pureRef, pureRef);
688 toQureg(mat, matRef);
689 REQUIRE( calcFidelity(mat,pure) == Approx(1) );
690
691 // test when density matrix is a random pure state
692 QVector r1 = getRandomStateVector(NUM_QUBITS);
693 matRef = getKetBra(r1, r1); // actually pure |r1><r1|
694 toQureg(mat, matRef);
695
696 // <pure|r1><r1|pure> = |<r1|pure>|^2 = |sum_j conj(r1_j) * pure_j|^2
697 qcomp dotProd = 0;
698 for (size_t i=0; i<r1.size(); i++)
699 dotProd += conj(r1[i]) * pureRef[i];
700 qreal refFid = pow(abs(dotProd), 2);
701
702 REQUIRE( calcFidelity(mat,pure) == Approx(refFid).margin(100 * REAL_EPS) );
703 }
704 SECTION( "mixed" ) {
705
706 QVector pureRef = getRandomStateVector(NUM_QUBITS);
707 toQureg(pure, pureRef);
708
709 // test when density matrix is mixed
710 QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
711 toQureg(mat, matRef);
712
713 // <pure|mat|pure> = <pure| (Mat|pure>)
714 QVector rhs = matRef * pureRef;
715 qcomp dotProd = 0;
716 for (size_t i=0; i<rhs.size(); i++)
717 dotProd += conj(pureRef[i]) * rhs[i];
718
719 REQUIRE( imag(dotProd) == Approx(0).margin(REAL_EPS) );
720 REQUIRE( calcFidelity(mat,pure) == Approx(real(dotProd)).margin(100 * REAL_EPS) );
721 }
722
723 // unnormalised test is no longer supported, since v4 calcFidelity
724 // validates thet the fidelity is correctly approximately real
725
726 // SECTION( "unnormalised" ) {
727
728 // // test when both density matrix and pure state are unnormalised
729 // QVector pureRef = getRandomQVector(1<<NUM_QUBITS);
730 // QMatrix matRef = getRandomQMatrix(1<<NUM_QUBITS);
731 // toQureg(pure, pureRef);
732 // toQureg(mat, matRef);
733
734 // // real[ <pure|mat|pure> ] = real[ <pure| (Mat|pure>) ]
735 // QVector rhs = matRef * pureRef;
736 // qcomp dotProd = 0;
737 // for (size_t i=0; i<rhs.size(); i++)
738 // dotProd += conj(pureRef[i]) * rhs[i];
739
740 // REQUIRE( calcFidelity(mat,pure) == Approx(real(dotProd)) );
741 // }
742 }
743 }
744 SECTION( "input validation" ) {
745
746 SECTION( "dimensions" ) {
747
748 // two state-vectors
749 Qureg vec2 = createQureg(vec.numQubits + 1);
750 REQUIRE_THROWS_WITH( calcFidelity(vec2,vec), ContainsSubstring("differing numbers of qubits") );
751 destroyQureg(vec2);
752
753 // density-matrix and state-vector
754 Qureg mat2 = createDensityQureg(vec.numQubits + 1);
755 REQUIRE_THROWS_WITH( calcFidelity(mat2,vec), ContainsSubstring("differing numbers of qubits") );
756 destroyQureg(mat2);
757 }
758 SECTION( "density-matrices" ) {
759
760 // two mixed statess
761 REQUIRE_THROWS_WITH( calcFidelity(mat,mat), ContainsSubstring("Quregs cannot both be density matrices") );
762 }
763 }
764 destroyQureg(vec);
765 destroyQureg(mat);
766 destroyQureg(pure);
767}
qreal calcFidelity(Qureg qureg, Qureg other)
Qureg createQureg(int numQubits)
Definition qureg.cpp:283

◆ TEST_CASE() [17/110]

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

Definition at line 775 of file test_calculations.cpp.

775 {
776
777 Qureg mat1 = createForcedDensityQureg(NUM_QUBITS);
778 Qureg mat2 = createForcedDensityQureg(NUM_QUBITS);
779
780 SECTION( "correctness" ) {
781
782 // perform these random tests 10 times
783 GENERATE( range(0,10) );
784
785 SECTION( "density-matrix" ) {
786
787 SECTION( "pure" ) {
788
789 // create random |r1><r1| and |r2><r2| states
790 QVector r1 = getRandomStateVector(NUM_QUBITS);
791 QMatrix m1 = getKetBra(r1,r1);
792 toQureg(mat1, m1);
793 QVector r2 = getRandomStateVector(NUM_QUBITS);
794 QMatrix m2 = getKetBra(r2,r2);
795 toQureg(mat2, m2);
796
797 // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
798 qreal tr = 0;
799 for (size_t i=0; i<m1.size(); i++)
800 for (size_t j=0; j<m1.size(); j++)
801 tr += pow(abs(m1[i][j] - m2[i][j]), 2);
802
803 qreal res = calcHilbertSchmidtDistance(mat1, mat2);
804 REQUIRE( res == Approx(sqrt(tr)) );
805
806 }
807 SECTION( "normalised" ) {
808
809 QMatrix ref1 = getRandomDensityMatrix(NUM_QUBITS);
810 QMatrix ref2 = getRandomDensityMatrix(NUM_QUBITS);
811 toQureg(mat1, ref1);
812 toQureg(mat2, ref2);
813
814 // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
815 qreal tr = 0;
816 for (size_t i=0; i<ref1.size(); i++)
817 for (size_t j=0; j<ref1.size(); j++)
818 tr += pow(abs(ref1[i][j] - ref2[i][j]), 2);
819
820 qreal res = calcHilbertSchmidtDistance(mat1, mat2);
821 REQUIRE( res == Approx(sqrt(tr)) );
822 }
823 SECTION( "unnormalised" ) {
824
825 // mat1 and mat2 are both random matrices
826 QMatrix ref1 = getRandomQMatrix(1<<NUM_QUBITS);
827 QMatrix ref2 = getRandomQMatrix(1<<NUM_QUBITS);
828 toQureg(mat1, ref1);
829 toQureg(mat2, ref2);
830
831 // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
832 qreal tr = 0;
833 for (size_t i=0; i<ref1.size(); i++)
834 for (size_t j=0; j<ref1.size(); j++)
835 tr += pow(abs(ref1[i][j] - ref2[i][j]), 2);
836
837 qreal res = calcHilbertSchmidtDistance(mat1, mat2);
838 REQUIRE( res == Approx(sqrt(tr)) );
839 }
840 }
841 }
842 SECTION( "input validation") {
843
844 SECTION( "dimensions" ) {
845
846 Qureg mat3 = createDensityQureg(NUM_QUBITS + 1);
847 REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(mat1,mat3), ContainsSubstring("differing numbers of qubits") );
848 destroyQureg(mat3);
849 }
850
851 // in v4, this function calls calcDistance() which has state-vector overloads
852
853 // SECTION( "state-vector" ) {
854
855 // Qureg vec = createForcedQureg(NUM_QUBITS);
856
857 // REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(vec,mat1), ContainsSubstring("valid only for density matrices") );
858 // REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(mat1,vec), ContainsSubstring("valid only for density matrices") );
859 // REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(vec,vec), ContainsSubstring("valid only for density matrices") );
860
861 // destroyQureg(vec);
862 // }
863 }
864 destroyQureg(mat1);
865 destroyQureg(mat2);
866}

◆ TEST_CASE() [18/110]

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

Definition at line 874 of file test_calculations.cpp.

874 {
875
876 Qureg vec1 = createForcedQureg(NUM_QUBITS);
877 Qureg vec2 = createForcedQureg(NUM_QUBITS);
878
879 SECTION( "correctness" ) {
880
881 // perform these random tests 10 times
882 GENERATE( range(0,10) );
883
884 SECTION( "state-vector" ) {
885
886 SECTION( "normalised" ) {
887
888 // <r1|r2> = sum_j conj(r1_j) * r2_j
889 QVector r1 = getRandomStateVector(NUM_QUBITS);
890 QVector r2 = getRandomStateVector(NUM_QUBITS);
891 qcomp prod = 0;
892 for (size_t i=0; i<r1.size(); i++)
893 prod += conj(r1[i]) * r2[i];
894
895 toQureg(vec1, r1);
896 toQureg(vec2, r2);
897 qcomp res = calcInnerProduct(vec1,vec2);
898
899 REQUIRE( real(res) == Approx(real(prod)) );
900 REQUIRE( imag(res) == Approx(imag(prod)) );
901 }
902 SECTION( "unnormalised" ) {
903
904 // <r1|r2> = sum_j conj(r1_j) * r2_j
905 QVector r1 = getRandomQVector(1<<NUM_QUBITS);
906 QVector r2 = getRandomQVector(1<<NUM_QUBITS);
907 qcomp prod = 0;
908 for (size_t i=0; i<r1.size(); i++)
909 prod += conj(r1[i]) * r2[i];
910
911 toQureg(vec1, r1);
912 toQureg(vec2, r2);
913 qcomp res = calcInnerProduct(vec1,vec2);
914
915 REQUIRE( real(res) == Approx(real(prod)).margin(REAL_EPS) );
916 REQUIRE( imag(res) == Approx(imag(prod)).margin(REAL_EPS) );
917 }
918 }
919 }
920 SECTION( "input validation" ) {
921
922 SECTION( "dimensions" ) {
923
924 Qureg vec3 = createQureg(NUM_QUBITS + 1);
925 REQUIRE_THROWS_WITH( calcInnerProduct(vec1,vec3), ContainsSubstring("differing numbers of qubits") );
926 destroyQureg(vec3);
927 }
928
929 // density-matrix arguments are permitted in v4
930
931 // SECTION( "density-matrix" ) {
932
933 // Qureg mat = createForcedDensityQureg(NUM_QUBITS);
934
935 // REQUIRE_THROWS_WITH( calcInnerProduct(vec1,mat), ContainsSubstring("valid only for state-vectors") );
936 // REQUIRE_THROWS_WITH( calcInnerProduct(mat,vec1), ContainsSubstring("valid only for state-vectors") );
937 // REQUIRE_THROWS_WITH( calcInnerProduct(mat,mat), ContainsSubstring("valid only for state-vectors") );
938
939 // destroyQureg(mat);
940 // }
941 }
942 destroyQureg(vec1);
943 destroyQureg(vec2);
944}
qcomp calcInnerProduct(Qureg qureg, Qureg other)

◆ TEST_CASE() [19/110]

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

Definition at line 952 of file test_calculations.cpp.

952 {
953
954 Qureg vec = createForcedQureg(NUM_QUBITS);
955 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
956
957 SECTION( "correctness" ) {
958
959 // generate all possible qubit arrangements
960 int numQubits = GENERATE_COPY( range(1,NUM_QUBITS+1) );
961 int* qubits = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numQubits) );
962
963 int numOutcomes = 1<<numQubits;
964 vector<qreal> probs(numOutcomes);
965 QVector refProbs = QVector(numOutcomes);
966
967 SECTION( "state-vector" ) {
968
969 SECTION( "normalised" ) {
970
971 QVector ref = getRandomStateVector(NUM_QUBITS);
972 toQureg(vec, ref);
973
974 // prob is sum of |amp|^2 of basis states which encode outcome
975 for (size_t i=0; i<ref.size(); i++) {
976 int outcome = 0;
977 for (int q=0; q<numQubits; q++) {
978 int bit = (i >> qubits[q]) & 1;
979 outcome += bit * (1 << q);
980 }
981 refProbs[outcome] += pow(abs(ref[i]), 2);
982 }
983
984 calcProbOfAllOutcomes(probs.data(), vec, qubits, numQubits);
985 REQUIRE( areEqual(refProbs, probs.data()) );
986 }
987 SECTION( "unnormalised" ) {
988
989 QVector ref = getRandomQVector(1<<NUM_QUBITS);
990 toQureg(vec, ref);
991
992 // prob is sum of |amp|^2 of basis states which encode outcome
993 for (size_t i=0; i<ref.size(); i++) {
994 int outcome = 0;
995 for (int q=0; q<numQubits; q++) {
996 int bit = (i >> qubits[q]) & 1;
997 outcome += bit * (1 << q);
998 }
999 refProbs[outcome] += pow(abs(ref[i]), 2);
1000 }
1001
1002 calcProbOfAllOutcomes(probs.data(), vec, qubits, numQubits);
1003 REQUIRE( areEqual(refProbs, probs.data()) );
1004 }
1005 }
1006 SECTION( "density-matrix" ) {
1007
1008 SECTION( "normalised" ) {
1009
1010 QMatrix ref = getRandomDensityMatrix(NUM_QUBITS);
1011 toQureg(mat, ref);
1012
1013 // prob is sum of diagonals which encode outcome
1014 for (size_t i=0; i<ref.size(); i++) {
1015 int outcome = 0;
1016 for (int q=0; q<numQubits; q++) {
1017 int bit = (i >> qubits[q]) & 1;
1018 outcome += bit * (1 << q);
1019 }
1020 refProbs[outcome] += real(ref[i][i]);
1021 }
1022
1023 calcProbOfAllOutcomes(probs.data(), mat, qubits, numQubits);
1024 REQUIRE( areEqual(refProbs, probs.data()) );
1025 }
1026 SECTION( "unnormalised" ) {
1027
1028 QMatrix ref = getRandomQMatrix(1<<NUM_QUBITS);
1029 toQureg(mat, ref);
1030
1031 // prob is sum of diagonals which encode outcome
1032 for (size_t i=0; i<ref.size(); i++) {
1033 int outcome = 0;
1034 for (int q=0; q<numQubits; q++) {
1035 int bit = (i >> qubits[q]) & 1;
1036 outcome += bit * (1 << q);
1037 }
1038 refProbs[outcome] += real(ref[i][i]);
1039 }
1040
1041 calcProbOfAllOutcomes(probs.data(), mat, qubits, numQubits);
1042 REQUIRE( areEqual(refProbs, probs.data()) );
1043 }
1044 }
1045 }
1046 SECTION( "input validation" ) {
1047
1048 int numQubits = 3;
1049 int qubits[] = {0, 1, 2};
1050 qreal probs[8];
1051
1052 SECTION( "number of qubits" ) {
1053
1054 // too small
1055 numQubits = GENERATE( -1, 0 );
1056 REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), ContainsSubstring("specified number of target qubits") && ContainsSubstring("invalid.") );
1057
1058 // too big
1059 numQubits = NUM_QUBITS + 1;
1060 REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), ContainsSubstring("target qubits") && ContainsSubstring("exceeds the number of qubits in the Qureg") );
1061 }
1062 SECTION( "qubit indices" ) {
1063
1064 qubits[GENERATE_COPY(range(0,numQubits))] = GENERATE( -1, NUM_QUBITS );
1065 REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), ContainsSubstring("Invalid target qubit") );
1066 }
1067 SECTION( "repetition of qubits" ) {
1068
1069 qubits[GENERATE_COPY(1,2)] = qubits[0];
1070 REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), ContainsSubstring("qubits must be unique") );
1071 }
1072 }
1073 destroyQureg(vec);
1074 destroyQureg(mat);
1075}

◆ TEST_CASE() [20/110]

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

Definition at line 1084 of file test_calculations.cpp.

1084 {
1085
1086 Qureg vec = createForcedQureg(NUM_QUBITS);
1087 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1088
1089 SECTION( "correctness" ) {
1090
1091 int target = GENERATE( range(0,NUM_QUBITS) );
1092 int outcome = GENERATE( 0, 1 );
1093
1094 SECTION( "state-vector" ) {
1095
1096 SECTION( "normalised" ) {
1097
1098 QVector ref = getRandomStateVector(NUM_QUBITS);
1099 toQureg(vec, ref);
1100
1101 // prob is sum of |amp|^2 of amplitudes where target bit is outcome
1102 qreal prob = 0;
1103 for (size_t ind=0; ind<ref.size(); ind++) {
1104 int bit = (ind >> target) & 1; // target-th bit
1105 if (bit == outcome)
1106 prob += pow(abs(ref[ind]), 2);
1107 }
1108
1109 REQUIRE( calcProbOfOutcome(vec, target, outcome) == Approx(prob) );
1110 }
1111 SECTION( "unnormalised" ) {
1112
1113 QVector ref = getRandomQVector(1<<NUM_QUBITS);
1114 toQureg(vec, ref);
1115
1116 // prob is sum of |amp|^2 of amplitudes where target bit is outcome
1117 qreal prob = 0;
1118 for (size_t ind=0; ind<ref.size(); ind++) {
1119 int bit = (ind >> target) & 1; // target-th bit
1120 if (bit == outcome)
1121 prob += pow(abs(ref[ind]), 2);
1122 }
1123
1124 REQUIRE( calcProbOfOutcome(vec, target, outcome) == Approx(prob) );
1125 }
1126 }
1127 SECTION( "density-matrix" ) {
1128
1129 SECTION( "pure" ) {
1130
1131 // set mat to a random |r><r|
1132 QVector ref = getRandomStateVector(NUM_QUBITS);
1133 toQureg(mat, getKetBra(ref, ref));
1134
1135 // calc prob of the state-vector
1136 qreal prob = 0;
1137 for (size_t ind=0; ind<ref.size(); ind++) {
1138 int bit = (ind >> target) & 1; // target-th bit
1139 if (bit == outcome)
1140 prob += pow(abs(ref[ind]), 2);
1141 }
1142
1143 REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(prob) );
1144 }
1145 SECTION( "mixed" ) {
1146
1147 QMatrix ref = getRandomDensityMatrix(NUM_QUBITS);
1148 toQureg(mat, ref);
1149
1150 // prob is sum of diagonal amps (should be real) where target bit is outcome
1151 qcomp tr = 0;
1152 for (size_t ind=0; ind<ref.size(); ind++) {
1153 int bit = (ind >> target) & 1; // target-th bit
1154 if (bit == outcome)
1155 tr += ref[ind][ind];
1156 }
1157
1158 REQUIRE( imag(tr) == Approx(0).margin(REAL_EPS) );
1159
1160 REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(real(tr)) );
1161 }
1162 SECTION( "unnormalised" ) {
1163
1164 QMatrix ref = getRandomQMatrix(1<<NUM_QUBITS);
1165 toQureg(mat, ref);
1166
1167 // prob is (sum of real of diagonal amps where target bit is outcome)
1168 qreal tr = 0;
1169 for (size_t ind=0; ind<ref.size(); ind++) {
1170 int bit = (ind >> target) & 1; // target-th bit
1171 if (bit == outcome)
1172 tr += real(ref[ind][ind]);
1173 }
1174
1175 REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(tr) );
1176 }
1177 }
1178 }
1179 SECTION( "input validation" ) {
1180
1181 SECTION( "qubit indices" ) {
1182
1183 int target = GENERATE( -1, NUM_QUBITS );
1184 REQUIRE_THROWS_WITH( calcProbOfOutcome(vec, target, 0), ContainsSubstring("Invalid target qubit") );
1185 }
1186 SECTION( "outcome value" ) {
1187
1188 int outcome = GENERATE( -1, 2 );
1189 REQUIRE_THROWS_WITH( calcProbOfOutcome(vec, 0, outcome), ContainsSubstring("measurement outcome") && ContainsSubstring("invalid") );
1190 }
1191 }
1192 destroyQureg(vec);
1193 destroyQureg(mat);
1194}

◆ TEST_CASE() [21/110]

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

Definition at line 1202 of file test_calculations.cpp.

1202 {
1203
1204 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1205
1206 SECTION( "correctness" ) {
1207
1208 // perform the following random tests 10 times
1209 GENERATE( range(1,10) );
1210
1211 SECTION( "density-matrix" ) {
1212
1213 SECTION( "pure" ) {
1214
1215 // pure states have unity purity
1216 initZeroState(mat);
1217 REQUIRE( calcPurity(mat) == 1 );
1218
1219 // (try also a pure random L2-vector)
1220 QVector r1 = getRandomStateVector(NUM_QUBITS); // |r>
1221 QMatrix m1 = getKetBra(r1, r1); // |r><r|
1222 toQureg(mat, m1);
1223 REQUIRE( calcPurity(mat) == Approx(1) );
1224
1225 }
1226 SECTION( "mixed" ) {
1227
1228 // mixed states have 1/2^N < purity < 1
1229 QMatrix ref = getRandomDensityMatrix(NUM_QUBITS);
1230 toQureg(mat, ref);
1231 qreal purity = calcPurity(mat);
1232 REQUIRE( purity < 1 );
1233 REQUIRE( purity >= 1/pow(2.,NUM_QUBITS) );
1234
1235 // compare to Tr(rho^2)
1236 QMatrix prod = ref*ref;
1237 qreal tr = 0;
1238 for (size_t i=0; i<prod.size(); i++)
1239 tr += real(prod[i][i]);
1240 REQUIRE( purity == Approx(tr) );
1241 }
1242 SECTION( "unnormalised" ) {
1243
1244 // unphysical states give sum_{ij} |rho_ij|^2
1245 QMatrix ref = getRandomQMatrix(1<<NUM_QUBITS);
1246 qreal tot = 0;
1247 for (size_t i=0; i<ref.size(); i++)
1248 for (size_t j=0; j<ref.size(); j++)
1249 tot += pow(abs(ref[i][j]), 2);
1250
1251 toQureg(mat, ref);
1252 REQUIRE( calcPurity(mat) == Approx(tot) );
1253 }
1254 }
1255 }
1256 SECTION( "input validation" ) {
1257
1258 // in v4, this accepts state-vectors
1259
1260 // SECTION( "state-vector" ) {
1261
1262 // Qureg vec = createForcedQureg(NUM_QUBITS);
1263 // REQUIRE_THROWS_WITH( calcPurity(vec), ContainsSubstring("valid only for density matrices") );
1264 // destroyQureg(vec);
1265 // }
1266 }
1267 destroyQureg(mat);
1268}
qreal calcPurity(Qureg qureg)
void initZeroState(Qureg qureg)

◆ TEST_CASE() [22/110]

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

Definition at line 1276 of file test_calculations.cpp.

1276 {
1277
1278 Qureg vec = createForcedQureg(NUM_QUBITS);
1279 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1280
1281 SECTION( "correctness" ) {
1282
1283 SECTION( "state-vector" ) {
1284
1285 // normalised: prob(vec) = 1
1286 initPlusState(vec);
1287 REQUIRE( calcTotalProb(vec) == Approx(1) );
1288
1289 // zero norm: prob(vec) = 0
1290 initBlankState(vec);
1291 REQUIRE( calcTotalProb(vec) == 0 );
1292
1293 // random L2 state: prob(vec) = 1
1294 toQureg(vec, getRandomStateVector(NUM_QUBITS));
1295 REQUIRE( calcTotalProb(vec) == Approx(1) );
1296
1297 // unnormalised: prob(vec) = sum_i |vec_i|^2
1298 initDebugState(vec);
1299 QVector ref = toQVector(vec);
1300 qreal refProb = 0;
1301 for (size_t i=0; i<ref.size(); i++)
1302 refProb += pow(abs(ref[i]), 2);
1303 REQUIRE( calcTotalProb(vec) == Approx(refProb) );
1304 }
1305 SECTION( "density-matrix" ) {
1306
1307 // normalised: prob(mat) = 1
1308 initPlusState(mat);
1309 REQUIRE( calcTotalProb(mat) == Approx(1) );
1310
1311 // zero norm: prob(mat) = 0
1312 initBlankState(mat);
1313 REQUIRE( calcTotalProb(mat) == 0 );
1314
1315 // random density matrix: prob(mat) = 1
1316 toQureg(mat, getRandomDensityMatrix(NUM_QUBITS));
1317 REQUIRE( calcTotalProb(mat) == Approx(1) );
1318
1319 // unnormalised: prob(mat) = sum_i real(mat_{ii})
1320 initDebugState(mat);
1321 QMatrix ref = toQMatrix(mat);
1322 qreal refProb = 0;
1323 for (size_t i=0; i<ref.size(); i++)
1324 refProb += real(ref[i][i]);
1325 REQUIRE( calcTotalProb(mat) == Approx(refProb) );
1326 }
1327 }
1328 SECTION( "input validation" ) {
1329
1330 // no validation
1331 SUCCEED();
1332 }
1333 destroyQureg(vec);
1334 destroyQureg(mat);
1335}
qreal calcTotalProb(Qureg qureg)
void initPlusState(Qureg qureg)
void initBlankState(Qureg qureg)

◆ TEST_CASE() [23/110]

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

Definition at line 29 of file test_state_initialisations.cpp.

29 {
30
31 Qureg vec1 = createForcedQureg(NUM_QUBITS);
32 Qureg mat1 = createForcedDensityQureg(NUM_QUBITS);
33
34 SECTION( "correctness" ) {
35
36 SECTION( "state-vector" ) {
37
38 Qureg vec2 = createForcedQureg(NUM_QUBITS);
39
40 // make sure states start differently
41 initDebugState(vec1);
42 initBlankState(vec2);
43 REQUIRE( !areEqual(vec1, vec2) );
44
45 // make sure vec2 is changed
46 QVector copy1 = toQVector(vec1);
47 cloneQureg(vec2, vec1);
48 REQUIRE( areEqual(vec1, vec2) );
49
50 // make sure vec1 unaffected
51 REQUIRE( areEqual(vec1, copy1) );
52
53 destroyQureg(vec2);
54 }
55 SECTION( "density-matrix" ) {
56
57 Qureg mat2 = createForcedDensityQureg(NUM_QUBITS);
58
59 // make sure states start differently
60 initDebugState(mat1);
61 initBlankState(mat2);
62 REQUIRE( !areEqual(mat1, mat2) );
63
64 // make sure vec2 is changed
65 QMatrix copy1 = toQMatrix(mat1);
66 cloneQureg(mat2, mat1);
67 REQUIRE( areEqual(mat1, mat2) );
68
69 // make sure vec1 unaffected
70 REQUIRE( areEqual(mat1, copy1) );
71
72 destroyQureg(mat2);
73 }
74 }
75 SECTION( "input validation" ) {
76
77 SECTION( "qureg type" ) {
78
79 REQUIRE_THROWS_WITH( cloneQureg(mat1, vec1), ContainsSubstring("must both be statevectors, or both be density matrices") );
80 REQUIRE_THROWS_WITH( cloneQureg(vec1, mat1), ContainsSubstring("must both be statevectors, or both be density matrices") );
81 }
82 SECTION( "qureg dimensions" ) {
83
84 Qureg vec3 = createForcedQureg(vec1.numQubits + 1);
85 Qureg mat3 = createForcedDensityQureg(mat1.numQubits + 1);
86
87 REQUIRE_THROWS_WITH( cloneQureg(vec1, vec3), ContainsSubstring("different number of qubits") );
88 REQUIRE_THROWS_WITH( cloneQureg(mat1, mat3), ContainsSubstring("different number of qubits") );
89
90 destroyQureg(vec3);
91 destroyQureg(mat3);
92 }
93 }
94 destroyQureg(vec1);
95 destroyQureg(mat1);
96}

◆ TEST_CASE() [24/110]

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

Definition at line 33 of file test_gates.cpp.

33 {
34
35 Qureg vec = createForcedQureg(NUM_QUBITS);
36 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
37
38 SECTION( "correctness" ) {
39
40 int qubit = GENERATE( range(0,NUM_QUBITS) );
41 int outcome = GENERATE( 0, 1 );
42
43 // repeat these random tests 10 times on every qubit, and for both outcomes
44 GENERATE( range(0,10) );
45
46 SECTION( "state-vector" ) {
47
48 // use a random L2 state for every qubit & outcome
49 QVector vecRef = getRandomStateVector(NUM_QUBITS);
50 toQureg(vec, vecRef);
51
52 // calculate prob of outcome
53 qreal prob = 0;
54 for (size_t ind=0; ind<vecRef.size(); ind++) {
55 int bit = (ind >> qubit) & 1; // target-th bit
56 if (bit == outcome)
57 prob += pow(abs(vecRef[ind]), 2);
58 }
59
60 // renormalise by the outcome prob
61 for (size_t ind=0; ind<vecRef.size(); ind++) {
62 int bit = (ind >> qubit) & 1; // target-th bit
63 if (bit == outcome)
64 vecRef[ind] /= sqrt(prob);
65 else
66 vecRef[ind] = 0;
67 }
68
69 qreal res = collapseToOutcome(vec, qubit, outcome);
70 REQUIRE( res == Approx(prob) );
71 REQUIRE( areEqual(vec, vecRef) );
72 }
73 SECTION( "density-matrix" ) {
74
75 // use a random density matrix for every qubit & outcome
76 QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
77 toQureg(mat, matRef);
78
79 // prob is sum of diagonal amps (should be real) where target bit is outcome
80 qcomp tr = 0;
81 for (size_t ind=0; ind<matRef.size(); ind++) {
82 int bit = (ind >> qubit) & 1; // qubit-th bit
83 if (bit == outcome)
84 tr += matRef[ind][ind];
85 }
86 REQUIRE( imag(tr) == Approx(0).margin(REAL_EPS) );
87 qreal prob = real(tr);
88
89 // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
90 for (size_t r=0; r<matRef.size(); r++) {
91 for (size_t c=0; c<matRef.size(); c++) {
92 int ketBit = (c >> qubit) & 1;
93 int braBit = (r >> qubit) & 1;
94
95 if (ketBit == outcome && braBit == outcome)
96 matRef[r][c] /= prob;
97 else
98 matRef[r][c] = 0;
99 }
100 }
101
102 qreal res = collapseToOutcome(mat, qubit, outcome);
103 REQUIRE( res == Approx(prob) );
104 REQUIRE( areEqual(mat, matRef) );
105 }
106 }
107 SECTION( "input validation" ) {
108
109 SECTION( "qubit index" ) {
110
111 int qubit = GENERATE( -1, NUM_QUBITS );
112 int outcome = 0;
113 REQUIRE_THROWS_WITH( collapseToOutcome(mat, qubit, outcome), ContainsSubstring("Invalid target qubit") );
114 }
115 SECTION( "outcome value" ) {
116
117 int qubit = 0;
118 int outcome = GENERATE( -1, 2 );
119 REQUIRE_THROWS_WITH( collapseToOutcome(mat, qubit, outcome), ContainsSubstring("qubit measurement outcome") && ContainsSubstring("invalid") );
120 }
121 SECTION( "outcome probability" ) {
122
123 initZeroState(vec);
124 REQUIRE_THROWS_WITH( collapseToOutcome(vec, 0, 1), ContainsSubstring("impossibly unlikely") );
125 initClassicalState(vec, 1);
126 REQUIRE_THROWS_WITH( collapseToOutcome(vec, 0, 0), ContainsSubstring("impossibly unlikely") );
127 }
128 }
129 destroyQureg(vec);
130 destroyQureg(mat);
131}
void initClassicalState(Qureg qureg, qindex stateInd)

◆ TEST_CASE() [25/110]

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

Definition at line 51 of file test_unitaries.cpp.

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

◆ TEST_CASE() [26/110]

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

Definition at line 232 of file test_unitaries.cpp.

232 {
233
234 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
235
236 qcomp a = getRandomReal(-1,1) * expI(getRandomReal(0,2*M_PI));
237 qcomp b = sqrt(1-abs(a)*abs(a)) * expI(getRandomReal(0,2*M_PI));
238 Complex alpha; alpha.real = real(a); alpha.imag = imag(a);
239 Complex beta; beta.real = real(b); beta.imag = imag(b);
240 QMatrix op{
241 {a, -conj(b)},
242 {b, conj(a)}};
243
244 SECTION( "correctness" ) {
245
246 int target = GENERATE( range(0,NUM_QUBITS) );
247 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
248
249 SECTION( "state-vector" ) {
250
251 controlledCompactUnitary(quregVec, control, target, alpha, beta);
252 applyReferenceOp(refVec, control, target, op);
253 REQUIRE( areEqual(quregVec, refVec) );
254 }
255 SECTION( "density-matrix" ) {
256
257 controlledCompactUnitary(quregMatr, control, target, alpha, beta);
258 applyReferenceOp(refMatr, control, target, op);
259 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
260 }
261 }
262 SECTION( "input validation" ) {
263
264 SECTION( "control and target collision" ) {
265
266 int qb = 0;
267 REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, qb, qb, alpha, beta), ContainsSubstring("control and target") );
268 }
269 SECTION( "qubit indices" ) {
270
271 int qb = GENERATE( -1, NUM_QUBITS );
272 REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, qb, 0, alpha, beta), ContainsSubstring("Invalid control") );
273 REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, 0, qb, alpha, beta), ContainsSubstring("Invalid target") );
274 }
275 SECTION( "unitarity" ) {
276
277 // unitary when |a|^2 + |b^2 = 1
278 alpha.real=1; alpha.imag=2;
279 beta.real=3; beta.imag=4;
280 REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, 0, 1, alpha, beta), ContainsSubstring("unitary") );
281 }
282 }
283 CLEANUP_TEST( quregVec, quregMatr );
284}

◆ TEST_CASE() [27/110]

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

Definition at line 292 of file test_unitaries.cpp.

292 {
293
294 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
295
296 // figure out max-num targs (inclusive) allowed by hardware backend
297 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
298 if (maxNumTargs >= NUM_QUBITS)
299 maxNumTargs = NUM_QUBITS - 1; // make space for control qubit
300
301 SECTION( "correctness" ) {
302
303 // generate all possible qubit arrangements
304 int ctrl = GENERATE( range(0,NUM_QUBITS) );
305 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
306 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs, ctrl) );
307
308 // for each qubit arrangement, use a new random unitary
309 QMatrix op = getRandomUnitary(numTargs);
310 ComplexMatrixN matr = createComplexMatrixN(numTargs);
311 toComplexMatrixN(op, matr);
312
313 SECTION( "state-vector" ) {
314
315 controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr);
316 applyReferenceOp(refVec, ctrl, targs, numTargs, op);
317 REQUIRE( areEqual(quregVec, refVec) );
318 }
319 SECTION( "density-matrix" ) {
320
321 controlledMultiQubitUnitary(quregMatr, ctrl, targs, numTargs, matr);
322 applyReferenceOp(refMatr, ctrl, targs, numTargs, op);
323 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
324 }
325 destroyComplexMatrixN(matr);
326 }
327 SECTION( "input validation" ) {
328
329 SECTION( "number of targets" ) {
330
331 // there cannot be more targets than qubits in register
332 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrl is invalid)
333 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
334 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
335 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
336 syncCompMatr(matr);
337
338 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, targs, numTargs, matr), ContainsSubstring("number of target qubits"));
339
340 destroyComplexMatrixN(matr);
341 }
342 SECTION( "repetition in targets" ) {
343
344 int ctrl = 0;
345 int numTargs = 3;
346 int targs[] = {1,2,2};
347 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
348 syncCompMatr(matr);
349
350 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
351 destroyComplexMatrixN(matr);
352 }
353 SECTION( "control and target collision" ) {
354
355 int numTargs = 3;
356 int targs[] = {0,1,2};
357 int ctrl = targs[GENERATE_COPY( range(0,numTargs) )];
358 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
359 syncCompMatr(matr);
360
361 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("control and target"));
362 destroyComplexMatrixN(matr);
363 }
364 SECTION( "qubit indices" ) {
365
366 int ctrl = 0;
367 int numTargs = 3;
368 int targs[] = {1,2,3};
369 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
370 syncCompMatr(matr);
371
372 int inv = GENERATE( -1, NUM_QUBITS );
373 ctrl = inv;
374 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("Invalid control") );
375
376 ctrl = 0; // restore valid ctrl
377 targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
378 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("Invalid target") );
379
380 destroyComplexMatrixN(matr);
381 }
382 SECTION( "unitarity" ) {
383
384 int ctrl = 0;
385 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
386 ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
387 syncCompMatr(matr);
388
389 int targs[NUM_QUBITS];
390 for (int i=0; i<numTargs; i++)
391 targs[i] = i+1;
392
393 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("unitary") );
394 destroyComplexMatrixN(matr);
395 }
396 SECTION( "unitary creation" ) {
397
398 int numTargs = 3;
399 int targs[] = {1,2,3};
400
401 ComplexMatrixN matr;
402 matr.cpuElems = NULL;
403 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, targs, numTargs, matr), ContainsSubstring("created") );
404 }
405 SECTION( "unitary dimensions" ) {
406
407 int ctrl = 0;
408 int targs[2] = {1,2};
409 ComplexMatrixN matr = createComplexMatrixN(3);
410 syncCompMatr(matr);
411
412 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size"));
413 destroyComplexMatrixN(matr);
414 }
415 SECTION( "unitary fits in node" ) {
416
417 // pretend we have a very limited distributed memory (judged by matr size)
418 quregVec.isDistributed = 1;
419 quregVec.numAmpsPerNode = 1;
420 quregVec.logNumAmpsPerNode = 0;
421 int qb[] = {1,2};
422
423 ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
424 for (int i=0; i<4; i++)
425 matr.cpuElems[i][i] = 1;
426 syncCompMatr(matr);
427
428 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, qb, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
429 destroyComplexMatrixN(matr);
430 }
431 }
432 CLEANUP_TEST( quregVec, quregMatr );
433}

◆ TEST_CASE() [28/110]

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

Definition at line 441 of file test_unitaries.cpp.

441 {
442
443 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
444 QMatrix op{{0,1},{1,0}};
445
446 SECTION( "correctness" ) {
447
448 int target = GENERATE( range(0,NUM_QUBITS) );
449 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
450
451 SECTION( "state-vector" ) {
452
453 controlledNot(quregVec, control, target);
454 applyReferenceOp(refVec, control, target, op);
455 REQUIRE( areEqual(quregVec, refVec) );
456 }
457 SECTION( "density-matrix" ) {
458
459 controlledNot(quregMatr, control, target);
460 applyReferenceOp(refMatr, control, target, op);
461 REQUIRE( areEqual(quregMatr, refMatr) );
462 }
463 }
464 SECTION( "input validation" ) {
465
466 SECTION( "control and target collision" ) {
467
468 int qb = GENERATE( range(0,NUM_QUBITS) );
469 REQUIRE_THROWS_WITH( controlledNot(quregVec, qb, qb), ContainsSubstring("control and target") );
470 }
471 SECTION( "qubit indices" ) {
472
473 int qb = GENERATE( -1, NUM_QUBITS );
474 REQUIRE_THROWS_WITH( controlledNot(quregVec, qb, 0), ContainsSubstring("Invalid control") );
475 REQUIRE_THROWS_WITH( controlledNot(quregVec, 0, qb), ContainsSubstring("Invalid target") );
476 }
477 }
478 CLEANUP_TEST( quregVec, quregMatr );
479}

◆ TEST_CASE() [29/110]

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

Definition at line 487 of file test_unitaries.cpp.

487 {
488
489 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
490 QMatrix op{{0,-qcomp(0,1)},{qcomp(0,1),0}};
491
492 SECTION( "correctness" ) {
493
494 int target = GENERATE( range(0,NUM_QUBITS) );
495 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
496
497 SECTION( "state-vector" ) {
498
499 controlledPauliY(quregVec, control, target);
500 applyReferenceOp(refVec, control, target, op);
501 REQUIRE( areEqual(quregVec, refVec) );
502 }
503 SECTION( "density-matrix" ) {
504
505 controlledPauliY(quregMatr, control, target);
506 applyReferenceOp(refMatr, control, target, op);
507 REQUIRE( areEqual(quregMatr, refMatr) );
508 }
509 }
510 SECTION( "input validation" ) {
511
512 SECTION( "control and target collision" ) {
513
514 int qb = GENERATE( range(0,NUM_QUBITS) );
515 REQUIRE_THROWS_WITH( controlledPauliY(quregVec, qb, qb), ContainsSubstring("control and target") );
516 }
517 SECTION( "qubit indices" ) {
518
519 int qb = GENERATE( -1, NUM_QUBITS );
520 REQUIRE_THROWS_WITH( controlledPauliY(quregVec, qb, 0), ContainsSubstring("Invalid control") );
521 REQUIRE_THROWS_WITH( controlledPauliY(quregVec, 0, qb), ContainsSubstring("Invalid target") );
522 }
523 }
524 CLEANUP_TEST( quregVec, quregMatr );
525}

◆ TEST_CASE() [30/110]

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

Definition at line 533 of file test_unitaries.cpp.

533 {
534
535 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
536 QMatrix op{{1,0},{0,-1}};
537
538 SECTION( "correctness" ) {
539
540 int target = GENERATE( range(0,NUM_QUBITS) );
541 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
542
543 SECTION( "state-vector" ) {
544
545 controlledPhaseFlip(quregVec, control, target);
546 applyReferenceOp(refVec, control, target, op);
547 REQUIRE( areEqual(quregVec, refVec) );
548 }
549 SECTION( "density-matrix" ) {
550
551 controlledPhaseFlip(quregMatr, control, target);
552 applyReferenceOp(refMatr, control, target, op);
553 REQUIRE( areEqual(quregMatr, refMatr) );
554 }
555 }
556 SECTION( "input validation" ) {
557
558 // in v4, all arguments are considered targets, not controls
559
560 SECTION( "target collision" ) {
561
562 int qb = GENERATE( range(0,NUM_QUBITS) );
563 REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, qb, qb), ContainsSubstring("target qubits contained duplicates") );
564 }
565
566 SECTION( "target indices" ) {
567
568 int qb = GENERATE( -1, NUM_QUBITS );
569 REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, qb, 0), ContainsSubstring("Invalid target") );
570 REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, 0, qb), ContainsSubstring("Invalid target") );
571 }
572 }
573 CLEANUP_TEST( quregVec, quregMatr );
574}

◆ TEST_CASE() [31/110]

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

Definition at line 582 of file test_unitaries.cpp.

582 {
583
584 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
585 qreal param = getRandomReal(-2*M_PI, 2*M_PI);
586 QMatrix op{{1,0},{0,expI(param)}};
587
588 SECTION( "correctness" ) {
589
590 int target = GENERATE( range(0,NUM_QUBITS) );
591 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
592
593 SECTION( "state-vector" ) {
594
595 controlledPhaseShift(quregVec, control, target, param);
596 applyReferenceOp(refVec, control, target, op);
597 REQUIRE( areEqual(quregVec, refVec) );
598 }
599 SECTION( "density-matrix" ) {
600
601 controlledPhaseShift(quregMatr, control, target, param);
602 applyReferenceOp(refMatr, control, target, op);
603 REQUIRE( areEqual(quregMatr, refMatr) );
604 }
605 }
606 SECTION( "input validation" ) {
607
608 // in v4, all arguments are considered targets
609
610 SECTION( "target collision" ) {
611
612 int qb = GENERATE( range(0,NUM_QUBITS) );
613 REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, qb, qb, param), ContainsSubstring("target qubits contained duplicates") );
614 }
615 SECTION( "qubit indices" ) {
616
617 int qb = GENERATE( -1, NUM_QUBITS );
618 REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, qb, 0, param), ContainsSubstring("Invalid target") );
619 REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, 0, qb, param), ContainsSubstring("Invalid target") );
620 }
621 }
622 CLEANUP_TEST( quregVec, quregMatr );
623}

◆ TEST_CASE() [32/110]

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

Definition at line 631 of file test_unitaries.cpp.

631 {
632
633 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
634
635 // each test will use a random parameter and axis vector
636 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
637 Vector vec;
638 vec.x=getRandomReal(1,2);
639 vec.y=getRandomReal(-2,-1);
640 vec.z=getRandomReal(-1,1); // lazily avoiding (x,y,z)=0
641
642 // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
643 // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
644 qreal c = cos(param/2);
645 qreal s = sin(param/2);
646 qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
647 QMatrix op{{c - qcomp(0,1)*vec.z*s/m, -(vec.y + qcomp(0,1)*vec.x)*s/m},
648 {(vec.y - qcomp(0,1)*vec.x)*s/m, c + qcomp(0,1)*vec.z*s/m}};
649
650 SECTION( "correctness" ) {
651
652 int target = GENERATE( range(0,NUM_QUBITS) );
653 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
654
655 SECTION( "state-vector" ) {
656
657 controlledRotateAroundAxis(quregVec, control, target, param, vec);
658 applyReferenceOp(refVec, control, target, op);
659 REQUIRE( areEqual(quregVec, refVec) );
660 }
661 SECTION( "density-matrix" ) {
662
663 controlledRotateAroundAxis(quregMatr, control, target, param, vec);
664 applyReferenceOp(refMatr, control, target, op);
665 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
666 }
667 }
668 SECTION( "input validation" ) {
669
670 SECTION( "control and target collision" ) {
671
672 int qb = GENERATE( range(0,NUM_QUBITS) );
673 REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, qb, qb, param, vec), ContainsSubstring("control and target") );
674 }
675 SECTION( "qubit indices" ) {
676
677 int qb = GENERATE( -1, NUM_QUBITS );
678 REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, qb, 0, param, vec), ContainsSubstring("Invalid control") );
679 REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, 0, qb, param, vec), ContainsSubstring("Invalid target") );
680 }
681 SECTION( "zero rotation axis" ) {
682
683 vec.x=0; vec.y=0; vec.z=0;
684 REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, 0, 1, param, vec), ContainsSubstring("axis") && ContainsSubstring("zero") );
685 }
686 }
687 CLEANUP_TEST( quregVec, quregMatr );
688}

◆ TEST_CASE() [33/110]

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

Definition at line 696 of file test_unitaries.cpp.

696 {
697
698 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
699 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
700 QMatrix op{
701 {cos(param/2), -sin(param/2)*qcomp(0,1)},
702 {-sin(param/2)*qcomp(0,1), cos(param/2)}};
703
704 SECTION( "correctness" ) {
705
706 int target = GENERATE( range(0,NUM_QUBITS) );
707 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
708
709 SECTION( "state-vector" ) {
710
711 controlledRotateX(quregVec, control, target, param);
712 applyReferenceOp(refVec, control, target, op);
713 REQUIRE( areEqual(quregVec, refVec) );
714 }
715 SECTION( "density-matrix" ) {
716
717 controlledRotateX(quregMatr, control, target, param);
718 applyReferenceOp(refMatr, control, target, op);
719 REQUIRE( areEqual(quregMatr, refMatr) );
720 }
721 }
722 SECTION( "input validation" ) {
723
724 SECTION( "control and target collision" ) {
725
726 int qb = GENERATE( range(0,NUM_QUBITS) );
727 REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, qb, param), ContainsSubstring("control and target") );
728 }
729 SECTION( "qubit indices" ) {
730
731 int qb = GENERATE( -1, NUM_QUBITS );
732 REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, 0, param), ContainsSubstring("Invalid control") );
733 REQUIRE_THROWS_WITH( controlledRotateX(quregVec, 0, qb, param), ContainsSubstring("Invalid target") );
734 }
735 }
736 CLEANUP_TEST( quregVec, quregMatr );
737}

◆ TEST_CASE() [34/110]

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

Definition at line 745 of file test_unitaries.cpp.

745 {
746
747 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
748 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
749 QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
750
751 SECTION( "correctness" ) {
752
753 int target = GENERATE( range(0,NUM_QUBITS) );
754 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
755
756 SECTION( "state-vector" ) {
757
758 controlledRotateY(quregVec, control, target, param);
759 applyReferenceOp(refVec, control, target, op);
760 REQUIRE( areEqual(quregVec, refVec) );
761 }
762 SECTION( "density-matrix" ) {
763
764 controlledRotateY(quregMatr, control, target, param);
765 applyReferenceOp(refMatr, control, target, op);
766 REQUIRE( areEqual(quregMatr, refMatr, 4*REAL_EPS) );
767 }
768 }
769 SECTION( "input validation" ) {
770
771 SECTION( "control and target collision" ) {
772
773 int qb = GENERATE( range(0,NUM_QUBITS) );
774 REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, qb, param), ContainsSubstring("control and target") );
775 }
776 SECTION( "qubit indices" ) {
777
778 int qb = GENERATE( -1, NUM_QUBITS );
779 REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, 0, param), ContainsSubstring("Invalid control") );
780 REQUIRE_THROWS_WITH( controlledRotateY(quregVec, 0, qb, param), ContainsSubstring("Invalid target") );
781 }
782 }
783 CLEANUP_TEST( quregVec, quregMatr );
784}

◆ TEST_CASE() [35/110]

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

Definition at line 792 of file test_unitaries.cpp.

792 {
793
794 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
795 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
796 QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
797
798 SECTION( "correctness" ) {
799
800 int target = GENERATE( range(0,NUM_QUBITS) );
801 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
802
803 SECTION( "state-vector" ) {
804
805 controlledRotateZ(quregVec, control, target, param);
806 applyReferenceOp(refVec, control, target, op);
807 REQUIRE( areEqual(quregVec, refVec) );
808 }
809 SECTION( "density-matrix" ) {
810
811 controlledRotateZ(quregMatr, control, target, param);
812 applyReferenceOp(refMatr, control, target, op);
813 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
814 }
815 }
816 SECTION( "input validation" ) {
817
818 SECTION( "control and target collision" ) {
819
820 int qb = GENERATE( range(0,NUM_QUBITS) );
821 REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, qb, param), ContainsSubstring("control and target") );
822 }
823 SECTION( "qubit indices" ) {
824
825 int qb = GENERATE( -1, NUM_QUBITS );
826 REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, 0, param), ContainsSubstring("Invalid control") );
827 REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, 0, qb, param), ContainsSubstring("Invalid target") );
828 }
829 }
830 CLEANUP_TEST( quregVec, quregMatr );
831}

◆ TEST_CASE() [36/110]

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

Definition at line 839 of file test_unitaries.cpp.

839 {
840
841 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
842
843 // in distributed mode, each node must be able to fit all amps modified by unitary
844 REQUIRE( quregVec.numAmpsPerNode >= 4 );
845
846 // every test will use a unique random matrix
849
850 SECTION( "correctness" ) {
851
852 int targ1 = GENERATE( range(0,NUM_QUBITS) );
853 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
854 int control = GENERATE_COPY( filter([=](int c){ return c!=targ1 && c!=targ2; }, range(0,NUM_QUBITS)) );
855
856 SECTION( "state-vector" ) {
857
858 controlledTwoQubitUnitary(quregVec, control, targ1, targ2, matr);
859 applyReferenceOp(refVec, control, targ1, targ2, op);
860 REQUIRE( areEqual(quregVec, refVec) );
861 }
862 SECTION( "density-matrix" ) {
863
864 controlledTwoQubitUnitary(quregMatr, control, targ1, targ2, matr);
865 applyReferenceOp(refMatr, control, targ1, targ2, op);
866 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
867 }
868 }
869 SECTION( "input validation" ) {
870
871 SECTION( "repetition of targets" ) {
872 int targ = 0;
873 int ctrl = 1;
874 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ, targ, matr), ContainsSubstring("target") && ContainsSubstring("unique") );
875 }
876 SECTION( "control and target collision" ) {
877
878 int targ1 = 1;
879 int targ2 = 2;
880 int ctrl = GENERATE( 1,2 ); // catch2 bug; can't do GENERATE_COPY( targ1, targ2 )
881 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, targ2, matr), ContainsSubstring("control and target") );
882 }
883 SECTION( "qubit indices" ) {
884
885 // valid config
886 int ctrl = 0;
887 int targ1 = 1;
888 int targ2 = 2;
889
890 int qb = GENERATE( -1, NUM_QUBITS );
891 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, qb, targ1, targ2, matr), ContainsSubstring("Invalid control") );
892 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, qb, targ2, matr), ContainsSubstring("Invalid target") );
893 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, qb, matr), ContainsSubstring("Invalid target") );
894 }
895 SECTION( "unitarity" ) {
896
897 matr.real[0][0] = 999; // break matr unitarity
898 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), ContainsSubstring("unitary") );
899 }
900 SECTION( "unitary fits in node" ) {
901
902 // pretend we have a very limited distributed memory
903 quregVec.isDistributed = 1;
904 quregVec.numAmpsPerNode = 1;
905 quregVec.logNumAmpsPerNode = 0;
906
907 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
908 }
909 }
910 CLEANUP_TEST( quregVec, quregMatr );
911}

◆ TEST_CASE() [37/110]

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

Definition at line 919 of file test_unitaries.cpp.

919 {
920
921 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
924
925 SECTION( "correctness" ) {
926
927 int target = GENERATE( range(0,NUM_QUBITS) );
928 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
929
930 SECTION( "state-vector" ) {
931
932 controlledUnitary(quregVec, control, target, matr);
933 applyReferenceOp(refVec, control, target, op);
934 REQUIRE( areEqual(quregVec, refVec) );
935 }
936 SECTION( "density-matrix" ) {
937
938 controlledUnitary(quregMatr, control, target, matr);
939 applyReferenceOp(refMatr, control, target, op);
940 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
941 }
942 }
943 SECTION( "input validation" ) {
944
945 SECTION( "control and target collision" ) {
946
947 int qb = GENERATE( range(0,NUM_QUBITS) );
948 REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, qb, matr), ContainsSubstring("control and target") );
949 }
950 SECTION( "qubit indices" ) {
951
952 int qb = GENERATE( -1, NUM_QUBITS );
953 REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, 0, matr), ContainsSubstring("Invalid control") );
954 REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, qb, matr), ContainsSubstring("Invalid target") );
955 }
956 SECTION( "unitarity" ) {
957
958 matr.real[0][0] = 9999; // break unitarity
959 REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, 1, matr), ContainsSubstring("unitary") );
960 }
961 }
962 CLEANUP_TEST( quregVec, quregMatr );
963}

◆ TEST_CASE() [38/110]

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

Definition at line 85 of file test_data_structures.cpp.

85 {
86
87 SECTION( "state-vector" ) {
88
89 Qureg a = createForcedQureg(NUM_QUBITS);
91
92 // check properties are the same
93 REQUIRE( b.isMultithreaded == a.isMultithreaded );
94 REQUIRE( b.isGpuAccelerated == a.isGpuAccelerated );
95 REQUIRE( b.isDistributed == a.isDistributed );
96
97 REQUIRE( b.rank == a.rank );
98 REQUIRE( b.numNodes == a.numNodes );
99 REQUIRE( b.logNumNodes == a.logNumNodes );
100
101 REQUIRE( b.isDensityMatrix == a.isDensityMatrix );
102 REQUIRE( b.numQubits == a.numQubits );
103 REQUIRE( b.numAmps == a.numAmps );
104 REQUIRE( b.logNumAmps == a.logNumAmps );
105
106 REQUIRE( b.numAmpsPerNode == a.numAmpsPerNode );
107 REQUIRE( b.logNumAmpsPerNode == a.logNumAmpsPerNode );
108 REQUIRE( b.logNumColsPerNode == a.logNumColsPerNode );
109
110 // check amps the same (works for GPU and distributed)
111 REQUIRE( areEqual(a, b) );
112
113 destroyQureg(a);
114 destroyQureg(b);
115 }
116 SECTION( "density-matrix" ) {
117
118 Qureg a = createForcedDensityQureg(NUM_QUBITS);
119 Qureg b = createCloneQureg(a);
120
121 // check properties are the same
122 REQUIRE( b.isMultithreaded == a.isMultithreaded );
123 REQUIRE( b.isGpuAccelerated == a.isGpuAccelerated );
124 REQUIRE( b.isDistributed == a.isDistributed );
125
126 REQUIRE( b.rank == a.rank );
127 REQUIRE( b.numNodes == a.numNodes );
128 REQUIRE( b.logNumNodes == a.logNumNodes );
129
130 REQUIRE( b.isDensityMatrix == a.isDensityMatrix );
131 REQUIRE( b.numQubits == a.numQubits );
132 REQUIRE( b.numAmps == a.numAmps );
133 REQUIRE( b.logNumAmps == a.logNumAmps );
134
135 REQUIRE( b.numAmpsPerNode == a.numAmpsPerNode );
136 REQUIRE( b.logNumAmpsPerNode == a.logNumAmpsPerNode );
137 REQUIRE( b.logNumColsPerNode == a.logNumColsPerNode );
138
139 // check amps are the same (works for GPU and distributed)
140 REQUIRE( areEqual(a, b) );
141
142 destroyQureg(a);
143 destroyQureg(b);
144 }
145}
Qureg createCloneQureg(Qureg qureg)
Definition qureg.cpp:319

◆ TEST_CASE() [39/110]

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

Definition at line 153 of file test_data_structures.cpp.

153 {
154
155 SECTION( "correctness" ) {
156
157 int numQb = GENERATE( range(1,10+1) );
158 ComplexMatrixN m = createComplexMatrixN(numQb);
159
160 // ensure elems are created and initialised to 0
161 REQUIRE( areEqual(toQMatrix(m), getZeroMatrix(1<<numQb)) );
162
163 destroyComplexMatrixN(m);
164 }
165 SECTION( "input validation" ) {
166
167 SECTION( "number of qubits" ) {
168
169 int numQb = GENERATE( -1, 0 );
170 REQUIRE_THROWS_WITH( createComplexMatrixN(numQb), ContainsSubstring("must target one or more qubits") );
171 }
172 }
173}

◆ TEST_CASE() [40/110]

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

Definition at line 181 of file test_data_structures.cpp.

181 {
182
183 // must be at least one column per node
184 int minNumQb = calcLog2(getQuESTEnv().numNodes);
185 if (minNumQb <= 0)
186 minNumQb = 1;
187
188 SECTION( "correctness" ) {
189
190 // try 10 valid number of qubits
191 int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
192 Qureg reg = createForcedDensityQureg(numQb);
193
194 // ensure elems (CPU and/or GPU) are created, and reg begins in |0><0|
195 QMatrix ref = getZeroMatrix(1<<numQb);
196 ref[0][0] = 1; // |0><0|
197 REQUIRE( areEqual(reg, ref) );
198
199 destroyQureg(reg);
200 }
201 SECTION( "input validation") {
202
203 SECTION( "number of qubits" ) {
204
205 int numQb = GENERATE( -1, 0 );
206 REQUIRE_THROWS_WITH( createForcedDensityQureg(numQb), ContainsSubstring("must contain one or more qubits") );
207 }
208 SECTION( "number of amplitudes" ) {
209
210 // v4 does not consult QuESTEnv
211
212 // // use local QuESTEnv to safely modify
213 // QuESTEnv env = getQuESTEnv();
214
215 // too many amplitudes to store in type
216 int maxQb = (int) calcLog2(SIZE_MAX) / 2;
217 REQUIRE_THROWS_WITH( createForcedDensityQureg(maxQb+1),
218 ContainsSubstring("the density matrix would contain more amplitudes") && ContainsSubstring("than can be addressed by the qindex type") );
219
220 // it is non-trivial to force an invalid distribution
221 // in v4, since QuESTEnv arg is no longer consulted; we
222 // will reserve this input validation for the full tests
223
224 // /* n-qubit density matrix contains 2^(2n) amplitudes
225 // * so can be spread between at most 2^(2n) ranks
226 // */
227 // /* env.numNodes is an int, so maxQb must be capped at 16 for this
228 // * test to avoid an integer overflow when storing 2**(2*minQb) in it
229 // */
230 // maxQb = maxQb > 16 ? 16 : maxQb;
231 // int minQb = GENERATE_COPY( range(3,maxQb) );
232 // env.numNodes = (int) pow(2, 2*minQb);
233 // int numQb = GENERATE_COPY( range(1,minQb) );
234 // REQUIRE_THROWS_WITH( createForcedDensityQureg(numQb, env), ContainsSubstring("Too few qubits") );
235 }
236 SECTION( "available memory" ) {
237
238 /* there is no reliable way to force the malloc statements to
239 * fail, and hence trigger the matrixInit validation */
240 SUCCEED( );
241 }
242 }
243}

◆ TEST_CASE() [41/110]

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

Definition at line 251 of file test_data_structures.cpp.

251 {
252
253 QuESTEnv env = getQuESTEnv();
254
255 // must be at least one amplitude per node
256 int minNumQb = calcLog2(env.numNodes);
257 if (minNumQb == 0)
258 minNumQb = 1;
259
260 SECTION( "correctness" ) {
261
262 // try 10 valid number of qubits
263 int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
264 DiagonalOp op = createDiagonalOp(numQb, env);
265
266 // check properties are correct
267 REQUIRE( op.numQubits == numQb );
268 REQUIRE( op.numElemsPerNode == (1LL << numQb) / (op.isDistributed? env.numNodes : 1) );
269 REQUIRE( op.cpuElems != NULL );
270
271 // check all elements in CPU are zero
272 REQUIRE( areEqual(toQVector(op), QVector(1LL << numQb)) );
273
274 // (no concise way to check this for GPU)
275
276 destroyDiagonalOp(op, env);
277 }
278 SECTION( "input validation" ) {
279
280 SECTION( "number of qubits" ) {
281
282 int numQb = GENERATE( -1, 0 );
283 REQUIRE_THROWS_WITH( createDiagonalOp(numQb, env), ContainsSubstring("must target one or more qubits") );
284 }
285 SECTION( "number of elements" ) {
286
287 // too many amplitudes to store in type
288 int maxQb = (int) calcLog2(SIZE_MAX);
289 REQUIRE_THROWS_WITH( createDiagonalOp(maxQb+1, env),
290 ContainsSubstring("the matrix would contain more elements") && ContainsSubstring("than the maximum which can be addressed by the qindex type") );
291
292 // cannot test when there are too few elements, since the deprecated
293 // interface is redirecting to createFullStateDiagMatr which auto-deploys,
294 // and so simply automatically disables distribution
295
296 // /* env.numNodes is an int, so maxQb must be capped at 32 for this
297 // * test to avoid an integer overflow when storing 2**minQb in it
298 // */
299 // maxQb = maxQb > 32 ? 32 : maxQb;
300 // // too few amplitudes to distribute
301 // int minQb = GENERATE_COPY( range(2,maxQb) );
302 // env.numNodes = (int) pow(2, minQb);
303 // int numQb = GENERATE_COPY( range(1,minQb) );
304 // REQUIRE_THROWS_WITH( createDiagonalOp(numQb, env), ContainsSubstring("Too few qubits") && ContainsSubstring("distributed"));
305 }
306 SECTION( "available memory" ) {
307
308 /* there is no reliable way to force the malloc statements to
309 * fail, and hence trigger the diagonalOpInit validation */
310 SUCCEED( );
311 }
312 }
313}

◆ TEST_CASE() [42/110]

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

Definition at line 683 of file test_data_structures.cpp.

683 {
684
685 /* there is no meaningful way to test this */
686 SUCCEED( );
687}

◆ TEST_CASE() [43/110]

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

Definition at line 695 of file test_data_structures.cpp.

695 {
696
697 // we use createForcedQureg() in lieu of createQureg()
698 // to override the auto-deployer and force Qureg to use
699 // every available parallellisation method
700
701 // must be at least one amplitude per node
702 int minNumQb = calcLog2(getQuESTEnv().numNodes);
703 if (minNumQb == 0)
704 minNumQb = 1;
705
706 SECTION( "correctness" ) {
707
708 // try 10 valid number of qubits
709 int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
710 Qureg reg = createForcedQureg(numQb);
711
712 // ensure elems (CPU and/or GPU) are created, and reg begins in |0>
713 QVector ref = QVector(1<<numQb);
714 ref[0] = 1; // |0>
715 REQUIRE( areEqual(reg, ref) );
716
717 destroyQureg(reg);
718 }
719 SECTION( "input validation") {
720
721 SECTION( "number of qubits" ) {
722
723 int numQb = GENERATE( -1, 0 );
724 REQUIRE_THROWS_WITH( createForcedQureg(numQb), ContainsSubstring("must contain one or more qubits") );
725 }
726 SECTION( "number of amplitudes" ) {
727
728 // too many amplitudes to store in type
729 int maxQb = (int) calcLog2(SIZE_MAX);
730 REQUIRE_THROWS_WITH( createForcedQureg(maxQb+1),
731 ContainsSubstring("the statevector would contain more amplitudes") &&
732 ContainsSubstring("than the maximum which can be addressed by the qindex type") );
733
734 // it is non-trivial to force an invalid distribution
735 // in v4, since QuESTEnv arg is no longer consulted; we
736 // will reserve this input validation for the full tests
737
738 // // too few amplitudes to distribute
739 // /* env.numNodes is an int, so maxQb must be capped at 32 for this
740 // * test to avoid an integer overflow when storing 2**minQb in it
741 // */
742 // maxQb = maxQb > 32 ? 32 : maxQb;
743 // int minQb = GENERATE_COPY( range(2,maxQb) );
744 // env.numNodes = (int) pow(2, minQb);
745 // int numQb = GENERATE_COPY( range(1,minQb) );
746 // REQUIRE_THROWS_WITH( createForcedQureg(numQb, env), ContainsSubstring("Too few qubits") );
747 }
748 SECTION( "available memory" ) {
749
750 /* there is no reliable way to force the malloc statements to
751 * fail, and hence trigger the matrixInit validation */
752 SUCCEED( );
753 }
754 }
755}

◆ TEST_CASE() [44/110]

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

Definition at line 763 of file test_data_structures.cpp.

763 {
764
765 SECTION( "correctness" ) {
766
767 int numQb = GENERATE( range(1,10+1) );
768 SubDiagonalOp op = createSubDiagonalOp(numQb);
769
770 // ensure elems are created and initialised to 0
771 REQUIRE( areEqual(toQMatrix(op), getZeroMatrix(1<<numQb)) );
772
773 destroySubDiagonalOp(op);
774 }
775 SECTION( "input validation" ) {
776
777 SECTION( "number of qubits" ) {
778
779 int numQb = GENERATE( -1, 0 );
780 REQUIRE_THROWS_WITH( createSubDiagonalOp(numQb), ContainsSubstring("must target one or more qubits") );
781
782 numQb = 100;
783 REQUIRE_THROWS_WITH( createSubDiagonalOp(numQb),
784 ContainsSubstring("the matrix would contain more elements") &&
785 ContainsSubstring("than the maximum which can be addressed by the qindex type") );
786 }
787 }
788}

◆ TEST_CASE() [45/110]

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

Definition at line 796 of file test_data_structures.cpp.

796 {
797
798 SECTION( "correctness" ) {
799
800 /* there is no meaningful way to test this */
801 SUCCEED( );
802 }
803 SECTION( "input validation" ) {
804
805 SECTION( "matrix not created" ) {
806
807 /* this is an artificial test case since nothing in the QuEST API
808 * automatically sets un-initialised ComplexMatrixN fields to
809 * the NULL pointer.
810 */
811 ComplexMatrixN m;
812 m.cpuElems = NULL;
813
814 /* the error message is also somewhat unrelated, but oh well
815 */
816 REQUIRE_THROWS_WITH( destroyComplexMatrixN(m), ContainsSubstring("Invalid CompMatr") );
817 }
818 }
819}

◆ TEST_CASE() [46/110]

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

Definition at line 827 of file test_data_structures.cpp.

827 {
828
829 /* there is no meaningful way to test this */
830 SUCCEED( );
831}

◆ TEST_CASE() [47/110]

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

Definition at line 839 of file test_data_structures.cpp.

839 {
840
841 /* there is no meaningful way to test this.
842 * We e.g. cannot check that the pointers are NULL because
843 * they are not updated; this function passes the struct by value,
844 * not by reference. We also cannot reliably monitor the
845 * memory used in the heap at runtime.
846 */
847 SUCCEED( );
848}

◆ TEST_CASE() [48/110]

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

Definition at line 856 of file test_data_structures.cpp.

856 {
857
858 /* there is no meaningful way to test this */
859 SUCCEED( );
860}

◆ TEST_CASE() [49/110]

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

Definition at line 868 of file test_data_structures.cpp.

868 {
869
870 /* there is no meaningful way to test this.
871 * We e.g. cannot check that the pointers are NULL because
872 * they are not updated; this function passes the struct by value,
873 * not by reference. We also cannot reliably monitor the
874 * memory used in the heap at runtime.
875 */
876 SUCCEED( );
877}

◆ TEST_CASE() [50/110]

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

Definition at line 885 of file test_data_structures.cpp.

885 {
886
887 /* there is no meaningful way to test this */
888 SUCCEED( );
889}

◆ TEST_CASE() [51/110]

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

Definition at line 104 of file test_unitaries.cpp.

104 {
105
106 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
107
108 SECTION( "correctness" ) {
109
110 // generate all possible targets
111 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
112 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
113
114 // initialise a random unitary diagonal op
115 SubDiagonalOp op = createSubDiagonalOp(numTargs);
116 for (long long int i=0; i<op.numElems; i++) {
117 qcomp elem = getRandomComplex();
118 elem /= abs(elem);
119 op.cpuElems[i] = elem;
120 }
121 syncDiagMatr(op);
122
123 QMatrix opMatr = toQMatrix(op);
124
125 SECTION( "state-vector" ) {
126
127 diagonalUnitary(quregVec, targs, numTargs, op);
128 applyReferenceOp(refVec, targs, numTargs, opMatr);
129 REQUIRE( areEqual(quregVec, refVec) );
130 }
131 SECTION( "density-matrix" ) {
132
133 diagonalUnitary(quregMatr, targs, numTargs, op);
134 applyReferenceOp(refMatr, targs, numTargs, opMatr);
135 REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
136 }
137
138 destroySubDiagonalOp(op);
139 }
140 SECTION( "input validation" ) {
141
142 SECTION( "diagonal dimension" ) {
143
144 int numTargs = 3;
145 SubDiagonalOp op = createSubDiagonalOp(numTargs);
146 syncDiagMatr(op);
147
148 int badNumTargs = GENERATE_COPY( numTargs-1, numTargs+1 );
149 int badTargs[NUM_QUBITS+1];
150 for (int i=0; i<NUM_QUBITS+1; i++)
151 badTargs[i]=i;
152
153 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, badTargs, badNumTargs, op), ContainsSubstring("matrix has an inconsistent size") );
154 destroySubDiagonalOp(op);
155 }
156 SECTION( "number of targets" ) {
157
158 // make too many targets (which are otherwise valid)
159 SubDiagonalOp badOp = createSubDiagonalOp(NUM_QUBITS + 1);
160 int targs[NUM_QUBITS + 1];
161 for (int t=0; t<badOp.numQubits; t++)
162 targs[t] = t;
163 for (int i=0; i<badOp.numElems; i++)
164 badOp.cpuElems[i] = 1;
165 syncDiagMatr(badOp);
166
167 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, badOp.numQubits, badOp), ContainsSubstring("number of target qubits") );
168 destroySubDiagonalOp(badOp);
169 }
170 SECTION( "repetition in targets" ) {
171
172 // make a valid unitary diagonal op
173 SubDiagonalOp op = createSubDiagonalOp(3);
174 for (int i=0; i<op.numElems; i++)
175 op.cpuElems[i] = 1;
176 syncDiagMatr(op);
177
178 // make a repetition in the target list
179 int targs[] = {2,1,2};
180
181 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, op.numQubits, op), ContainsSubstring("target qubits contained duplicates") );
182 destroySubDiagonalOp(op);
183 }
184 SECTION( "qubit indices" ) {
185
186 // make a valid unitary diagonal op
187 SubDiagonalOp op = createSubDiagonalOp(3);
188 for (int i=0; i<op.numElems; i++)
189 op.cpuElems[i] = 1;
190 syncDiagMatr(op);
191
192 int targs[] = {0,1,2};
193
194 // make each target in-turn invalid
195 int badIndex = GENERATE( range(0,3) );
196 int badValue = GENERATE( -1, NUM_QUBITS );
197 targs[badIndex] = badValue;
198
199 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, op.numQubits, op), ContainsSubstring("Invalid target qubit") );
200 destroySubDiagonalOp(op);
201 }
202 SECTION( "unitarity" ) {
203
204 // make a valid unitary diagonal op
205 SubDiagonalOp op = createSubDiagonalOp(3);
206 int targs[] = {0,1,2};
207 for (int i=0; i<op.numElems; i++)
208 op.cpuElems[i] = 1;
209 syncDiagMatr(op);
210
211 // break unitarity via reals
212 op.cpuElems[2] = -9999.1;
213 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, op.numQubits, op), ContainsSubstring("unitary") );
214
215 // restore reals and break unitarity via imag
216 op.cpuElems[2] = 1;
217 op.cpuElems[3] = -9999.5;
218 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, op.numQubits, op), ContainsSubstring("unitary") );
219
220 destroySubDiagonalOp(op);
221 }
222 }
223 CLEANUP_TEST( quregVec, quregMatr );
224}

◆ TEST_CASE() [52/110]

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

Definition at line 1343 of file test_calculations.cpp.

1343 {
1344
1345 Qureg vec = createForcedQureg(NUM_QUBITS);
1346
1347 SECTION( "correctness" ) {
1348
1349 SECTION( "state-vector" ) {
1350
1351 initDebugState(vec);
1352 QVector ref = toQVector(vec);
1353
1354 int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1355 qcomp amp = getAmp(vec,ind);
1356 REQUIRE( amp == ref[ind] );
1357 }
1358 }
1359 SECTION( "input validation" ) {
1360
1361 SECTION( "state index" ) {
1362
1363 int ind = GENERATE( -1, 1<<NUM_QUBITS );
1364 REQUIRE_THROWS_WITH( getAmp(vec,ind), ContainsSubstring("Basis state index") && ContainsSubstring("invalid") );
1365 }
1366 SECTION( "density-matrix" ) {
1367
1368 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1369 REQUIRE_THROWS_WITH( getAmp(mat,0), ContainsSubstring("Expected a statevector Qureg but received a density matrix") );
1370 destroyQureg(mat);
1371 }
1372 }
1373 destroyQureg(vec);
1374}

◆ TEST_CASE() [53/110]

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

Definition at line 1382 of file test_calculations.cpp.

1382 {
1383
1384 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1385
1386 SECTION( "correctness" ) {
1387
1388 SECTION( "density-matrix" ) {
1389
1390 initDebugState(mat);
1391 QMatrix ref = toQMatrix(mat);
1392
1393 int row = GENERATE( range(0,1<<NUM_QUBITS) );
1394 int col = GENERATE( range(0,1<<NUM_QUBITS) );
1395
1396 qcomp amp = getDensityAmp(mat,row,col);
1397 REQUIRE( amp == ref[row][col] );
1398 }
1399 }
1400 SECTION( "input validation" ) {
1401
1402 SECTION( "state index" ) {
1403
1404 int ind = GENERATE( -1, 1<<NUM_QUBITS );
1405 REQUIRE_THROWS_WITH( getDensityAmp(mat,ind,0), ContainsSubstring("The row and column indices") && ContainsSubstring("invalid") );
1406 REQUIRE_THROWS_WITH( getDensityAmp(mat,0,ind), ContainsSubstring("The row and column indices") && ContainsSubstring("invalid") );
1407
1408 }
1409 SECTION( "state-vector" ) {
1410
1411 Qureg vec = createForcedQureg(NUM_QUBITS);
1412 REQUIRE_THROWS_WITH( getDensityAmp(vec,0,0), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
1413 destroyQureg(vec);
1414 }
1415 }
1416 destroyQureg(mat);
1417}

◆ TEST_CASE() [54/110]

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

Definition at line 1425 of file test_calculations.cpp.

1425 {
1426
1427 Qureg vec = createForcedQureg(NUM_QUBITS);
1428
1429 SECTION( "correctness" ) {
1430
1431 SECTION( "state-vector" ) {
1432
1433 initDebugState(vec);
1434 QVector ref = toQVector(vec);
1435
1436 int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1437 REQUIRE( getImagAmp(vec,ind) == imag(ref[ind]) );
1438 }
1439 }
1440 SECTION( "input validation" ) {
1441
1442 SECTION( "state index" ) {
1443
1444 int ind = GENERATE( -1, 1<<NUM_QUBITS );
1445 REQUIRE_THROWS_WITH( getImagAmp(vec,ind), ContainsSubstring("Basis state index") && ContainsSubstring("invalid") );
1446 }
1447 SECTION( "density-matrix" ) {
1448
1449 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1450 REQUIRE_THROWS_WITH( getImagAmp(mat,0), ContainsSubstring("Expected a statevector Qureg but received a density matrix") );
1451 destroyQureg(mat);
1452 }
1453 }
1454 destroyQureg(vec);
1455}

◆ TEST_CASE() [55/110]

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

Definition at line 1463 of file test_calculations.cpp.

1463 {
1464
1465 SECTION( "correctness" ) {
1466
1467 // test >= NUM_QUBITS so as not to limit distribution size
1468 int numQb = GENERATE( range(NUM_QUBITS, NUM_QUBITS+10) );
1469
1470 SECTION( "state-vector" ) {
1471
1472 Qureg vec = createForcedQureg(numQb);
1473 REQUIRE( getNumAmps(vec) == (1<<numQb) );
1474 destroyQureg(vec);
1475 }
1476 }
1477
1478 // in v4, argument can be a density matrix (return total num amps)
1479
1480 // SECTION( "input validation" ) {
1481
1482 // SECTION( "density-matrix" ) {
1483 // Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1484 // REQUIRE_THROWS_WITH( getNumAmps(mat), ContainsSubstring("Expected a statevector Qureg but received a density matrix") );
1485 // destroyQureg(mat);
1486 // }
1487 // }
1488}

◆ TEST_CASE() [56/110]

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

Definition at line 1496 of file test_calculations.cpp.

1496 {
1497
1498 SECTION( "correctness" ) {
1499
1500 // test >= NUM_QUBITS so as not to limit distribution size
1501 int numQb = GENERATE( range(NUM_QUBITS, NUM_QUBITS+10) );
1502
1503 SECTION( "state-vector" ) {
1504
1505 Qureg vec = createForcedQureg(numQb);
1506 REQUIRE( getNumQubits(vec) == numQb );
1507 destroyQureg(vec);
1508 }
1509 SECTION( "density-matrix" ) {
1510
1511 // density matrices use square as much memory; we must be careful not to seg-fault!
1512 if (2*numQb > 25)
1513 numQb = 13; // max size
1514
1515 Qureg mat = createForcedDensityQureg(numQb);
1516 REQUIRE( getNumQubits(mat) == numQb );
1517 destroyQureg(mat);
1518 }
1519 }
1520 SECTION( "input validation" ) {
1521
1522 // no validation
1523 SUCCEED();
1524 }
1525}

◆ TEST_CASE() [57/110]

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

Definition at line 1533 of file test_calculations.cpp.

1533 {
1534
1535 Qureg vec = createForcedQureg(NUM_QUBITS);
1536
1537 SECTION( "correctness" ) {
1538
1539 SECTION( "state-vector" ) {
1540
1541 initDebugState(vec);
1542 QVector ref = toQVector(vec);
1543
1544 int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1545 qreal refCalc = pow(abs(ref[ind]), 2);
1546 REQUIRE( getProbAmp(vec,ind) == Approx(refCalc) );
1547 }
1548 }
1549 SECTION( "input validation" ) {
1550
1551 SECTION( "state index" ) {
1552
1553 int ind = GENERATE( -1, 1<<NUM_QUBITS );
1554 REQUIRE_THROWS_WITH( getProbAmp(vec,ind), ContainsSubstring("Basis state index") && ContainsSubstring("invalid") );
1555 }
1556
1557 // in v4, this redirects to calcProbOfBasisState() which accepts
1558 // both statevectors and density matrices
1559
1560 // SECTION( "density-matrix" ) {
1561
1562 // Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1563 // REQUIRE_THROWS_WITH( getProbAmp(mat,0), ContainsSubstring("Expected a statevector Qureg but received a density matrix") );
1564 // destroyQureg(mat);
1565 // }
1566 }
1567 destroyQureg(vec);
1568}

◆ TEST_CASE() [58/110]

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

Definition at line 1576 of file test_calculations.cpp.

1576 {
1577
1578 Qureg vec = createForcedQureg(NUM_QUBITS);
1579
1580 SECTION( "correctness" ) {
1581
1582 SECTION( "state-vector" ) {
1583
1584 initDebugState(vec);
1585 QVector ref = toQVector(vec);
1586
1587 int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1588 REQUIRE( getRealAmp(vec,ind) == real(ref[ind]) );
1589 }
1590 }
1591 SECTION( "input validation" ) {
1592
1593 SECTION( "state index" ) {
1594
1595 int ind = GENERATE( -1, 1<<NUM_QUBITS );
1596 REQUIRE_THROWS_WITH( getRealAmp(vec,ind), ContainsSubstring("Basis state index") && ContainsSubstring("invalid") );
1597 }
1598 SECTION( "density-matrix" ) {
1599
1600 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
1601 REQUIRE_THROWS_WITH( getRealAmp(mat,0), ContainsSubstring("Expected a statevector Qureg but received a density matrix") );
1602 destroyQureg(mat);
1603 }
1604 }
1605 destroyQureg(vec);
1606}

◆ TEST_CASE() [59/110]

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

Definition at line 971 of file test_unitaries.cpp.

971 {
972
973 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
974 qreal a = 1/sqrt(2);
975 QMatrix op{{a,a},{a,-a}};
976
977 SECTION( "correctness" ) {
978
979 int target = GENERATE( range(0,NUM_QUBITS) );
980
981 SECTION( "state-vector ") {
982
983 hadamard(quregVec, target);
984 applyReferenceOp(refVec, target, op);
985 REQUIRE( areEqual(quregVec, refVec) );
986 }
987 SECTION( "density-matrix" ) {
988
989 hadamard(quregMatr, target);
990 applyReferenceOp(refMatr, target, op);
991 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
992 }
993 }
994 SECTION( "input validation" ) {
995
996 SECTION( "qubit indices" ) {
997
998 int target = GENERATE( -1, NUM_QUBITS );
999 REQUIRE_THROWS_WITH( hadamard(quregVec, target), ContainsSubstring("Invalid target") );
1000 }
1001 }
1002 CLEANUP_TEST( quregVec, quregMatr );
1003}

◆ TEST_CASE() [60/110]

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

Definition at line 300 of file test_state_initialisations.cpp.

300 {
301
302 Qureg vec = createForcedQureg(NUM_QUBITS);
303 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
304
305 // create random (unnormalised) vector
306 QVector vecRef = getRandomQVector(1<<NUM_QUBITS);
307
308 SECTION( "correctness" ) {
309
310 SECTION( "state-vector" ) {
311
312 initArbitraryPureState(vec, vecRef.data());
313
314 REQUIRE( areEqual(vec, vecRef) );
315 }
316 SECTION( "density-matrix" ) {
317
318 initArbitraryPureState(mat, vecRef.data());
319
320 // matRef = |vecRef><vecRef|
321 QMatrix matRef = getZeroMatrix(vecRef.size());
322 for (size_t r=0; r<vecRef.size(); r++)
323 for (size_t c=0; c<vecRef.size(); c++)
324 matRef[r][c] = vecRef[r] * conj(vecRef[c]);
325
326 REQUIRE( areEqual(mat, matRef) );
327 }
328 }
329 destroyQureg(vec);
330 destroyQureg(mat);
331}
void initArbitraryPureState(Qureg qureg, qcomp *amps)

◆ TEST_CASE() [61/110]

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

Definition at line 104 of file test_state_initialisations.cpp.

104 {
105
106 Qureg vec = createForcedQureg(NUM_QUBITS);
107 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
108
109 SECTION( "correctness" ) {
110
111 SECTION( "state-vector" ) {
112
113 initBlankState(vec);
114 REQUIRE( areEqual(vec, QVector(1<<NUM_QUBITS)) );
115 }
116 SECTION( "density-matrix" ) {
117
118 initBlankState(mat);
119 REQUIRE( areEqual(mat, getZeroMatrix(1<<NUM_QUBITS)) );
120 }
121 }
122 SECTION( "input validation" ) {
123
124 // no user validation
125 SUCCEED( );
126 }
127 destroyQureg(vec);
128 destroyQureg(mat);
129}

◆ TEST_CASE() [62/110]

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

Definition at line 137 of file test_state_initialisations.cpp.

137 {
138
139 Qureg vec = createForcedQureg(NUM_QUBITS);
140 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
141
142 SECTION( "correctness" ) {
143
144 int numInds = (1<<NUM_QUBITS);
145 int ind = GENERATE_COPY( range(0,numInds) );
146
147 SECTION( "state-vector" ) {
148
149 initClassicalState(vec, ind);
150 QVector vecRef = QVector(1<<NUM_QUBITS);
151 vecRef[ind] = 1;
152 REQUIRE( areEqual(vec, vecRef) );
153 }
154 SECTION( "density-matrix" ) {
155
156 initClassicalState(mat, ind);
157 QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
158 matRef[ind][ind] = 1;
159 REQUIRE( areEqual(mat, matRef) );
160 }
161 }
162 SECTION( "input validation" ) {
163
164 SECTION( "state index" ) {
165
166 int ind = GENERATE( -1, (1<<NUM_QUBITS) );
167 REQUIRE_THROWS_WITH( initClassicalState(vec, ind), ContainsSubstring("Basis state index") );
168 }
169 }
170 destroyQureg(vec);
171 destroyQureg(mat);
172}

◆ TEST_CASE() [63/110]

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

Definition at line 180 of file test_state_initialisations.cpp.

180 {
181
182 Qureg vec = createForcedQureg(NUM_QUBITS);
183 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
184
185 SECTION( "correctness" ) {
186
187 SECTION( "state-vector" ) {
188
189 // |+> = 1/sqrt(N^2) sum_i |i>
190 // = 1/sqrt(N^2) {1, ..., 1}
191 initPlusState(vec);
192 QVector vecRef = QVector(1<<NUM_QUBITS);
193 for (size_t i=0; i<vecRef.size(); i++)
194 vecRef[i] = 1./sqrt(pow(2,NUM_QUBITS));
195 REQUIRE( areEqual(vec, vecRef) );
196 }
197 SECTION( "density-matrix" ) {
198
199 // |+><+| = 1/sqrt(N^2) sum_i |i> 1/sqrt(N^2) sum_j <j|
200 // = 1/(N^2) sum_{ij} |i><j|
201 // = 1/(N^2) {{1, ..., 1}, ...}
202 initPlusState(mat);
203 QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
204 for (size_t i=0; i<matRef.size(); i++)
205 for (size_t j=0; j<matRef.size(); j++)
206 matRef[i][j] = 1./pow(2, NUM_QUBITS);
207 REQUIRE( areEqual(mat, matRef) );
208 }
209 }
210 SECTION( "input validation" ) {
211
212 // no user validation
213 SUCCEED( );
214 }
215 destroyQureg(vec);
216 destroyQureg(mat);
217}

◆ TEST_CASE() [64/110]

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

Definition at line 225 of file test_state_initialisations.cpp.

225 {
226
227 Qureg vec1 = createForcedQureg(NUM_QUBITS);
228 Qureg mat1 = createForcedDensityQureg(NUM_QUBITS);
229
230 SECTION( "correctness" ) {
231
232 SECTION( "state-vector" ) {
233
234 /* state-vector version just performs cloneQureg */
235
236 Qureg vec2 = createForcedQureg(NUM_QUBITS);
237
238 // make sure states start differently
239 initDebugState(vec1);
240 initBlankState(vec2);
241 REQUIRE( !areEqual(vec1, vec2) );
242
243 // make sure vec2 is overwritten with vec1
244 QVector copy1 = toQVector(vec1);
245 initPureState(vec2, vec1);
246 REQUIRE( areEqual(vec1, vec2) );
247
248 // make sure vec1 was not modified
249 REQUIRE( areEqual(vec1, copy1) );
250
251 destroyQureg(vec2);
252 }
253 SECTION( "density-matrix" ) {
254
255 /* density matrix version initialises matrix in |pure><pure| */
256
257 initDebugState(vec1); // |vec1> = sum_i a_i |i>
258 QVector copy1 = toQVector(vec1);
259
260 // make sure mat1 is modified correctly
261 initBlankState(mat1);
262 initPureState(mat1, vec1); // mat1 = |vec1><vec1| = sum_{ij} a_i a_j* |i><j|
263
264 QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
265 for (size_t i=0; i<matRef.size(); i++)
266 for (size_t j=0; j<matRef.size(); j++)
267 matRef[i][j] = copy1[i] * conj(copy1[j]);
268 REQUIRE( areEqual(mat1, matRef) );
269
270 // make sure vec1 was not modified
271 REQUIRE( areEqual(vec1, copy1) );
272 }
273 }
274 SECTION( "input validation" ) {
275
276 SECTION( "qureg types" ) {
277
278 // density matrix as second arg is illegal (regardless of first arg)
279 REQUIRE_THROWS_WITH( initPureState(vec1, mat1), ContainsSubstring("(the second argument) must be a statevector") );
280 REQUIRE_THROWS_WITH( initPureState(mat1, mat1), ContainsSubstring("(the second argument) must be a statevector") );
281 }
282 SECTION( "qureg dimensions" ) {
283
284 Qureg vec2 = createForcedQureg(NUM_QUBITS + 1);
285 REQUIRE_THROWS_WITH( initPureState(vec1, vec2), ContainsSubstring("differing number of qubits") );
286 REQUIRE_THROWS_WITH( initPureState(mat1, vec2), ContainsSubstring("differing number of qubits") );
287 destroyQureg(vec2);
288 }
289 }
290 destroyQureg(vec1);
291 destroyQureg(mat1);
292}
void initPureState(Qureg qureg, Qureg pure)

◆ TEST_CASE() [65/110]

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

Definition at line 339 of file test_state_initialisations.cpp.

339 {
340
341 Qureg vec = createForcedQureg(NUM_QUBITS);
342 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
343
344 SECTION( "correctness" ) {
345
346 SECTION( "state-vector" ) {
347
348 initBlankState(vec);
349 initZeroState(vec);
350
351 QVector refVec = QVector(vec.numAmps);
352 refVec[0] = 1;
353 REQUIRE( areEqual(vec, refVec) );
354 }
355 SECTION( "density-matrix" ) {
356
357 initBlankState(mat);
358 initZeroState(mat);
359
360 QMatrix refMat = getZeroMatrix(1<<mat.numQubits);
361 refMat[0][0] = 1;
362 REQUIRE( areEqual(mat, refMat) );
363 }
364 }
365 SECTION( "input validation" ) {
366
367 // no input validation
368 SUCCEED( );
369 }
370 destroyQureg(vec);
371 destroyQureg(mat);
372}

◆ TEST_CASE() [66/110]

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

Definition at line 139 of file test_gates.cpp.

139 {
140
141 Qureg vec = createForcedQureg(NUM_QUBITS);
142 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
143
144 SECTION( "correctness" ) {
145
146 int qubit = GENERATE( range(0,NUM_QUBITS) );
147
148 // repeat these random tests 10 times on every qubit
149 GENERATE( range(0,10) );
150
151 SECTION( "state-vector" ) {
152
153 QVector vecRef = getRandomStateVector(NUM_QUBITS);
154 toQureg(vec, vecRef);
155
156 int outcome = measure(vec, qubit);
157 REQUIRE( (outcome == 0 || outcome == 1) );
158
159 // calculate prob of this outcome
160 qreal prob = 0;
161 for (size_t ind=0; ind<vecRef.size(); ind++) {
162 int bit = (ind >> qubit) & 1; // target-th bit
163 if (bit == outcome)
164 prob += pow(abs(vecRef[ind]), 2);
165 }
166
167 REQUIRE( prob > REAL_EPS );
168
169 // renormalise by the outcome prob
170 for (size_t ind=0; ind<vecRef.size(); ind++) {
171 int bit = (ind >> qubit) & 1; // target-th bit
172 if (bit == outcome)
173 vecRef[ind] /= sqrt(prob);
174 else
175 vecRef[ind] = 0;
176 }
177 REQUIRE( areEqual(vec, vecRef) );
178 }
179 SECTION( "density-matrix" ) {
180
181 QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
182 toQureg(mat, matRef);
183
184 int outcome = measure(mat, qubit);
185 REQUIRE( (outcome == 0 || outcome == 1) );
186
187 // compute prob of this outcome
188 qreal prob = 0;
189 for (size_t ind=0; ind<matRef.size(); ind++) {
190 int bit = (ind >> qubit) & 1; // qubit-th bit
191 if (bit == outcome)
192 prob += real(matRef[ind][ind]);
193 }
194
195 REQUIRE( prob > REAL_EPS );
196
197 // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
198 for (size_t r=0; r<matRef.size(); r++) {
199 for (size_t c=0; c<matRef.size(); c++) {
200 int ketBit = (c >> qubit) & 1;
201 int braBit = (r >> qubit) & 1;
202
203 if (ketBit == outcome && braBit == outcome)
204 matRef[r][c] /= prob;
205 else
206 matRef[r][c] = 0;
207 }
208 }
209
210 REQUIRE( areEqual(mat, matRef) );
211 }
212 }
213 SECTION( "input validation" ) {
214
215 SECTION( "qubit index" ) {
216
217 int qubit = GENERATE( -1, NUM_QUBITS );
218 REQUIRE_THROWS_WITH( measure(vec, qubit), ContainsSubstring("Invalid target qubit") );
219 }
220 }
221 destroyQureg(vec);
222 destroyQureg(mat);
223}

◆ TEST_CASE() [67/110]

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

Definition at line 231 of file test_gates.cpp.

231 {
232
233 Qureg vec = createForcedQureg(NUM_QUBITS);
234 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
235
236 SECTION( "correctness" ) {
237
238 int qubit = GENERATE( range(0,NUM_QUBITS) );
239
240 // repeat these random tests 10 times on every qubit
241 GENERATE( range(0,10) );
242
243 SECTION( "state-vector" ) {
244
245 QVector vecRef = getRandomStateVector(NUM_QUBITS);
246 toQureg(vec, vecRef);
247
248 qreal res;
249 int outcome = measureWithStats(vec, qubit, &res);
250 REQUIRE( (outcome == 0 || outcome == 1) );
251
252 // calculate prob of this outcome
253 qreal prob = 0;
254 for (size_t ind=0; ind<vecRef.size(); ind++) {
255 int bit = (ind >> qubit) & 1; // target-th bit
256 if (bit == outcome)
257 prob += pow(abs(vecRef[ind]), 2);
258 }
259
260 REQUIRE( prob == Approx(res) );
261
262 // renormalise by the outcome prob
263 for (size_t ind=0; ind<vecRef.size(); ind++) {
264 int bit = (ind >> qubit) & 1; // target-th bit
265 if (bit == outcome)
266 vecRef[ind] /= sqrt(prob);
267 else
268 vecRef[ind] = 0;
269 }
270 REQUIRE( areEqual(vec, vecRef) );
271 }
272 SECTION( "density-matrix" ) {
273
274 QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
275 toQureg(mat, matRef);
276
277 qreal res;
278 int outcome = measureWithStats(mat, qubit, &res);
279 REQUIRE( (outcome == 0 || outcome == 1) );
280
281 // compute prob of this outcome
282 qreal prob = 0;
283 for (size_t ind=0; ind<matRef.size(); ind++) {
284 int bit = (ind >> qubit) & 1; // qubit-th bit
285 if (bit == outcome)
286 prob += real(matRef[ind][ind]);
287 }
288
289 REQUIRE( prob == Approx(res) );
290
291 // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
292 for (size_t r=0; r<matRef.size(); r++) {
293 for (size_t c=0; c<matRef.size(); c++) {
294 int ketBit = (c >> qubit) & 1;
295 int braBit = (r >> qubit) & 1;
296
297 if (ketBit == outcome && braBit == outcome)
298 matRef[r][c] /= prob;
299 else
300 matRef[r][c] = 0;
301 }
302 }
303
304 REQUIRE( areEqual(mat, matRef) );
305 }
306 }
307 SECTION( "input validation" ) {
308
309 SECTION( "qubit index" ) {
310
311 int qubit = GENERATE( -1, NUM_QUBITS );
312 qreal res;
313 REQUIRE_THROWS_WITH( measureWithStats(vec, qubit, &res), ContainsSubstring("Invalid target qubit") );
314 }
315 }
316 destroyQureg(vec);
317 destroyQureg(mat);
318}

◆ TEST_CASE() [68/110]

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

Definition at line 46 of file test_decoherence.cpp.

46 {
47
48 PREPARE_TEST(qureg, ref);
49
50 SECTION( "correctness" ) {
51
52 int target = GENERATE( range(0, NUM_QUBITS) );
53 qreal prob = getRandomReal(0, 1);
54 mixDamping(qureg, target, prob);
55
56 // ref -> kraus0 ref kraus0^dagger + kraus1 ref kraus1^dagger
57 QMatrix kraus0{{1,0},{0,sqrt(1-prob)}};
58 QMatrix rho0 = ref;
59 applyReferenceOp(rho0, target, kraus0);
60 QMatrix kraus1{{0,sqrt(prob)},{0,0}};
61 QMatrix rho1 = ref;
62 applyReferenceOp(rho1, target, kraus1);
63 ref = rho0 + rho1;
64
65 REQUIRE( areEqual(qureg, ref) );
66 }
67 SECTION( "validation ") {
68
69 SECTION( "qubit index" ) {
70
71 int target = GENERATE( -1, NUM_QUBITS );
72 REQUIRE_THROWS_WITH( mixDamping(qureg, target, 0), ContainsSubstring("Invalid target") );
73
74 }
75 SECTION( "probability" ) {
76
77 REQUIRE_THROWS_WITH( mixDamping(qureg, 0, -.1), ContainsSubstring("probability is invalid") );
78 REQUIRE_THROWS_WITH( mixDamping(qureg, 0, 1.1), ContainsSubstring("probability is invalid") );
79 }
80 SECTION( "density-matrix" ) {
81
82 Qureg vec = createQureg(NUM_QUBITS);
83 REQUIRE_NOTHROW( mixDamping(vec, 0, 0) ); // zero-prob allowed in v4
84 REQUIRE_THROWS_WITH( mixDamping(vec, 0, .1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
86 }
87 }
88 destroyQureg(qureg, getQuESTEnv());
89}
void mixDamping(Qureg qureg, int target, qreal prob)

◆ TEST_CASE() [69/110]

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

Definition at line 97 of file test_decoherence.cpp.

97 {
98
99 Qureg qureg1 = createForcedDensityQureg(NUM_QUBITS);
100 Qureg qureg2 = createForcedDensityQureg(NUM_QUBITS);
101 initDebugState(qureg1);
102 initDebugState(qureg2);
103 QMatrix ref1 = toQMatrix(qureg1);
104 QMatrix ref2 = toQMatrix(qureg2);
105
106 SECTION( "correctness" ) {
107
108 // test p in {0, 1} and 10 random values in (0,1)
109 qreal prob = GENERATE( 0., 1., take(10, random(0.,1.)) );
110 mixDensityMatrix(qureg1, prob, qureg2);
111
112 // ensure target qureg modified correctly
113 ref1 = (1-prob)*ref1 + (prob)*ref2;
114 REQUIRE( areEqual(qureg1, ref1) );
115
116 // enure other qureg was not modified
117 REQUIRE( areEqual(qureg2, ref2) );
118 }
119 SECTION( "input validation" ) {
120
121 SECTION( "probabilities" ) {
122
123 qreal prob = GENERATE( -0.1, 1.1 );
124 REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, prob, qureg2), ContainsSubstring("probability is invalid") );
125 }
126 SECTION( "density matrices" ) {
127
128 // one is statevec
129 Qureg state1 = createQureg(qureg1.numQubits, getQuESTEnv());
130 REQUIRE_THROWS_WITH( mixDensityMatrix(state1, 0, qureg1), ContainsSubstring("The first Qureg") && ContainsSubstring("must be a density matrix") );
131
132 // in v4, the 2nd arg can be a statevector
133
134 // REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, 0, state1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
135
136 // both are statevec
137 Qureg state2 = createQureg(qureg1.numQubits, getQuESTEnv());
138 REQUIRE_THROWS_WITH( mixDensityMatrix(state1, 0, state2), ContainsSubstring("The first Qureg") && ContainsSubstring("must be a density matrix") );
139
140 destroyQureg(state1, getQuESTEnv());
141 destroyQureg(state2, getQuESTEnv());
142 }
143 SECTION( "matching dimensions" ) {
144
145 Qureg qureg3 = createDensityQureg(1 + qureg1.numQubits, getQuESTEnv());
146 REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, 0, qureg3), ContainsSubstring("inconsistent number of qubits") );
147 REQUIRE_THROWS_WITH( mixDensityMatrix(qureg3, 0, qureg1), ContainsSubstring("inconsistent number of qubits") );
148 destroyQureg(qureg3, getQuESTEnv());
149 }
150 }
151 destroyQureg(qureg1, getQuESTEnv());
152 destroyQureg(qureg2, getQuESTEnv());
153}

◆ TEST_CASE() [70/110]

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

Definition at line 161 of file test_decoherence.cpp.

161 {
162
163 PREPARE_TEST(qureg, ref);
164
165 SECTION( "correctness" ) {
166
167 int target = GENERATE( range(0,NUM_QUBITS) );
168 qreal prob = getRandomReal(0, 1/2.);
169 mixDephasing(qureg, target, prob);
170
171 // ref -> (1 - prob) ref + prob Z ref Z
172 QMatrix phaseRef = ref;
173 applyReferenceOp(phaseRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
174 ref = ((1 - prob) * ref) + (prob * phaseRef);
175
176 REQUIRE( areEqual(qureg, ref) );
177 }
178 SECTION( "validation" ) {
179
180 SECTION( "qubit index" ) {
181
182 int target = GENERATE( -1, NUM_QUBITS );
183 REQUIRE_THROWS_WITH( mixDephasing(qureg, target, 0), ContainsSubstring("Invalid target") );
184
185 }
186 SECTION( "probability" ) {
187
188 REQUIRE_THROWS_WITH( mixDephasing(qureg, 0, -.1), ContainsSubstring("probability is invalid") );
189 REQUIRE_THROWS_WITH( mixDephasing(qureg, 0, .6), ContainsSubstring("probability") && ContainsSubstring("1/2") );
190 }
191 SECTION( "density-matrix" ) {
192
193 Qureg vec = createQureg(NUM_QUBITS);
194 REQUIRE_NOTHROW( mixDephasing(vec, 0, 0) ); // zero prob ok in v4
195 REQUIRE_THROWS_WITH( mixDephasing(vec, 0, 0.1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
197 }
198 }
199 destroyQureg(qureg, getQuESTEnv());
200}
void mixDephasing(Qureg qureg, int target, qreal prob)

◆ TEST_CASE() [71/110]

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

Definition at line 208 of file test_decoherence.cpp.

208 {
209
210 PREPARE_TEST(qureg, ref);
211
212 SECTION( "correctness " ) {
213
214 int target = GENERATE( range(0,NUM_QUBITS) );
215 qreal prob = getRandomReal(0, 3/4.);
216 mixDepolarising(qureg, target, prob);
217
218 QMatrix xRef = ref;
219 applyReferenceOp(xRef, target, QMatrix{{0,1},{1,0}}); // X ref X
220 QMatrix yRef = ref;
221 applyReferenceOp(yRef, target, QMatrix{{0,-qcomp(0,1)},{qcomp(0,1),0}}); // Y ref Y
222 QMatrix zRef = ref;
223 applyReferenceOp(zRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
224 ref = ((1 - prob) * ref) + ((prob/3.) * ( xRef + yRef + zRef));
225
226 REQUIRE( areEqual(qureg, ref) );
227 }
228 SECTION( "validation ") {
229
230 SECTION( "qubit index" ) {
231
232 int target = GENERATE( -1, NUM_QUBITS );
233 REQUIRE_THROWS_WITH( mixDepolarising(qureg, target, 0), ContainsSubstring("Invalid target") );
234
235 }
236 SECTION( "probability" ) {
237
238 REQUIRE_THROWS_WITH( mixDepolarising(qureg, 0, -.1), ContainsSubstring("probability is invalid") );
239 REQUIRE_THROWS_WITH( mixDepolarising(qureg, 0, .76), ContainsSubstring("probability") && ContainsSubstring("3/4") );
240 }
241 SECTION( "density-matrix" ) {
242
243 Qureg vec = createQureg(NUM_QUBITS);
244 REQUIRE_NOTHROW( mixDepolarising(vec, 0, 0) ); // zero-prob ok in v4
245 REQUIRE_THROWS_WITH( mixDepolarising(vec, 0, 0.1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
247 }
248 }
249 destroyQureg(qureg, getQuESTEnv());
250}
void mixDepolarising(Qureg qureg, int target, qreal prob)

◆ TEST_CASE() [72/110]

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

Definition at line 586 of file test_decoherence.cpp.

586 {
587
588 PREPARE_TEST(qureg, ref);
589
590 SECTION( "correctness" ) {
591
592 int target = GENERATE( range(0,NUM_QUBITS) );
593 int numOps = GENERATE( range(1,5) ); // max 4 inclusive
594 vector<QMatrix> matrs = getRandomKrausMap(1, numOps);
595
596 vector<ComplexMatrix2> ops(numOps);
597 for (int i=0; i<numOps; i++)
598 ops[i] = toComplexMatrix2(matrs[i]);
599
600 v3_mixKrausMap(qureg, target, ops.data(), numOps);
601
602 // set ref -> K_i ref K_i^dagger
603 vector<QMatrix> matrRefs(numOps);
604 for (int i=0; i<numOps; i++) {
605 matrRefs[i] = ref;
606 applyReferenceOp(matrRefs[i], target, matrs[i]);
607 }
608 ref = getZeroMatrix(ref.size());
609 for (int i=0; i<numOps; i++)
610 ref += matrRefs[i];
611
612 REQUIRE( areEqual(qureg, ref, 10*REAL_EPS) );
613 }
614 SECTION( "input validation" ) {
615
616 // cannot use NULL because v3 deprecation API copies ops arg before v4 validation
617 ComplexMatrix2 spoofOps[1];
618
619 SECTION( "number of operators" ) {
620
621 int numOps = 0;
622
623 REQUIRE_THROWS_WITH( v3_mixKrausMap(qureg, 0, spoofOps, numOps), ContainsSubstring("must be given a strictly positive number of matrices") );
624 }
625 SECTION( "trace preserving" ) {
626
627 // valid Kraus map
628 int numOps = GENERATE( range(1,5) ); // max 4 inclusive
629 vector<QMatrix> matrs = getRandomKrausMap(1, numOps);
630 vector<ComplexMatrix2> ops(numOps);
631 for (int i=0; i<numOps; i++)
632 ops[i] = toComplexMatrix2(matrs[i]);
633
634 // make invalid
635 ops[GENERATE_REF( range(0,numOps) )].real[0][0] = 9999;
636 REQUIRE_THROWS_WITH( v3_mixKrausMap(qureg, 0, ops.data(), numOps), ContainsSubstring("trace preserving") );
637 }
638 SECTION( "qubit index" ) {
639
640 int target = GENERATE( -1, NUM_QUBITS );
641 REQUIRE_THROWS_WITH( v3_mixKrausMap(qureg, target, spoofOps, 1), ContainsSubstring("Invalid target qubit") );
642 }
643 SECTION( "density-matrix" ) {
644
645 Qureg vec = createQureg(NUM_QUBITS);
646 REQUIRE_THROWS_WITH( v3_mixKrausMap(vec, 0, spoofOps, 1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
648 }
649 SECTION( "operators fit in node" ) {
650
651 qureg.isDistributed = 1;
652 qureg.numAmpsPerNode = 3; // min 4
653 qureg.logNumAmpsPerNode = 1; // min 2
654
655 REQUIRE_THROWS_WITH( v3_mixKrausMap(qureg, 0, spoofOps, 1), ContainsSubstring("each node's communication buffer") && ContainsSubstring("cannot simultaneously store") );
656 }
657 }
658 destroyQureg(qureg, getQuESTEnv());
659}
vector< qmatrix > getRandomKrausMap(int numQb, int numOps)
Definition random.cpp:405

◆ TEST_CASE() [73/110]

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

Definition at line 258 of file test_decoherence.cpp.

258 {
259
260 PREPARE_TEST(qureg, ref);
261
262 // figure out max-num (inclusive) targs allowed by hardware backend
263 // (each node must contain as 2^(2*numTargs) amps)
264 int maxNumTargs = qureg.logNumAmpsPerNode / 2;
265
266 SECTION( "correctness" ) {
267
268 /* note that this function incurs a stack overhead when numTargs < 4,
269 * and a heap overhead when numTargs >= 4
270 */
271
272 // try every size (qubit wise) map
273 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
274
275 // previously, we tried every unique set of targets, via:
276 // int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
277 // alas, this is too slow for CI, so we instead try a fixed number of random sets:
278 GENERATE( range(0, 10) );
279 vector<int> targs(numTargs);
280 setRandomTargets(targs, NUM_QUBITS);
281
282 // try the min and max number of operators, and 2 random numbers
283 // (there are way too many to try all!)
284 int maxNumOps = (2*numTargs)*(2*numTargs);
285 int numOps = GENERATE_COPY( 1, maxNumOps, take(2,random(1,maxNumOps)) );
286
287 // use a new random map
288 vector<QMatrix> matrs = getRandomKrausMap(numTargs, numOps);
289
290 // create map in QuEST datatypes
291 vector<ComplexMatrixN> ops(numOps);
292 for (int i=0; i<numOps; i++) {
293 ops[i] = createCompMatr(numTargs);
294 setCompMatr(ops[i], matrs[i]);
295 }
296
297 mixMultiQubitKrausMap(qureg, targs.data(), numTargs, ops.data(), numOps);
298
299 // set ref -> K_i ref K_i^dagger
300 vector<QMatrix> matrRefs(numOps);
301 for (int i=0; i<numOps; i++) {
302 matrRefs[i] = ref;
303 applyReferenceOp(matrRefs[i], targs.data(), numTargs, matrs[i]);
304 }
305 ref = getZeroMatrix(ref.size());
306 for (int i=0; i<numOps; i++)
307 ref += matrRefs[i];
308
309 REQUIRE( areEqual(qureg, ref, 1E2*REAL_EPS) );
310
311 // cleanup QuEST datatypes
312 for (int i=0; i<numOps; i++)
313 destroyCompMatr(ops[i]);
314 }
315 SECTION( "input validation" ) {
316
317 // spoof a list of properly-initialised CompMatr to avoid seg-fault in deprecation API.
318 // note some functions will need smaller matrices which is fine; a subset of each
319 // spoof'd matrix will be copied over by the deprecation layer
320 ComplexMatrixN spoofOps[NUM_QUBITS];
321 for (int i=0; i<NUM_QUBITS; i++) {
322 spoofOps[i] = createComplexMatrixN(NUM_QUBITS);
323 syncCompMatr(spoofOps[i]);
324 }
325
326 SECTION( "repetition of target" ) {
327
328 // make valid targets
329 int targs[NUM_QUBITS];
330 for (int i=0; i<NUM_QUBITS; i++)
331 targs[i] = i;
332
333 // duplicate one
334 int badInd = GENERATE( range(0,NUM_QUBITS) );
335 int copyInd = GENERATE_COPY( filter([=](int i){ return i!=badInd; }, range(0,NUM_QUBITS)) );
336 targs[badInd] = targs[copyInd];
337
338 REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, spoofOps, 1), ContainsSubstring("target qubits") && ContainsSubstring("unique") );
339 }
340 SECTION( "qubit indices" ) {
341
342 // make valid targets
343 int targs[NUM_QUBITS];
344 for (int i=0; i<NUM_QUBITS; i++)
345 targs[i] = i;
346
347 // make one invalid
348 targs[GENERATE( range(0,NUM_QUBITS) )] = GENERATE( -1, NUM_QUBITS );
349
350 REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, spoofOps, 1), ContainsSubstring("Invalid target qubit") );
351 }
352
353 // cannot test this with deprecated API, since 'numOps' informs a copy before validation
354
355 // SECTION( "number of operators" ) {
356
357 // int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
358 // int numOps = GENERATE_REF( -1, 0 );
359
360 // // make valid targets to avoid triggering target validation
361 // vector<int> targs(numTargs);
362 // for (int i=0; i<numTargs; i++)
363 // targs[i] = i;
364
365 // REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs.data(), numTargs, spoofOps, numOps), ContainsSubstring("must be given a strictly positive number of matrices") );
366 // }
367
368 // this validation cannot be performed by the deprecation API which copies
369 // over all ops arguments without prior checking them as NULL
370
371 // SECTION( "initialisation of operators" ) {
372
373 // /* compilers don't auto-initialise to NULL; the below circumstance
374 // * only really occurs when 'malloc' returns NULL in createCompMatr,
375 // * which actually triggers its own validation. Hence this test is useless
376 // * currently.
377 // */
378
379 // int numTargs = NUM_QUBITS;
380 // int numOps = (2*numTargs)*(2*numTargs);
381
382 // vector<ComplexMatrixN> ops(numOps);
383 // for (int i=0; i<numOps; i++)
384 // ops[i] = createComplexMatrixN(numTargs);
385
386 // // make one of the max-ops explicitly NULL
387 // ops[GENERATE_COPY( range(0,numTargs) )].cpuElems = NULL;
388
389 // // make valid targets to avoid triggering target validation
390 // vector<int> targs(numTargs);
391 // for (int i=0; i<numTargs; i++)
392 // targs[i] = i;
393
394 // REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs.data(), numTargs, ops.data(), numOps), ContainsSubstring("ComplexMatrixN") && ContainsSubstring("created") );
395
396 // for (int i=0; i<numOps; i++)
397 // destroyComplexMatrixN(ops[i]);
398 // }
399
400 // this validation cannot be performed by the deprecation API which copies
401 // over all ops arguments without prior checking them as matching in dimension
402
403 // SECTION( "dimension of operators" ) {
404
405 // // make valid (dimension-wise) max-qubits Kraus map
406 // int numTargs = NUM_QUBITS;
407 // int numOps = (2*numTargs)*(2*numTargs);
408 // vector<ComplexMatrixN> ops(numOps);
409 // for (int i=0; i<numOps; i++)
410 // ops[i] = createComplexMatrixN(numTargs);
411
412 // // make one have wrong-dimensions
413 // int badInd = GENERATE_COPY( range(0,numTargs) );
414 // destroyComplexMatrixN(ops[badInd]);
415 // ops[badInd] = createComplexMatrixN(numTargs - 1);
416
417 // // make valid targets to avoid triggering target validation
418 // vector<int> targs(numTargs);
419 // for (int i=0; i<numTargs; i++)
420 // targs[i] = i;
421
422 // REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs.data(), numTargs, ops.data(), numOps), ContainsSubstring("same number of qubits") );
423
424 // for (int i=0; i<numOps; i++)
425 // destroyComplexMatrixN(ops[i]);
426 // }
427
428 SECTION( "trace preserving" ) {
429
430 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
431 int maxNumOps = (2*numTargs) * (2*numTargs);
432 int numOps = GENERATE_COPY( 1, 2, maxNumOps );
433
434 // generate a valid map
435 vector<QMatrix> matrs = getRandomKrausMap(numTargs, numOps);
436 vector<ComplexMatrixN> ops(numOps);
437 for (int i=0; i<numOps; i++) {
438 ops[i] = createComplexMatrixN(numTargs);
439 toComplexMatrixN(matrs[i], ops[i]);
440 }
441
442 // make only one invalid
443 ops[GENERATE_COPY( 0, numOps - 1)].cpuElems[0][0] = -123456789;
444
445 // make valid targets to avoid triggering target validation
446 vector<int> targs(numTargs);
447 for (int i=0; i<numTargs; i++)
448 targs[i] = i;
449
450 REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs.data(), numTargs, ops.data(), numOps), ContainsSubstring("trace preserving") );
451
452 for (int i=0; i<numOps; i++)
453 destroyComplexMatrixN(ops[i]);
454 }
455 SECTION( "density-matrix" ) {
456
457 Qureg statevec = createQureg(NUM_QUBITS);
458
459 // make valid targets to avoid triggering target validation
460 int targs[NUM_QUBITS];
461 for (int i=0; i<NUM_QUBITS; i++)
462 targs[i] = i;
463
464 REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(statevec, targs, NUM_QUBITS, spoofOps, 1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
465 destroyQureg(statevec, getQuESTEnv());
466
467 }
468 SECTION( "operator fits in node" ) {
469
470 // each node requires (2 numTargs)^2 amplitudes
471 int minAmps = (2*NUM_QUBITS) * (2*NUM_QUBITS);
472
473 // make valid targets to avoid triggering target validation
474 int targs[NUM_QUBITS];
475 for (int i=0; i<NUM_QUBITS; i++)
476 targs[i] = i;
477
478 // make a simple Identity map
479 ComplexMatrixN ops[] = {createComplexMatrixN(NUM_QUBITS)};
480 for (int i=0; i<(1<<NUM_QUBITS); i++)
481 ops[0].cpuElems[i][i] = 1;
482 syncCompMatr(ops[0]);
483
484 // fake a smaller qureg
485 qureg.isDistributed = 1;
486 qureg.numAmpsPerNode = minAmps - 1;
487 qureg.logNumAmpsPerNode = log2(minAmps) - 1;
488 REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, ops, 1), ContainsSubstring("each node's communication buffer") && ContainsSubstring("cannot simultaneously store") );
489
490 destroyComplexMatrixN(ops[0]);
491 }
492
493 for (int i=0; i<NUM_QUBITS; i++)
494 destroyCompMatr(spoofOps[i]);
495 }
496 destroyQureg(qureg, getQuESTEnv());
497}
void setRandomTargets(int *targs, int numTargs, int numQb)
CompMatr createCompMatr(int numQubits)
Definition matrices.cpp:213
void destroyCompMatr(CompMatr matrix)
Definition matrices.cpp:398
void setCompMatr(CompMatr matr, qcomp **vals)
Definition matrices.cpp:423

◆ TEST_CASE() [74/110]

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

Definition at line 667 of file test_decoherence.cpp.

667 {
668
669 PREPARE_TEST(qureg, ref);
670
671 SECTION( "correctness" ) {
672
673 int target = GENERATE( range(0,NUM_QUBITS) );
674 int numOps = GENERATE( range(1,5) ); // max 4 inclusive
675
676 // map consists of unconstrained 2x2 random matrices
677 vector<QMatrix> matrs;
678 for (int i=0; i<numOps; i++)
679 matrs.push_back(getRandomQMatrix(2));
680
681 vector<ComplexMatrix2> ops(numOps);
682 for (int i=0; i<numOps; i++)
683 ops[i] = toComplexMatrix2(matrs[i]);
684 mixNonTPKrausMap(qureg, target, ops.data(), numOps);
685
686 // set ref -> K_i ref K_i^dagger
687 vector<QMatrix> matrRefs(numOps);
688 for (int i=0; i<numOps; i++) {
689 matrRefs[i] = ref;
690 applyReferenceOp(matrRefs[i], target, matrs[i]);
691 }
692 ref = getZeroMatrix(ref.size());
693 for (int i=0; i<numOps; i++)
694 ref += matrRefs[i];
695
696 REQUIRE( areEqual(qureg, ref, 1E2*REAL_EPS) );
697 }
698 SECTION( "input validation" ) {
699
700 // v3 deprecation API copies ops list before v4 validation, so we cannot pass ops=NULL
701 ComplexMatrix2 spoofOps[1];
702
703 SECTION( "number of operators" ) {
704
705 int numOps = 0;
706 REQUIRE_THROWS_WITH( mixNonTPKrausMap(qureg, 0, spoofOps, numOps), ContainsSubstring("must be given a strictly positive number of matrices") );
707 }
708 SECTION( "qubit index" ) {
709
710 int target = GENERATE( -1, NUM_QUBITS );
711 REQUIRE_THROWS_WITH( mixNonTPKrausMap(qureg, target, spoofOps, 1), ContainsSubstring("Invalid target qubit") );
712 }
713 SECTION( "density-matrix" ) {
714
715 Qureg vec = createQureg(NUM_QUBITS);
716 REQUIRE_THROWS_WITH( mixNonTPKrausMap(vec, 0, spoofOps, 1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
718 }
719 SECTION( "operators fit in node" ) {
720
721 qureg.isDistributed = 1;
722 qureg.numAmpsPerNode = 3; // min 4
723 qureg.logNumAmpsPerNode = 1; // min 2
724 REQUIRE_THROWS_WITH( mixNonTPKrausMap(qureg, 0, spoofOps, 1), ContainsSubstring("each node's communication buffer") && ContainsSubstring("cannot simultaneously store") );
725 }
726 }
727 destroyQureg(qureg, getQuESTEnv());
728}

◆ TEST_CASE() [75/110]

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

Definition at line 736 of file test_decoherence.cpp.

736 {
737
738 PREPARE_TEST(qureg, ref);
739
740 // figure out max-num (inclusive) targs allowed by hardware backend
741 // (each node must contain as 2^(2*numTargs) amps)
742 int maxNumTargs = calcLog2(qureg.numAmpsPerNode) / 2;
743
744 SECTION( "correctness" ) {
745
746 /* note that this function incurs a stack overhead when numTargs < 4,
747 * and a heap overhead when numTargs >= 4
748 */
749
750 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
751
752 // previously, we tried every unique set of targets, via:
753 // int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
754 // alas, this is too slow for CI, so we instead try a fixed number of random sets:
755 GENERATE( range(0, 10) );
756 vector<int> targs(numTargs);
757 setRandomTargets(targs, NUM_QUBITS);
758
759 // try the min and max number of operators, and 2 random numbers
760 // (there are way too many to try all!)
761 int maxNumOps = (2*numTargs)*(2*numTargs);
762 int numOps = GENERATE_COPY( 1, maxNumOps, take(2,random(1,maxNumOps)) );
763
764 // use a new random map, of unconstrained random (2^numTargs x 2^numTargs) matrices
765 vector<QMatrix> matrs;
766 for (int i=0; i<numOps; i++)
767 matrs.push_back(getRandomQMatrix(1 << numTargs));
768
769 // create map in QuEST datatypes
770 vector<ComplexMatrixN> ops(numOps);
771 for (int i=0; i<numOps; i++) {
772 ops[i] = createComplexMatrixN(numTargs);
773 toComplexMatrixN(matrs[i], ops[i]);
774 }
775
776 mixNonTPMultiQubitKrausMap(qureg, targs.data(), numTargs, ops.data(), numOps);
777
778 // set ref -> K_i ref K_i^dagger
779 vector<QMatrix> matrRefs(numOps);
780 for (int i=0; i<numOps; i++) {
781 matrRefs[i] = ref;
782 applyReferenceOp(matrRefs[i], targs.data(), numTargs, matrs[i]);
783 }
784 ref = getZeroMatrix(ref.size());
785 for (int i=0; i<numOps; i++)
786 ref += matrRefs[i];
787
788 REQUIRE( areEqual(qureg, ref, 1E5*REAL_EPS) );
789
790 // cleanup QuEST datatypes
791 for (int i=0; i<numOps; i++)
792 destroyComplexMatrixN(ops[i]);
793 }
794 SECTION( "input validation" ) {
795
796 // spoof a list of properly-initialised CompMatr to avoid seg-fault in deprecation API.
797 // note some functions will need smaller matrices which is fine; a subset of each
798 // spoof'd matrix will be copied over by the deprecation layer
799 ComplexMatrixN spoofOps[NUM_QUBITS];
800 for (int i=0; i<NUM_QUBITS; i++) {
801 spoofOps[i] = createComplexMatrixN(NUM_QUBITS);
802 syncCompMatr(spoofOps[i]);
803 }
804
805 SECTION( "repetition of target" ) {
806
807 // make valid targets
808 int targs[NUM_QUBITS];
809 for (int i=0; i<NUM_QUBITS; i++)
810 targs[i] = i;
811
812 // duplicate one
813 int badInd = GENERATE( range(0,NUM_QUBITS) );
814 int copyInd = GENERATE_COPY( filter([=](int i){ return i!=badInd; }, range(0,NUM_QUBITS)) );
815 targs[badInd] = targs[copyInd];
816
817 REQUIRE_THROWS_WITH( mixNonTPMultiQubitKrausMap(qureg, targs, NUM_QUBITS, spoofOps, 1), ContainsSubstring("target qubits") && ContainsSubstring("unique") );
818 }
819 SECTION( "qubit indices" ) {
820
821 // make valid targets
822 int targs[NUM_QUBITS];
823 for (int i=0; i<NUM_QUBITS; i++)
824 targs[i] = i;
825
826 // make one invalid
827 targs[GENERATE( range(0,NUM_QUBITS) )] = GENERATE( -1, NUM_QUBITS );
828
829 REQUIRE_THROWS_WITH( mixNonTPMultiQubitKrausMap(qureg, targs, NUM_QUBITS, spoofOps, 1), ContainsSubstring("Invalid target qubit") );
830 }
831
832 // cannot test this with deprecated API, since 'numOps' informs a copy before validation
833
834 // SECTION( "number of operators" ) {
835
836 // int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
837 // int numOps = GENERATE_REF( -1, 0 );
838
839 // // make valid targets to avoid triggering target validation
840 // vector<int> targs(numTargs);
841 // for (int i=0; i<numTargs; i++)
842 // targs[i] = i;
843 // REQUIRE_THROWS_WITH( mixNonTPMultiQubitKrausMap(qureg, targs.data(), numTargs, spoofOps, numOps), ContainsSubstring("must be given a strictly positive number of matrices") );
844 // }
845
846 // this validation cannot be performed by the deprecation API which copies
847 // over all ops arguments without prior checking them as NULL
848
849 // SECTION( "initialisation of operators" ) {
850
851 // /* compilers don't auto-initialise to NULL; the below circumstance
852 // * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
853 // * which actually triggers its own validation. Hence this test is useless
854 // * currently.
855 // */
856
857 // int numTargs = NUM_QUBITS;
858 // int numOps = (2*numTargs)*(2*numTargs);
859
860 // // no need to initialise ops, but set their attribs correct to avoid triggering other validation
861 // vector<ComplexMatrixN> ops(numOps);
862 // for (int i=0; i<numOps; i++)
863 // ops[i].numQubits = numTargs;
864
865 // // make one of the max-ops explicitly NULL
866 // ops[GENERATE_COPY( range(0,numTargs) )].cpuElems = NULL;
867
868 // // make valid targets to avoid triggering target validation
869 // vector<int> targs(numTargs);
870 // for (int i=0; i<numTargs; i++)
871 // targs[i] = i;
872
873 // REQUIRE_THROWS_WITH( mixNonTPMultiQubitKrausMap(qureg, targs.data(), numTargs, ops.data(), numOps), ContainsSubstring("ComplexMatrixN") && ContainsSubstring("created") );
874 // }
875
876 // this validation cannot be performed by the deprecation API which copies
877 // over all ops arguments without prior checking them as matching in dimension
878
879 // SECTION( "dimension of operators" ) {
880
881 // // make valid (dimension-wise) max-qubits Kraus map
882 // int numTargs = NUM_QUBITS;
883 // int numOps = (2*numTargs)*(2*numTargs);
884 // vector<ComplexMatrixN> ops(numOps);
885 // for (int i=0; i<numOps; i++)
886 // ops[i] = createComplexMatrixN(numTargs);
887
888 // // make one have wrong-dimensions
889 // int badInd = GENERATE_COPY( range(0,numTargs) );
890 // destroyComplexMatrixN(ops[badInd]);
891 // ops[badInd] = createComplexMatrixN(numTargs - 1);
892
893 // // make valid targets to avoid triggering target validation
894 // vector<int> targs(numTargs);
895 // for (int i=0; i<numTargs; i++)
896 // targs[i] = i;
897
898 // REQUIRE_THROWS_WITH( mixNonTPMultiQubitKrausMap(qureg, targs.data(), numTargs, ops.data(), numOps), ContainsSubstring("same number of qubits") );
899
900 // for (int i=0; i<numOps; i++)
901 // destroyComplexMatrixN(ops[i]);
902 // }
903
904 SECTION( "density-matrix" ) {
905
906 Qureg statevec = createQureg(NUM_QUBITS);
907
908 // make valid targets to avoid triggering target validation
909 int targs[NUM_QUBITS];
910 for (int i=0; i<NUM_QUBITS; i++)
911 targs[i] = i;
912
913 REQUIRE_THROWS_WITH( mixNonTPMultiQubitKrausMap(statevec, targs, NUM_QUBITS, spoofOps, 1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
914 destroyQureg(statevec, getQuESTEnv());
915
916 }
917 SECTION( "operator fits in node" ) {
918
919 // each node requires (2 numTargs)^2 amplitudes
920 int minAmps = (2*NUM_QUBITS) * (2*NUM_QUBITS);
921
922 // make valid targets to avoid triggering target validation
923 int targs[NUM_QUBITS];
924 for (int i=0; i<NUM_QUBITS; i++)
925 targs[i] = i;
926
927 // make a simple Identity map
928 ComplexMatrixN ops[] = {createComplexMatrixN(NUM_QUBITS)};
929 for (int i=0; i<(1<<NUM_QUBITS); i++)
930 ops[0].cpuElems[i][i] = 1;
931 syncCompMatr(ops[0]);
932
933 // fake a smaller qureg
934 qureg.isDistributed = 1;
935 qureg.numAmpsPerNode = minAmps - 1;
936 qureg.logNumAmpsPerNode = log2(minAmps) - 1;
937 REQUIRE_THROWS_WITH( mixNonTPMultiQubitKrausMap(qureg, targs, NUM_QUBITS, ops, 1), ContainsSubstring("each node's communication buffer") && ContainsSubstring("cannot simultaneously store") );
938
939 destroyComplexMatrixN(ops[0]);
940 }
941
942 for (int i=0; i<NUM_QUBITS; i++)
943 destroyComplexMatrixN(spoofOps[i]);
944 }
945 destroyQureg(qureg, getQuESTEnv());
946}

◆ TEST_CASE() [76/110]

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

Definition at line 954 of file test_decoherence.cpp.

954 {
955
956 PREPARE_TEST(qureg, ref);
957
958 SECTION( "correctness" ) {
959
960 int targ1 = GENERATE( range(0,NUM_QUBITS) );
961 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
962 int numOps = GENERATE( range(1,17) ); // max 16 inclusive
963
964 // map consists of unconstrained 4x4 random matrices
965 vector<QMatrix> matrs;
966 for (int i=0; i<numOps; i++)
967 matrs.push_back(getRandomQMatrix(4));
968
969 vector<ComplexMatrix4> ops(numOps);
970 for (int i=0; i<numOps; i++)
971 ops[i] = toComplexMatrix4(matrs[i]);
972 mixNonTPTwoQubitKrausMap(qureg, targ1, targ2, ops.data(), numOps);
973
974 // set ref -> K_i ref K_i^dagger
975 int targs[2] = {targ1, targ2};
976 vector<QMatrix> matrRefs(numOps);
977 for (int i=0; i<numOps; i++) {
978 matrRefs[i] = ref;
979 applyReferenceOp(matrRefs[i], targs, 2, matrs[i]);
980 }
981 ref = getZeroMatrix(ref.size());
982 for (int i=0; i<numOps; i++)
983 ref += matrRefs[i];
984
985 REQUIRE( areEqual(qureg, ref, 1E4*REAL_EPS) );
986 }
987 SECTION( "input validation" ) {
988
989 // deprecated v3 API copies ops before v4 validation, so we cannot pass ops=NULL
990 ComplexMatrix4 spoofOps[1];
991
992 // cannot test this with deprecated API, since 'numOps' informs a copy before validation
993
994 // SECTION( "number of operators" ) {
995
996 // int numOps = GENERATE( -1, 0 );
997 // REQUIRE_THROWS_WITH( mixNonTPTwoQubitKrausMap(qureg, 0,1, spoofOps, numOps), ContainsSubstring("must be given a strictly positive number of matrices") );
998 // }
999
1000 SECTION( "target collision" ) {
1001
1002 int target = GENERATE( range(0,NUM_QUBITS) );
1003 REQUIRE_THROWS_WITH( mixNonTPTwoQubitKrausMap(qureg, target, target, spoofOps, 1), ContainsSubstring("target qubits") && ContainsSubstring("unique") );
1004 }
1005 SECTION( "qubit index" ) {
1006
1007 int target = GENERATE( -1, NUM_QUBITS );
1008 REQUIRE_THROWS_WITH( mixNonTPTwoQubitKrausMap(qureg, 0,target, spoofOps, 1), ContainsSubstring("Invalid target qubit") );
1009 REQUIRE_THROWS_WITH( mixNonTPTwoQubitKrausMap(qureg, target,0, spoofOps, 1), ContainsSubstring("Invalid target qubit") );
1010 }
1011 SECTION( "density-matrix" ) {
1012
1013 Qureg vec = createQureg(NUM_QUBITS);
1014 REQUIRE_THROWS_WITH( mixNonTPTwoQubitKrausMap(vec, 0,1, spoofOps, 1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
1015 destroyQureg(vec, getQuESTEnv());
1016 }
1017 SECTION( "operators fit in node" ) {
1018
1019 qureg.isDistributed = 1;
1020 qureg.numAmpsPerNode = 15; // min 16
1021 qureg.logNumAmpsPerNode = 3; // min 4
1022 REQUIRE_THROWS_WITH( mixNonTPTwoQubitKrausMap(qureg, 0,1, spoofOps, 1), ContainsSubstring("each node's communication buffer") && ContainsSubstring("cannot simultaneously store") );
1023 }
1024 }
1025 destroyQureg(qureg, getQuESTEnv());
1026}

◆ TEST_CASE() [77/110]

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

Definition at line 505 of file test_decoherence.cpp.

505 {
506
507 PREPARE_TEST(qureg, ref);
508
509 SECTION( "correctness" ) {
510
511 int target = GENERATE( range(0,NUM_QUBITS) );
512
513 // randomly generate valid pauli-error probabilities
514 qreal probs[3];
515 qreal max0 = 1/2.; // satisfies p1 < 1 - py
516 probs[0] = getRandomReal(0, max0);
517 qreal max1 = (max0 - probs[0])/2.; // p2 can use half of p1's "unused space"
518 probs[1] = getRandomReal(0, max1);
519 qreal max2 = (max1 - probs[1])/2.; // p3 can use half of p2's "unused space"
520 probs[2] = getRandomReal(0, max2);
521
522 // uniformly randomly assign probs (bound to target)
523 int inds[3] = {0,1,2};
524 std::shuffle(inds,inds+3, std::default_random_engine(1E5 * target));
525 qreal probX = probs[inds[0]]; // seed:target shows no variation
526 qreal probY = probs[inds[1]];
527 qreal probZ = probs[inds[2]];
528
529 mixPauli(qureg, target, probX, probY, probZ);
530
531 QMatrix xRef = ref;
532 applyReferenceOp(xRef, target, QMatrix{{0,1},{1,0}}); // X ref X
533 QMatrix yRef = ref;
534 applyReferenceOp(yRef, target, QMatrix{{0,-qcomp(0,1)},{qcomp(0,1),0}}); // Y ref Y
535 QMatrix zRef = ref;
536 applyReferenceOp(zRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
537 ref = ((1 - probX - probY - probZ) * ref) +
538 (probX * xRef) + (probY * yRef) + (probZ * zRef);
539
540 REQUIRE( areEqual(qureg, ref) );
541 }
542 SECTION( "input validation" ) {
543
544 SECTION( "qubit index" ) {
545
546 int target = GENERATE( -1, NUM_QUBITS );
547 REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, 0), ContainsSubstring("Invalid target") );
548
549 }
550 SECTION( "probability" ) {
551
552 int target = 0;
553
554 // probs clearly must be in [0, 1]
555 REQUIRE_THROWS_WITH( mixPauli(qureg, target, -.1, 0, 0), ContainsSubstring("probability is invalid") );
556 REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, -.1, 0), ContainsSubstring("probability is invalid") );
557 REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, -.1), ContainsSubstring("probability is invalid") );
558
559 // max single-non-zero-prob is 0.5
560 REQUIRE_THROWS_WITH( mixPauli(qureg, target, .6, 0, 0), ContainsSubstring("probabilities exceed that which induce maximal mixing") );
561 REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, .6, 0), ContainsSubstring("probabilities exceed that which induce maximal mixing") );
562 REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, .6), ContainsSubstring("probabilities exceed that which induce maximal mixing") );
563
564 // must satisfy px, py, pz < 1 - px - py - pz
565 REQUIRE_THROWS_WITH( mixPauli(qureg, target, .3, .3, .3), ContainsSubstring("probabilities exceed that which induce maximal mixing") );
566 }
567 SECTION( "density-matrix" ) {
568
569 Qureg vec = createQureg(NUM_QUBITS);
570 REQUIRE_NOTHROW( mixPauli(vec, 0, 0, 0, 0) ); // zero-prob ok in v4
571 REQUIRE_THROWS_WITH( mixPauli(vec, 0, 0.1, 0, 0), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
572 REQUIRE_THROWS_WITH( mixPauli(vec, 0, 0, 0.1, 0), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
573 REQUIRE_THROWS_WITH( mixPauli(vec, 0, 0, 0, 0.1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
575 }
576 }
577 destroyQureg(qureg, getQuESTEnv());
578}

◆ TEST_CASE() [78/110]

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

Definition at line 1034 of file test_decoherence.cpp.

1034 {
1035
1036 PREPARE_TEST(qureg, ref);
1037
1038 SECTION( "correctness" ) {
1039
1040 int targ1 = GENERATE( range(0,NUM_QUBITS) );
1041 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
1042 qreal prob = getRandomReal(0, 3/4.);
1043
1044 mixTwoQubitDephasing(qureg, targ1, targ2, prob);
1045
1046 // ref -> (1 - prob) ref + prob/3 (Z1 ref Z1 + Z2 ref Z2 + Z1 Z2 ref Z1 Z2)
1047 QMatrix zMatr{{1,0},{0,-1}};
1048 QMatrix z1Ref = ref;
1049 applyReferenceOp(z1Ref, targ1, zMatr); // Z1 ref Z1
1050 QMatrix z2Ref = ref;
1051 applyReferenceOp(z2Ref, targ2, zMatr); // Z2 ref Z2
1052 QMatrix z1z2Ref = ref;
1053 applyReferenceOp(z1z2Ref, targ1, zMatr);
1054 applyReferenceOp(z1z2Ref, targ2, zMatr); // Z1 Z2 ref Z1 Z2
1055 ref = ((1 - prob) * ref) + (prob/3.) * (z1Ref + z2Ref + z1z2Ref);
1056
1057 REQUIRE( areEqual(qureg, ref) );
1058 }
1059 SECTION( "input validation" ) {
1060
1061 SECTION( "qubit indices" ) {
1062
1063 int targ = GENERATE( -1, NUM_QUBITS );
1064 REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, targ, 0), ContainsSubstring("Invalid target") );
1065 REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, targ, 0, 0), ContainsSubstring("Invalid target") );
1066 }
1067 SECTION( "target collision" ) {
1068
1069 int targ = GENERATE( range(0,NUM_QUBITS) );
1070 REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, targ, targ, 0), ContainsSubstring("target") && ContainsSubstring("unique") );
1071 }
1072 SECTION( "probability" ) {
1073
1074 REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, 1, -.1), ContainsSubstring("probability is invalid") );
1075 REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, 1, 3/4. + .01), ContainsSubstring("probability") && ContainsSubstring("3/4") );
1076 }
1077 SECTION( "density-matrix" ) {
1078
1079 Qureg vec = createQureg(NUM_QUBITS);
1080 REQUIRE_NOTHROW( mixTwoQubitDephasing(vec, 0, 1, 0) ); // zero-prob ok in v4
1081 REQUIRE_THROWS_WITH( mixTwoQubitDephasing(vec, 0, 1, 0.1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
1082 destroyQureg(vec, getQuESTEnv());
1083 }
1084 }
1085 destroyQureg(qureg, getQuESTEnv());
1086}
void mixTwoQubitDephasing(Qureg qureg, int target1, int target2, qreal prob)

◆ TEST_CASE() [79/110]

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

Definition at line 1094 of file test_decoherence.cpp.

1094 {
1095
1096 PREPARE_TEST(qureg, ref);
1097
1098 SECTION( "correctness" ) {
1099
1100 int targ1 = GENERATE( range(0,NUM_QUBITS) );
1101 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
1102 qreal prob = getRandomReal(0, 15/16.);
1103
1104 mixTwoQubitDepolarising(qureg, targ1, targ2, prob);
1105
1106 QMatrix paulis[4] = {
1107 QMatrix{{1,0},{0,1}}, // I
1108 QMatrix{{0,1},{1,0}}, // X
1109 QMatrix{{0,-qcomp(0,1)},{qcomp(0,1),0}}, // Y
1110 QMatrix{{1,0},{0,-1}} // Z
1111 };
1112
1113 int targs[2] = {targ1, targ2};
1114 QMatrix refInit = ref;
1115 ref = (1 - (16/15.)*prob) * ref;
1116 for (int i=0; i<4; i++) {
1117 for (int j=0; j<4; j++) {
1118 QMatrix term = refInit;
1119 QMatrix op = getKroneckerProduct(paulis[i], paulis[j]);
1120 applyReferenceOp(term, targs, 2, op);
1121 ref += (prob/15.) * term;
1122 }
1123 }
1124
1125 REQUIRE( areEqual(qureg, ref, 1E4*REAL_EPS) );
1126 }
1127 SECTION( "input validation" ) {
1128
1129 SECTION( "qubit indices" ) {
1130
1131 int targ = GENERATE( -1, NUM_QUBITS );
1132 REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, targ, 0), ContainsSubstring("Invalid target") );
1133 REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, targ, 0, 0), ContainsSubstring("Invalid target") );
1134 }
1135 SECTION( "target collision" ) {
1136
1137 int targ = GENERATE( range(0,NUM_QUBITS) );
1138 REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, targ, targ, 0), ContainsSubstring("target") && ContainsSubstring("unique") );
1139 }
1140 SECTION( "probability" ) {
1141
1142 REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, 1, -.1), ContainsSubstring("probability is invalid") );
1143 REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, 1, 15/16. + .01), ContainsSubstring("probability") && ContainsSubstring("15/16") );
1144 }
1145 SECTION( "density-matrix" ) {
1146
1147 Qureg vec = createQureg(NUM_QUBITS);
1148 REQUIRE_NOTHROW( mixTwoQubitDepolarising(vec, 0, 1, 0) ); // zero prob ok in v4
1149 REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(vec, 0, 1, 0.1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
1150 destroyQureg(vec, getQuESTEnv());
1151 }
1152 }
1153 destroyQureg(qureg, getQuESTEnv());
1154}
void mixTwoQubitDepolarising(Qureg qureg, int target1, int target2, qreal prob)

◆ TEST_CASE() [80/110]

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

Definition at line 1162 of file test_decoherence.cpp.

1162 {
1163
1164 PREPARE_TEST(qureg, ref);
1165
1166 SECTION( "correctness" ) {
1167
1168 int targ1 = GENERATE( range(0,NUM_QUBITS) );
1169 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
1170 int numOps = GENERATE( range(1,17) ); // max 16 inclusive
1171 vector<QMatrix> matrs = getRandomKrausMap(2, numOps);
1172
1173 vector<ComplexMatrix4> ops(numOps);
1174 for (int i=0; i<numOps; i++)
1175 ops[i] = toComplexMatrix4(matrs[i]);
1176 mixTwoQubitKrausMap(qureg, targ1, targ2, ops.data(), numOps);
1177
1178 // set ref -> K_i ref K_i^dagger
1179 int targs[2] = {targ1, targ2};
1180 vector<QMatrix> matrRefs(numOps);
1181 for (int i=0; i<numOps; i++) {
1182 matrRefs[i] = ref;
1183 applyReferenceOp(matrRefs[i], targs, 2, matrs[i]);
1184 }
1185 ref = getZeroMatrix(ref.size());
1186 for (int i=0; i<numOps; i++)
1187 ref += matrRefs[i];
1188
1189 REQUIRE( areEqual(qureg, ref, 10*REAL_EPS) );
1190 }
1191 SECTION( "input validation" ) {
1192
1193 ComplexMatrix4 emptyOps[1];
1194
1195 SECTION( "number of operators" ) {
1196
1197 // in v4, a separate createKausMap call is made which throws the below error
1198 int numOps = 0;
1199 REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, emptyOps, numOps), ContainsSubstring("must be given a strictly positive number of matrices") );
1200 }
1201 SECTION( "trace preserving" ) {
1202
1203 // valid Kraus map
1204 int numOps = GENERATE( range(1,16) );
1205 vector<QMatrix> matrs = getRandomKrausMap(2, numOps);
1206 vector<ComplexMatrix4> ops(numOps);
1207 for (int i=0; i<numOps; i++)
1208 ops[i] = toComplexMatrix4(matrs[i]);
1209
1210 // make only one of the ops at a time invalid
1211 ops[GENERATE_REF( range(0,numOps) )].real[0][0] = 999;
1212
1213 REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, ops.data(), numOps), ContainsSubstring("trace preserving") );
1214 }
1215 SECTION( "target collision" ) {
1216
1217 int target = GENERATE( range(0,NUM_QUBITS) );
1218 REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, target, target, emptyOps, 1), ContainsSubstring("target qubits") && ContainsSubstring("unique") );
1219 }
1220 SECTION( "qubit index" ) {
1221
1222 int target = GENERATE( -1, NUM_QUBITS );
1223 REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,target, emptyOps, 1), ContainsSubstring("Invalid target qubit") );
1224 REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, target,0, emptyOps, 1), ContainsSubstring("Invalid target qubit") );
1225 }
1226 SECTION( "density-matrix" ) {
1227
1228 Qureg vec = createQureg(NUM_QUBITS);
1229 REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(vec, 0,1, emptyOps, 1), ContainsSubstring("Expected a density matrix Qureg but received a statevector") );
1230 destroyQureg(vec, getQuESTEnv());
1231 }
1232 SECTION( "operators fit in node" ) {
1233
1234 qureg.isDistributed = 1;
1235 qureg.numAmpsPerNode = 15; // min 16
1236 qureg.logNumAmpsPerNode = 3; // min 4
1237 REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, emptyOps, 1), ContainsSubstring("each node's communication buffer") && ContainsSubstring("cannot simultaneously store") );
1238 }
1239 }
1240 destroyQureg(qureg, getQuESTEnv());
1241}

◆ TEST_CASE() [81/110]

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

Definition at line 1011 of file test_unitaries.cpp.

1011 {
1012
1013 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1014
1015 SECTION( "correctness" ) {
1016
1017 // try all possible numbers of targets and controls
1018 int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for 1 ctrl
1019 int maxNumCtrls = NUM_QUBITS - numTargs;
1020 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1021
1022 // generate all possible valid qubit arrangements
1023 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1024 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1025
1026 // for each qubit arrangement, use a new random unitary
1027 QMatrix notOp{{0, 1},{1,0}};
1028
1029 SECTION( "state-vector" ) {
1030
1031 multiControlledMultiQubitNot(quregVec, ctrls, numCtrls, targs, numTargs);
1032 for (int t=0; t<numTargs; t++)
1033 applyReferenceOp(refVec, ctrls, numCtrls, targs[t], notOp);
1034
1035 REQUIRE( areEqual(quregVec, refVec) );
1036 }
1037 SECTION( "density-matrix" ) {
1038
1039 multiControlledMultiQubitNot(quregMatr, ctrls, numCtrls, targs, numTargs);
1040 for (int t=0; t<numTargs; t++)
1041 applyReferenceOp(refMatr, ctrls, numCtrls, targs[t], notOp);
1042
1043 REQUIRE( areEqual(quregMatr, refMatr) );
1044 }
1045 }
1046 SECTION( "input validation" ) {
1047
1048 SECTION( "number of targets" ) {
1049
1050 // there cannot be more targets than qubits in register
1051 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1052 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1053 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1054 int ctrls[] = {0};
1055 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 1, targs, numTargs), ContainsSubstring("number of target qubits"));
1056 }
1057 SECTION( "repetition in targets" ) {
1058
1059 int ctrls[] = {0};
1060 int numTargs = 3;
1061 int targs[] = {1,2,2};
1062 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 1, targs, numTargs), ContainsSubstring("target") && ContainsSubstring("unique"));
1063 }
1064 SECTION( "number of controls" ) {
1065
1066 // v4 API permits passing zero controls
1067 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1068 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1069 for (int i=0; i<NUM_QUBITS+1; i++)
1070 ctrls[i] = i+1;
1071 int targs[1] = {0};
1072 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, numCtrls, targs, 1), ContainsSubstring("number of control qubits"));
1073 }
1074 SECTION( "repetition in controls" ) {
1075
1076 int ctrls[] = {0,1,1};
1077 int targs[] = {3};
1078 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 3, targs, 1), ContainsSubstring("control") && ContainsSubstring("unique"));
1079 }
1080 SECTION( "control and target collision" ) {
1081
1082 int ctrls[] = {0,1,2};
1083 int targs[] = {3,1,4};
1084 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 3, targs, 3), ContainsSubstring("control and target"));
1085 }
1086 SECTION( "qubit indices" ) {
1087
1088 // valid inds
1089 int numQb = 2;
1090 int qb1[2] = {0,1};
1091 int qb2[2] = {2,3};
1092
1093 // make qb1 invalid
1094 int inv = GENERATE( -1, NUM_QUBITS );
1095 qb1[GENERATE_COPY(range(0,numQb))] = inv;
1096
1097 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, qb1, numQb, qb2, numQb), ContainsSubstring("Invalid control") );
1098 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, qb2, numQb, qb1, numQb), ContainsSubstring("Invalid target") );
1099 }
1100 }
1101 CLEANUP_TEST( quregVec, quregMatr );
1102}

◆ TEST_CASE() [82/110]

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

Definition at line 1110 of file test_unitaries.cpp.

1110 {
1111
1112 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1113
1114 // figure out max-num targs (inclusive) allowed by hardware backend
1115 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
1116 if (maxNumTargs >= NUM_QUBITS)
1117 maxNumTargs = NUM_QUBITS - 1; // leave room for min-number of control qubits
1118
1119 SECTION( "correctness" ) {
1120
1121 // try all possible numbers of targets and controls
1122 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
1123 int maxNumCtrls = NUM_QUBITS - numTargs;
1124 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1125
1126 // generate all possible valid qubit arrangements
1127 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1128 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1129
1130 // for each qubit arrangement, use a new random unitary
1131 QMatrix op = getRandomUnitary(numTargs);
1132 ComplexMatrixN matr = createComplexMatrixN(numTargs);
1133 toComplexMatrixN(op, matr);
1134
1135 SECTION( "state-vector" ) {
1136
1137 multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, numTargs, matr);
1138 applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
1139 REQUIRE( areEqual(quregVec, refVec) );
1140 }
1141 SECTION( "density-matrix" ) {
1142
1143 multiControlledMultiQubitUnitary(quregMatr, ctrls, numCtrls, targs, numTargs, matr);
1144 applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
1145 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1146 }
1147 destroyComplexMatrixN(matr);
1148 }
1149 SECTION( "input validation" ) {
1150
1151 SECTION( "number of targets" ) {
1152
1153 // there cannot be more targets than qubits in register
1154 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1155 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1156 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1157 int ctrls[] = {0};
1158 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
1159 toComplexMatrixN(getRandomUnitary(NUM_QUBITS+1), matr); // ensure unitary
1160
1161 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), ContainsSubstring("number of target qubits"));
1162 destroyComplexMatrixN(matr);
1163 }
1164 SECTION( "repetition in targets" ) {
1165
1166 int ctrls[] = {0};
1167 int numTargs = 3;
1168 int targs[] = {1,2,2};
1169 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1170 toComplexMatrixN(getRandomUnitary(numTargs), matr); // ensure unitary
1171
1172 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
1173 destroyComplexMatrixN(matr);
1174 }
1175 SECTION( "number of controls" ) {
1176
1177 // v4 API permits passing zero controls
1178 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1179 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1180 for (int i=0; i<NUM_QUBITS+1; i++)
1181 ctrls[i] = i+1;
1182 int targs[1] = {0};
1183 ComplexMatrixN matr = createComplexMatrixN(1);
1184 toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
1185
1186 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, 1, matr), ContainsSubstring("number of control qubits"));
1187 destroyComplexMatrixN(matr);
1188 }
1189 SECTION( "repetition in controls" ) {
1190
1191 int ctrls[] = {0,1,1};
1192 int targs[] = {3};
1193 ComplexMatrixN matr = createComplexMatrixN(1);
1194 toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
1195
1196 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 1, matr), ContainsSubstring("control") && ContainsSubstring("unique"));
1197 destroyComplexMatrixN(matr);
1198 }
1199 SECTION( "control and target collision" ) {
1200
1201 int ctrls[] = {0,1,2};
1202 int targs[] = {3,1,4};
1203 ComplexMatrixN matr = createComplexMatrixN(3);
1204 toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
1205
1206 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 3, matr), ContainsSubstring("control and target"));
1207 destroyComplexMatrixN(matr);
1208 }
1209 SECTION( "qubit indices" ) {
1210
1211 // valid inds
1212 int numQb = 2;
1213 int qb1[2] = {0,1};
1214 int qb2[2] = {2,3};
1215 ComplexMatrixN matr = createComplexMatrixN(numQb);
1216 toComplexMatrixN(getRandomUnitary(numQb), matr); // ensure unitary
1217
1218 // make qb1 invalid
1219 int inv = GENERATE( -1, NUM_QUBITS );
1220 qb1[GENERATE_COPY(range(0,numQb))] = inv;
1221
1222 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb1, numQb, qb2, numQb, matr), ContainsSubstring("Invalid control") );
1223 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb2, numQb, qb1, numQb, matr), ContainsSubstring("Invalid target") );
1224 destroyComplexMatrixN(matr);
1225 }
1226 SECTION( "unitarity" ) {
1227
1228 int ctrls[1] = {0};
1229 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
1230 int targs[NUM_QUBITS];
1231 for (int i=0; i<numTargs; i++)
1232 targs[i] = i+1;
1233
1234 ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
1235 syncCompMatr(matr);
1236
1237 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), ContainsSubstring("unitary") );
1238
1239 destroyComplexMatrixN(matr);
1240 }
1241 SECTION( "unitary creation" ) {
1242
1243 int ctrls[1] = {0};
1244 int targs[3] = {1,2,3};
1245
1246 ComplexMatrixN matr;
1247 matr.cpuElems = NULL;
1248 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 3, matr), ContainsSubstring("created") );
1249 }
1250 SECTION( "unitary dimensions" ) {
1251
1252 int ctrls[1] = {0};
1253 int targs[2] = {1,2};
1254 ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
1255 toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
1256
1257 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size"));
1258 destroyComplexMatrixN(matr);
1259 }
1260 SECTION( "unitary fits in node" ) {
1261
1262 // pretend we have a very limited distributed memory (judged by matr size)
1263 quregVec.isDistributed = 1;
1264 quregVec.numAmpsPerNode = 1;
1265 quregVec.logNumAmpsPerNode = 0;
1266
1267 int ctrls[1] = {0};
1268 int targs[2] = {1,2};
1269 ComplexMatrixN matr = createComplexMatrixN(2);
1270 for (int i=0; i<4; i++)
1271 matr.cpuElems[i][i] = 1;
1272 syncCompMatr(matr);
1273
1274 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
1275 destroyComplexMatrixN(matr);
1276 }
1277 }
1278 CLEANUP_TEST( quregVec, quregMatr );
1279}

◆ TEST_CASE() [83/110]

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

Definition at line 1287 of file test_unitaries.cpp.

1287 {
1288
1289 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1290 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1291
1292 SECTION( "correctness" ) {
1293
1294 // try all possible numbers of targets and controls
1295 int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for min 1 control qubit
1296 int maxNumCtrls = NUM_QUBITS - numTargs;
1297 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1298
1299 // generate all possible valid qubit arrangements
1300 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1301 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1302
1303 /* it's too expensive to try ALL Pauli sequences, via
1304 * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
1305 * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
1306 * Hence, we instead opt to randomly generate pauliseqs
1307 */
1308 pauliOpType paulis[NUM_QUBITS];
1309 for (int i=0; i<numTargs; i++)
1310 paulis[i] = (pauliOpType) getRandomInt(1,4); // exclude 0=Id
1311
1312 // exclude identities from reference matrix exp (they apply unwanted global phase)
1313 int refTargs[NUM_QUBITS];
1314 int numRefTargs = 0;
1315
1316 QMatrix xMatr{{0,1},{1,0}};
1317 QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
1318 QMatrix zMatr{{1,0},{0,-1}};
1319
1320 // build correct reference matrix by pauli-matrix exponentiation...
1321 QMatrix pauliProd{{1}};
1322 for (int i=0; i<numTargs; i++) {
1323 QMatrix fac;
1324 if (paulis[i] == PAULI_I) continue; // exclude I-targets from ref list
1325 if (paulis[i] == PAULI_X) fac = xMatr;
1326 if (paulis[i] == PAULI_Y) fac = yMatr;
1327 if (paulis[i] == PAULI_Z) fac = zMatr;
1328 pauliProd = getKroneckerProduct(fac, pauliProd);
1329
1330 // include this target in ref list
1331 refTargs[numRefTargs++] = targs[i];
1332 }
1333
1334 // produces exp(-i param/2 pauliProd), unless pauliProd = I
1335 QMatrix op;
1336 if (numRefTargs > 0)
1337 op = getExponentialOfPauliMatrix(param, pauliProd);
1338
1339 SECTION( "state-vector" ) {
1340
1341 multiControlledMultiRotatePauli(quregVec, ctrls, numCtrls, targs, paulis, numTargs, param);
1342 if (numRefTargs > 0)
1343 applyReferenceOp(refVec, ctrls, numCtrls, refTargs, numRefTargs, op);
1344 REQUIRE( areEqual(quregVec, refVec) );
1345 }
1346 SECTION( "density-matrix" ) {
1347
1348 multiControlledMultiRotatePauli(quregMatr, ctrls, numCtrls, targs, paulis, numTargs, param);
1349 if (numRefTargs > 0)
1350 applyReferenceOp(refMatr, ctrls, numCtrls, refTargs, numRefTargs, op);
1351 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1352 }
1353 }
1354 SECTION( "input validation" ) {
1355
1356 // test all validation on both state-vector and density-matrix.
1357 // want GENERATE_COPY( quregVec, quregMatr ), but too lazy to patch
1358 // using github.com/catchorg/Catch2/issues/1809
1359 Qureg regs[] = {quregVec, quregMatr};
1360 Qureg qureg = regs[GENERATE(0,1)];
1361
1362 // over-sized array to prevent seg-fault in case of validation fail below
1363 pauliOpType paulis[NUM_QUBITS+1];
1364 for (int q=0; q<NUM_QUBITS+1; q++)
1365 paulis[q] = PAULI_I;
1366
1367 SECTION( "pauli codes" ) {
1368
1369 int numCtrls = 1;
1370 int ctrls[] = {3};
1371 int numTargs = 3;
1372 int targs[3] = {0, 1, 2};
1373
1374 // make a single Pauli invalid
1375 paulis[GENERATE_COPY(range(0,numTargs))] = (pauliOpType) GENERATE( -1, 4 );
1376
1377 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("invalid Pauli code"));
1378 }
1379 SECTION( "number of targets" ) {
1380
1381 // zero non-Id Paulis are permitted in v4 (effecting Identity)
1382
1383 // there cannot be more targets than qubits in register
1384 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1385 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1386 for (int i=0; i<NUM_QUBITS+1; i++)
1387 targs[i] = i+1;
1388 int numCtrls = 1;
1389 int ctrls[] = {0};
1390
1391 // in v4, Id Paulis do not contribute to numTargets
1392 for (int i=0; i<NUM_QUBITS; i++)
1393 paulis[i] = PAULI_X;
1394
1395 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, -1, param), ContainsSubstring("must contain at least one Pauli operator") );
1396 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, NUM_QUBITS+1, param), ContainsSubstring("non-identity Pauli operator") && ContainsSubstring("exceeds the maximum target") );
1397 }
1398 SECTION( "repetition in targets" ) {
1399
1400 int numCtrls = 1;
1401 int numTargs = 3;
1402 int ctrls[] = {0};
1403 int targs[] = {1,2,2};
1404
1405 for (int i=0; i<NUM_QUBITS; i++)
1406 paulis[i] = PAULI_X;
1407
1408 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("Pauli indices") && ContainsSubstring("duplicate"));
1409 }
1410 SECTION( "number of controls" ) {
1411
1412 // v4 API permits passing zero and NUM_QUBITS controls
1413 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1414 int numTargs = 1;
1415 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1416 for (int i=0; i<NUM_QUBITS+1; i++)
1417 ctrls[i] = i+1;
1418 int targs[1] = {0};
1419
1420 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("number of control qubits"));
1421 }
1422 SECTION( "repetition in controls" ) {
1423
1424 int numCtrls = 3;
1425 int numTargs = 1;
1426 int ctrls[] = {0,1,1};
1427 int targs[] = {3};
1428
1429 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("control") && ContainsSubstring("unique"));
1430 }
1431 SECTION( "control and target collision" ) {
1432
1433 int numCtrls = 3;
1434 int numTargs = 3;
1435 int ctrls[] = {0,1,2};
1436 int targs[] = {3,1,4};
1437 for (int i=0; i<numTargs; i++)
1438 paulis[i] = PAULI_X;
1439
1440 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("control qubit overlaps a non-identity Pauli"));
1441 }
1442 SECTION( "qubit indices" ) {
1443
1444 // valid inds
1445 int numQb = 2;
1446 int qb1[2] = {0,1};
1447 int qb2[2] = {2,3};
1448
1449 for (int i=0; i<NUM_QUBITS; i++)
1450 paulis[i] = PAULI_X;
1451
1452 // make qb1 invalid
1453 int inv = GENERATE( -1, NUM_QUBITS );
1454 qb1[GENERATE_COPY(range(0,numQb))] = inv;
1455
1456 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, qb1, numQb, qb2, paulis, numQb, param), ContainsSubstring("Invalid control") );
1457 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, qb2, numQb, qb1, paulis, numQb, param), ContainsSubstring("Invalid index") || ContainsSubstring("exceeds the maximum") );
1458 }
1459 }
1460 CLEANUP_TEST( quregVec, quregMatr );
1461}

◆ TEST_CASE() [84/110]

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

Definition at line 1469 of file test_unitaries.cpp.

1469 {
1470
1471 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1472 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1473
1474 SECTION( "correctness" ) {
1475
1476 // try all possible numbers of targets and controls
1477 int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for min 1 control qubit
1478 int maxNumCtrls = NUM_QUBITS - numTargs;
1479 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1480
1481 // generate all possible valid qubit arrangements
1482 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1483 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1484
1485 // build correct reference matrix by diagonal-matrix exponentiation...
1486 QMatrix zMatr{{1,0},{0,-1}};
1487 QMatrix zProd = zMatr;
1488 for (int t=0; t<numTargs-1; t++)
1489 zProd = getKroneckerProduct(zMatr, zProd); // Z . Z ... Z
1490
1491 // exp( -i param/2 Z . Z ... Z)
1492 QMatrix op = getExponentialOfDiagonalMatrix(qcomp(0, -param/2) * zProd);
1493
1494 SECTION( "state-vector" ) {
1495
1496 multiControlledMultiRotateZ(quregVec, ctrls, numCtrls, targs, numTargs, param);
1497 applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
1498 REQUIRE( areEqual(quregVec, refVec) );
1499 }
1500 SECTION( "density-matrix" ) {
1501
1502 multiControlledMultiRotateZ(quregMatr, ctrls, numCtrls, targs, numTargs, param);
1503 applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
1504 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1505 }
1506 }
1507 SECTION( "input validation" ) {
1508
1509 // test all validation on both state-vector and density-matrix.
1510 // want GENERATE_COPY( quregVec, quregMatr ), but too lazy to patch
1511 // using github.com/catchorg/Catch2/issues/1809
1512 Qureg regs[] = {quregVec, quregMatr};
1513 Qureg qureg = regs[GENERATE(0,1)];
1514
1515 SECTION( "number of targets" ) {
1516
1517 // there cannot be more targets than qubits in register
1518 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1519 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1520 int numCtrls = 1;
1521 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1522 int ctrls[] = {0};
1523
1524 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("number of target qubits") );
1525 }
1526 SECTION( "repetition in targets" ) {
1527
1528 int numCtrls = 1;
1529 int numTargs = 3;
1530 int ctrls[] = {0};
1531 int targs[] = {1,2,2};
1532
1533 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("target") && ContainsSubstring("unique"));
1534 }
1535 SECTION( "number of controls" ) {
1536
1537 // v4 API permits passing zero and NUM_QUBITS controls
1538 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1539 int numTargs = 1;
1540 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1541 for (int i=0; i<NUM_QUBITS+1; i++)
1542 ctrls[i] = i+1;
1543 int targs[1] = {0};
1544
1545 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("number of control qubits"));
1546 }
1547 SECTION( "repetition in controls" ) {
1548
1549 int numCtrls = 3;
1550 int numTargs = 1;
1551 int ctrls[] = {0,1,1};
1552 int targs[] = {3};
1553
1554 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("control") && ContainsSubstring("unique"));
1555 }
1556 SECTION( "control and target collision" ) {
1557
1558 int numCtrls = 3;
1559 int numTargs = 3;
1560 int ctrls[] = {0,1,2};
1561 int targs[] = {3,1,4};
1562
1563 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("control and target"));
1564 }
1565 SECTION( "qubit indices" ) {
1566
1567 // valid inds
1568 int numQb = 2;
1569 int qb1[2] = {0,1};
1570 int qb2[2] = {2,3};
1571
1572 // make qb1 invalid
1573 int inv = GENERATE( -1, NUM_QUBITS );
1574 qb1[GENERATE_COPY(range(0,numQb))] = inv;
1575
1576 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, qb1, numQb, qb2, numQb, param), ContainsSubstring("Invalid control") );
1577 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, qb2, numQb, qb1, numQb, param), ContainsSubstring("Invalid target") );
1578 }
1579 }
1580 CLEANUP_TEST( quregVec, quregMatr );
1581}
qmatrix getExponentialOfDiagonalMatrix(qmatrix m)
Definition linalg.cpp:336

◆ TEST_CASE() [85/110]

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

Definition at line 1589 of file test_unitaries.cpp.

1589 {
1590
1591 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1592
1593 // acts on the final control qubit
1594 QMatrix op{{1,0},{0,-1}};
1595
1596 SECTION( "correctness" ) {
1597
1598 // generate ALL valid qubit arrangements
1599 int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1600 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1601
1602 SECTION( "state-vector" ) {
1603
1604 multiControlledPhaseFlip(quregVec, ctrls, numCtrls);
1605 applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1606 REQUIRE( areEqual(quregVec, refVec) );
1607 }
1608 SECTION( "density-matrix" ) {
1609
1610 multiControlledPhaseFlip(quregMatr, ctrls, numCtrls);
1611 applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1612 REQUIRE( areEqual(quregMatr, refMatr) );
1613 }
1614 }
1615 SECTION( "input validation" ) {
1616
1617 SECTION( "number of targets" ) {
1618
1619 // in v4, all qubits are considered targets
1620
1621 // v4 API permits passing zero controls
1622 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1623 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1624 REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), ContainsSubstring("number of target qubits"));
1625 }
1626 SECTION( "repetition of targets" ) {
1627
1628 int numCtrls = 3;
1629 int ctrls[] = {0,1,1};
1630 REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), ContainsSubstring("qubits must be unique"));
1631 }
1632 SECTION( "qubit indices" ) {
1633
1634 int numCtrls = 3;
1635 int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1636 REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), ContainsSubstring("Invalid target qubit") );
1637 }
1638 }
1639 CLEANUP_TEST( quregVec, quregMatr );
1640}

◆ TEST_CASE() [86/110]

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

Definition at line 1648 of file test_unitaries.cpp.

1648 {
1649
1650 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1651 qreal param = getRandomReal(-2*M_PI, 2*M_PI);
1652 QMatrix op{{1,0},{0,expI(param)}};
1653
1654 SECTION( "correctness" ) {
1655
1656 // generate ALL valid qubit arrangements
1657 int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1658 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1659
1660 SECTION( "state-vector" ) {
1661
1662 multiControlledPhaseShift(quregVec, ctrls, numCtrls, param);
1663 applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1664 REQUIRE( areEqual(quregVec, refVec) );
1665 }
1666 SECTION( "density-matrix" ) {
1667
1668 multiControlledPhaseShift(quregMatr, ctrls, numCtrls, param);
1669 applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1670 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1671 }
1672 }
1673 SECTION( "input validation" ) {
1674
1675 // in v4, all arguments are considered targets (not controls)
1676
1677 SECTION( "number of targets" ) {
1678
1679 // v4 API permits passing zero controls
1680 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1681 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1682 REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), ContainsSubstring("number of target qubits"));
1683 }
1684 SECTION( "repetition of targets" ) {
1685
1686 int numCtrls = 3;
1687 int ctrls[] = {0,1,1};
1688 REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), ContainsSubstring("qubits must be unique"));
1689 }
1690 SECTION( "qubit indices" ) {
1691
1692 int numCtrls = 3;
1693 int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1694 REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), ContainsSubstring("Invalid target qubit") );
1695 }
1696 }
1697 CLEANUP_TEST( quregVec, quregMatr );
1698}

◆ TEST_CASE() [87/110]

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

Definition at line 1706 of file test_unitaries.cpp.

1706 {
1707
1708 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1709
1710 // in distributed mode, each node must be able to fit all amps modified by unitary
1711 REQUIRE( quregVec.numAmpsPerNode >= 4 );
1712
1713 // every test will use a unique random matrix
1714 QMatrix op = getRandomUnitary(2);
1716
1717 SECTION( "correctness" ) {
1718
1719 // generate ALL valid qubit arrangements
1720 int targ1 = GENERATE( range(0,NUM_QUBITS) );
1721 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
1722 int targs[] = {targ1, targ2};
1723 int numCtrls = GENERATE( range(1,NUM_QUBITS-1) ); // leave room for 2 targets (upper bound is exclusive)
1724 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, 2) );
1725
1726 SECTION( "state-vector" ) {
1727
1728 multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr);
1729 applyReferenceOp(refVec, ctrls, numCtrls, targ1, targ2, op);
1730 REQUIRE( areEqual(quregVec, refVec) );
1731 }
1732 SECTION( "density-matrix" ) {
1733
1734 multiControlledTwoQubitUnitary(quregMatr, ctrls, numCtrls, targ1, targ2, matr);
1735 applyReferenceOp(refMatr, ctrls, numCtrls, targ1, targ2, op);
1736 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1737 }
1738 }
1739 SECTION( "input validation" ) {
1740
1741 SECTION( "number of controls" ) {
1742
1743 // v4 API permits passing zero and NUM_QUBITS controls
1744
1745 // numCtrls=(NUM_QUBITS-1) is ok since requires ctrl qubit inds are invalid
1746 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1747 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1748 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, 0, 1, matr), ContainsSubstring("number of control qubits"));
1749 }
1750 SECTION( "repetition of controls" ) {
1751
1752 int numCtrls = 3;
1753 int ctrls[] = {0,1,1};
1754 int targ1 = 2;
1755 int targ2 = 3;
1756 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), ContainsSubstring("control") && ContainsSubstring("unique"));;
1757 }
1758 SECTION( "repetition of targets" ) {
1759
1760 int numCtrls = 3;
1761 int ctrls[] = {0,1,2};
1762 int targ1 = 3;
1763 int targ2 = targ1;
1764 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
1765 }
1766 SECTION( "control and target collision" ) {
1767
1768 int numCtrls = 3;
1769 int ctrls[] = {0,1,2};
1770 int targ1 = 3;
1771 int targ2 = ctrls[GENERATE_COPY( range(0,numCtrls) )];
1772 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), ContainsSubstring("control and target") );
1773 }
1774 SECTION( "qubit indices" ) {
1775
1776 // valid indices
1777 int targ1 = 0;
1778 int targ2 = 1;
1779 int numCtrls = 3;
1780 int ctrls[] = { 2, 3, 4 };
1781
1782 int inv = GENERATE( -1, NUM_QUBITS );
1783 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, inv, targ2, matr), ContainsSubstring("Invalid target") );
1784 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, inv, matr), ContainsSubstring("Invalid target") );
1785
1786 ctrls[numCtrls-1] = inv; // make ctrls invalid
1787 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), ContainsSubstring("Invalid control") );
1788 }
1789 SECTION( "unitarity " ) {
1790
1791 int ctrls[1] = {0};
1792 matr.real[0][0] = 99999; // break unitarity
1793 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), ContainsSubstring("unitary") );
1794 }
1795 SECTION( "unitary fits in node" ) {
1796
1797 // pretend we have a very limited distributed memory
1798 quregVec.isDistributed = 1;
1799 quregVec.numAmpsPerNode = 1;
1800 quregVec.logNumAmpsPerNode = 0;
1801
1802 int ctrls[1] = {0};
1803 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
1804 }
1805 }
1806 CLEANUP_TEST( quregVec, quregMatr );
1807}

◆ TEST_CASE() [88/110]

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

Definition at line 1815 of file test_unitaries.cpp.

1815 {
1816
1817 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1818
1819 // every test will use a unique random matrix
1820 QMatrix op = getRandomUnitary(1);
1822
1823 SECTION( "correctness" ) {
1824
1825 int target = GENERATE( range(0,NUM_QUBITS) );
1826 int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
1827 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
1828
1829 SECTION( "state-vector" ) {
1830
1831 multiControlledUnitary(quregVec, ctrls, numCtrls, target, matr);
1832 applyReferenceOp(refVec, ctrls, numCtrls, target, op);
1833 REQUIRE( areEqual(quregVec, refVec) );
1834 }
1835 SECTION( "density-matrix" ) {
1836
1837 multiControlledUnitary(quregMatr, ctrls, numCtrls, target, matr);
1838 applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
1839 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1840 }
1841 }
1842 SECTION( "input validation" ) {
1843
1844 SECTION( "number of controls" ) {
1845
1846 // v4 API permits passing zero and NUM_QUBITS controls
1847 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1848 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1849 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, numCtrls, 0, matr), ContainsSubstring("number of control qubits"));
1850 }
1851 SECTION( "repetition of controls" ) {
1852
1853 int ctrls[] = {0,1,1};
1854 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 2, matr), ContainsSubstring("control") && ContainsSubstring("unique"));
1855 }
1856 SECTION( "control and target collision" ) {
1857
1858 int ctrls[] = {0,1,2};
1859 int targ = ctrls[GENERATE( range(0,3) )];
1860 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), ContainsSubstring("control and target") );
1861 }
1862 SECTION( "qubit indices" ) {
1863
1864 int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1865 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 0, matr), ContainsSubstring("Invalid control") );
1866
1867 ctrls[2] = 3; // make ctrls valid
1868 int targ = GENERATE( -1, NUM_QUBITS );
1869 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), ContainsSubstring("Invalid target") );
1870 }
1871 SECTION( "unitarity" ) {
1872
1873 matr.real[0][0] = 9999; // break matr unitarity
1874 int ctrls[] = {0};
1875 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 1, 1, matr), ContainsSubstring("unitary") );
1876 }
1877 }
1878 CLEANUP_TEST( quregVec, quregMatr );
1879}

◆ TEST_CASE() [89/110]

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

Definition at line 1887 of file test_unitaries.cpp.

1887 {
1888
1889 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1890
1891 SECTION( "correctness" ) {
1892
1893 // try all possible numbers of targets and controls
1894 int numTargs = GENERATE_COPY( range(1,NUM_QUBITS+1) ); // leave space for 1 ctrl
1895
1896 // generate all possible valid qubit arrangements
1897 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1898
1899 // for each qubit arrangement, use a new random unitary
1900 QMatrix notOp{{0, 1},{1,0}};
1901
1902 SECTION( "state-vector" ) {
1903
1904 multiQubitNot(quregVec, targs, numTargs);
1905 for (int t=0; t<numTargs; t++)
1906 applyReferenceOp(refVec, targs[t], notOp);
1907
1908 REQUIRE( areEqual(quregVec, refVec) );
1909 }
1910 SECTION( "density-matrix" ) {
1911
1912 multiQubitNot(quregMatr, targs, numTargs);
1913 for (int t=0; t<numTargs; t++)
1914 applyReferenceOp(refMatr, targs[t], notOp);
1915
1916 REQUIRE( areEqual(quregMatr, refMatr) );
1917 }
1918 }
1919 SECTION( "input validation" ) {
1920
1921 SECTION( "number of targets" ) {
1922
1923 // there cannot be more targets than qubits in register
1924 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1925 int targs[NUM_QUBITS+1];
1926 REQUIRE_THROWS_WITH( multiQubitNot(quregVec, targs, numTargs), ContainsSubstring("number of target qubits"));
1927 }
1928 SECTION( "repetition in targets" ) {
1929
1930 int numTargs = 3;
1931 int targs[] = {1,2,2};
1932 REQUIRE_THROWS_WITH( multiQubitNot(quregVec, targs, numTargs), ContainsSubstring("target") && ContainsSubstring("unique"));
1933 }
1934 SECTION( "target indices" ) {
1935
1936 // valid inds
1937 int numQb = 5;
1938 int qubits[] = {0,1,2,3,4};
1939
1940 // make one index invalid
1941 qubits[GENERATE_COPY(range(0,numQb))] = GENERATE( -1, NUM_QUBITS );
1942 REQUIRE_THROWS_WITH( multiQubitNot(quregVec, qubits, numQb), ContainsSubstring("Invalid target") );
1943 }
1944 }
1945 CLEANUP_TEST( quregVec, quregMatr );
1946}

◆ TEST_CASE() [90/110]

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

Definition at line 1954 of file test_unitaries.cpp.

1954 {
1955
1956 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1957
1958 // figure out max-num (inclusive) targs allowed by hardware backend
1959 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
1960
1961 SECTION( "correctness" ) {
1962
1963 // generate all possible qubit arrangements
1964 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
1965 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1966
1967 // for each qubit arrangement, use a new random unitary
1968 QMatrix op = getRandomUnitary(numTargs);
1969 ComplexMatrixN matr = createComplexMatrixN(numTargs);
1970 toComplexMatrixN(op, matr);
1971
1972 SECTION( "state-vector" ) {
1973
1974 multiQubitUnitary(quregVec, targs, numTargs, matr);
1975 applyReferenceOp(refVec, targs, numTargs, op);
1976 REQUIRE( areEqual(quregVec, refVec) );
1977 }
1978 SECTION( "density-matrix" ) {
1979
1980 multiQubitUnitary(quregMatr, targs, numTargs, matr);
1981 applyReferenceOp(refMatr, targs, numTargs, op);
1982 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1983 }
1984 destroyComplexMatrixN(matr);
1985 }
1986 SECTION( "input validation" ) {
1987
1988 SECTION( "number of targets" ) {
1989
1990 // there cannot be more targets than qubits in register
1991 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1992 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1993 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
1994 syncCompMatr(matr);
1995
1996 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("number of target qubits"));
1997 destroyComplexMatrixN(matr);
1998 }
1999 SECTION( "repetition in targets" ) {
2000
2001 int numTargs = 3;
2002 int targs[] = {1,2,2};
2003 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
2004 syncCompMatr(matr);
2005
2006 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
2007 destroyComplexMatrixN(matr);
2008 }
2009 SECTION( "qubit indices" ) {
2010
2011 int numTargs = 3;
2012 int targs[] = {1,2,3};
2013 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
2014 syncCompMatr(matr);
2015
2016 int inv = GENERATE( -1, NUM_QUBITS );
2017 targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
2018 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("Invalid target") );
2019
2020 destroyComplexMatrixN(matr);
2021 }
2022 SECTION( "unitarity" ) {
2023
2024 int numTargs = GENERATE_COPY( range(1,maxNumTargs) );
2025 int targs[NUM_QUBITS];
2026 for (int i=0; i<numTargs; i++)
2027 targs[i] = i+1;
2028
2029 ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
2030 syncCompMatr(matr);
2031
2032 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("unitary") );
2033 destroyComplexMatrixN(matr);
2034 }
2035 SECTION( "unitary creation" ) {
2036
2037 int numTargs = 3;
2038 int targs[] = {1,2,3};
2039
2040 ComplexMatrixN matr;
2041 matr.cpuElems = NULL;
2042 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("created") );
2043 }
2044 SECTION( "unitary dimensions" ) {
2045
2046 int targs[2] = {1,2};
2047 ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
2048 syncCompMatr(matr);
2049
2050 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size"));
2051 destroyComplexMatrixN(matr);
2052 }
2053 SECTION( "unitary fits in node" ) {
2054
2055 // pretend we have a very limited distributed memory (judged by matr size)
2056 quregVec.isDistributed = 1;
2057 quregVec.numAmpsPerNode = 1;
2058 quregVec.logNumAmpsPerNode = 0;
2059
2060 int qb[] = {1,2};
2061 ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
2062 for (int i=0; i<4; i++)
2063 matr.cpuElems[i][i] = 1;
2064 syncCompMatr(matr);
2065
2066 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, qb, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
2067 destroyComplexMatrixN(matr);
2068 }
2069 }
2070 CLEANUP_TEST( quregVec, quregMatr );
2071}

◆ TEST_CASE() [91/110]

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

Definition at line 2079 of file test_unitaries.cpp.

2079 {
2080
2081 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2082 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2083
2084 SECTION( "correctness" ) {
2085
2086 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
2087 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
2088
2089 /* it's too expensive to try ALL Pauli sequences, via
2090 * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
2091 * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
2092 * Hence, we instead opt to repeatedlyrandomly generate pauliseqs
2093 */
2094 GENERATE( range(0,10) ); // gen 10 random pauli-codes for every targs
2095 pauliOpType paulis[NUM_QUBITS];
2096 for (int i=0; i<numTargs; i++)
2097 paulis[i] = (pauliOpType) getRandomInt(1,4); // exclude Id=0
2098
2099 // exclude identities from reference matrix exp (they apply unwanted global phase)
2100 int refTargs[NUM_QUBITS];
2101 int numRefTargs = 0;
2102
2103 QMatrix xMatr{{0,1},{1,0}};
2104 QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
2105 QMatrix zMatr{{1,0},{0,-1}};
2106
2107 // build correct reference matrix by pauli-matrix exponentiation...
2108 QMatrix pauliProd{{1}};
2109 for (int i=0; i<numTargs; i++) {
2110 QMatrix fac;
2111 if (paulis[i] == PAULI_I) continue; // exclude I-targets from ref list
2112 if (paulis[i] == PAULI_X) fac = xMatr;
2113 if (paulis[i] == PAULI_Y) fac = yMatr;
2114 if (paulis[i] == PAULI_Z) fac = zMatr;
2115 pauliProd = getKroneckerProduct(fac, pauliProd);
2116
2117 // include this target in ref list
2118 refTargs[numRefTargs++] = targs[i];
2119 }
2120
2121 // produces exp(-i param/2 pauliProd), unless pauliProd = I
2122 QMatrix op;
2123 if (numRefTargs > 0)
2124 op = getExponentialOfPauliMatrix(param, pauliProd);
2125
2126 SECTION( "state-vector" ) {
2127
2128 multiRotatePauli(quregVec, targs, paulis, numTargs, param);
2129 if (numRefTargs > 0)
2130 applyReferenceOp(refVec, refTargs, numRefTargs, op);
2131 REQUIRE( areEqual(quregVec, refVec) );
2132 }
2133 SECTION( "density-matrix" ) {
2134
2135 multiRotatePauli(quregMatr, targs, paulis, numTargs, param);
2136 if (numRefTargs > 0)
2137 applyReferenceOp(refMatr, refTargs, numRefTargs, op);
2138 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2139 }
2140 }
2141 SECTION( "input validation" ) {
2142
2143 SECTION( "number of targets" ) {
2144
2145 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
2146 int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
2147 for (int i=0; i<NUM_QUBITS+1; i++)
2148 targs[i] = i;
2149 pauliOpType paulis[NUM_QUBITS+1];
2150 for (int i=0; i<NUM_QUBITS+1; i++)
2151 paulis[i] = PAULI_X;
2152
2153 REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), (ContainsSubstring("Pauli operator") && ContainsSubstring("exceeds the maximum target")) || ContainsSubstring("Invalid number of Paulis") );
2154 }
2155 SECTION( "repetition of targets" ) {
2156
2157 int numTargs = 3;
2158 int targs[3] = {0, 1, 1};
2159 pauliOpType paulis[3] = {PAULI_X, PAULI_X, PAULI_X};
2160 REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), ContainsSubstring("Pauli indices contained a duplicate"));
2161 }
2162 SECTION( "qubit indices" ) {
2163
2164 int numTargs = 3;
2165 int targs[3] = {0, 1, 2};
2166 targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
2167 pauliOpType paulis[NUM_QUBITS];
2168 for (int i=0; i<NUM_QUBITS; i++)
2169 paulis[i] = PAULI_X;
2170
2171 REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), (ContainsSubstring("non-identity Pauli operator") && ContainsSubstring("exceeds the maximum")) || ContainsSubstring("Invalid index"));
2172 }
2173 SECTION( "pauli codes" ) {
2174 int numTargs = 3;
2175 int targs[3] = {0, 1, 2};
2176 pauliOpType paulis[3] = {PAULI_X, PAULI_X, PAULI_X};
2177 paulis[GENERATE_COPY(range(0,numTargs))] = (pauliOpType) GENERATE( -1, 4 );
2178 REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), ContainsSubstring("invalid Pauli code"));
2179 }
2180 }
2181 CLEANUP_TEST( quregVec, quregMatr );
2182}

◆ TEST_CASE() [92/110]

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

Definition at line 2190 of file test_unitaries.cpp.

2190 {
2191
2192 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2193 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2194
2195 SECTION( "correctness" ) {
2196
2197 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
2198 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
2199
2200 // build correct reference matrix by diagonal-matrix exponentiation...
2201 QMatrix zMatr{{1,0},{0,-1}};
2202 QMatrix zProd = zMatr;
2203 for (int t=0; t<numTargs-1; t++)
2204 zProd = getKroneckerProduct(zMatr, zProd); // Z . Z ... Z
2205
2206 // (-i param/2) Z . I . Z ...
2207 QMatrix expArg = qcomp(0, -param/2) *
2208 getFullOperatorMatrix(NULL, 0, targs, numTargs, zProd, NUM_QUBITS);
2209
2210 // exp( -i param/2 Z . I . Z ...)
2212
2213 // all qubits to specify full operator matrix on reference structures
2214 int allQubits[NUM_QUBITS];
2215 for (int i=0; i<NUM_QUBITS; i++)
2216 allQubits[i] = i;
2217
2218 SECTION( "state-vector" ) {
2219
2220 multiRotateZ(quregVec, targs, numTargs, param);
2221 applyReferenceOp(refVec, allQubits, NUM_QUBITS, op);
2222 REQUIRE( areEqual(quregVec, refVec) );
2223 }
2224 SECTION( "density-matrix" ) {
2225
2226 multiRotateZ(quregMatr, targs, numTargs, param);
2227 applyReferenceOp(refMatr, allQubits, NUM_QUBITS, op);
2228 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2229 }
2230 }
2231 SECTION( "input validation" ) {
2232
2233 SECTION( "number of targets" ) {
2234
2235 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
2236 int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
2237 REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), ContainsSubstring("number of target qubits"));
2238
2239 }
2240 SECTION( "repetition of targets" ) {
2241
2242 int numTargs = 3;
2243 int targs[3] = {0, 1, 1};
2244 REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), ContainsSubstring("target") && ContainsSubstring("unique"));
2245 }
2246 SECTION( "qubit indices" ) {
2247
2248 int numTargs = 3;
2249 int targs[3] = {0, 1, 2};
2250 targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
2251 REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), ContainsSubstring("Invalid target"));
2252 }
2253 }
2254 CLEANUP_TEST( quregVec, quregMatr );
2255}

◆ TEST_CASE() [93/110]

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

Definition at line 2263 of file test_unitaries.cpp.

2263 {
2264
2265 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2266
2267 // every test will use a unique random matrix
2268 QMatrix op = getRandomUnitary(1);
2270
2271 // the zero-conditioned control qubits can be effected by notting before/after ctrls
2272 QMatrix notOp{{0,1},{1,0}};
2273
2274 SECTION( "correctness" ) {
2275
2276 int target = GENERATE( range(0,NUM_QUBITS) );
2277 int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
2278 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
2279 int* ctrlState = GENERATE_COPY( bitsets(numCtrls) );
2280
2281 SECTION( "state-vector" ) {
2282
2283 multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, target, matr);
2284
2285 // simulate controlled-state by notting before & after controls
2286 for (int i=0; i<numCtrls; i++)
2287 if (ctrlState[i] == 0)
2288 applyReferenceOp(refVec, ctrls[i], notOp);
2289 applyReferenceOp(refVec, ctrls, numCtrls, target, op);
2290 for (int i=0; i<numCtrls; i++)
2291 if (ctrlState[i] == 0)
2292 applyReferenceOp(refVec, ctrls[i], notOp);
2293
2294 REQUIRE( areEqual(quregVec, refVec) );
2295 }
2296 SECTION( "density-matrix" ) {
2297
2298 multiStateControlledUnitary(quregMatr, ctrls, ctrlState, numCtrls, target, matr);
2299
2300 // simulate controlled-state by notting before & after controls
2301 for (int i=0; i<numCtrls; i++)
2302 if (ctrlState[i] == 0)
2303 applyReferenceOp(refMatr, ctrls[i], notOp);
2304 applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
2305 for (int i=0; i<numCtrls; i++)
2306 if (ctrlState[i] == 0)
2307 applyReferenceOp(refMatr, ctrls[i], notOp);
2308
2309 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2310 }
2311 }
2312 SECTION( "input validation" ) {
2313
2314 SECTION( "number of controls" ) {
2315
2316 // v4 API permits passing zero and NUM_QUBITS controls
2317 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
2318 int ctrls[NUM_QUBITS+1];
2319 int ctrlState[NUM_QUBITS+1] = {0};
2320 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, 0, matr), ContainsSubstring("number of control qubits"));
2321 }
2322 SECTION( "repetition of controls" ) {
2323
2324 int ctrls[] = {0,1,1};
2325 int ctrlState[] = {0, 1, 0};
2326 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 2, matr), ContainsSubstring("control") && ContainsSubstring("unique"));
2327 }
2328 SECTION( "control and target collision" ) {
2329
2330 int ctrls[] = {0,1,2};
2331 int ctrlState[] = {0, 1, 0};
2332 int targ = ctrls[GENERATE( range(0,3) )];
2333 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), ContainsSubstring("control and target") );
2334 }
2335 SECTION( "qubit indices" ) {
2336
2337 int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
2338 int ctrlState[] = {0, 1, 0};
2339 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 0, matr), ContainsSubstring("Invalid control") );
2340
2341 ctrls[2] = 3; // make ctrls valid
2342 int targ = GENERATE( -1, NUM_QUBITS );
2343 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), ContainsSubstring("Invalid target") );
2344 }
2345 SECTION( "unitarity" ) {
2346
2347 matr.real[0][0] = 99999; // break matr unitarity
2348 int ctrls[] = {0};
2349 int ctrlState[1] = {0};
2350 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 1, 1, matr), ContainsSubstring("unitary") );
2351 }
2352 SECTION( "control state bits" ) {
2353
2354 // valid qubits
2355 int ctrls[] = {0, 1, 2};
2356 int ctrlState[] = {0, 0, 0};
2357 int targ = 3;
2358
2359 // make invalid
2360 ctrlState[2] = GENERATE(-1, 2);
2361 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), ContainsSubstring("state") );
2362 }
2363 }
2364 CLEANUP_TEST( quregVec, quregMatr );
2365}
Catch::Generators::GeneratorWrapper< int * > bitsets(int numBits)

◆ TEST_CASE() [94/110]

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

Definition at line 2373 of file test_unitaries.cpp.

2373 {
2374
2375 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2376 QMatrix op{{0,1},{1,0}};
2377
2378 SECTION( "correctness" ) {
2379
2380 int target = GENERATE( range(0,NUM_QUBITS) );
2381
2382 SECTION( "state-vector" ) {
2383
2384 pauliX(quregVec, target);
2385 applyReferenceOp(refVec, target, op);
2386 REQUIRE( areEqual(quregVec, refVec) );
2387 }
2388 SECTION( "density-matrix correctness" ) {
2389
2390 pauliX(quregMatr, target);
2391 applyReferenceOp(refMatr, target, op);
2392 REQUIRE( areEqual(quregMatr, refMatr) );
2393 }
2394 }
2395 SECTION( "input validation" ) {
2396
2397 SECTION( "qubit indices" ) {
2398
2399 int target = GENERATE( -1, NUM_QUBITS );
2400 REQUIRE_THROWS_WITH( pauliX(quregVec, target), ContainsSubstring("Invalid target") );
2401 }
2402 }
2403 CLEANUP_TEST( quregVec, quregMatr );
2404}

◆ TEST_CASE() [95/110]

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

Definition at line 2412 of file test_unitaries.cpp.

2412 {
2413
2414 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2415 QMatrix op{{0,-qcomp(0,1)},{qcomp(0,1),0}};
2416
2417 SECTION( "correctness" ) {
2418
2419 int target = GENERATE( range(0,NUM_QUBITS) );
2420
2421 SECTION( "state-vector" ) {
2422
2423 pauliY(quregVec, target);
2424 applyReferenceOp(refVec, target, op);
2425 REQUIRE( areEqual(quregVec, refVec) );
2426 }
2427 SECTION( "density-matrix correctness" ) {
2428
2429 pauliY(quregMatr, target);
2430 applyReferenceOp(refMatr, target, op);
2431 REQUIRE( areEqual(quregMatr, refMatr) );
2432 }
2433 }
2434 SECTION( "input validation" ) {
2435
2436 SECTION( "qubit indices" ) {
2437
2438 int target = GENERATE( -1, NUM_QUBITS );
2439 REQUIRE_THROWS_WITH( pauliY(quregVec, target), ContainsSubstring("Invalid target") );
2440 }
2441 }
2442 CLEANUP_TEST( quregVec, quregMatr );
2443}

◆ TEST_CASE() [96/110]

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

Definition at line 2451 of file test_unitaries.cpp.

2451 {
2452
2453 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2454 QMatrix op{{1,0},{0,-1}};
2455
2456 SECTION( "correctness" ) {
2457
2458 int target = GENERATE( range(0,NUM_QUBITS) );
2459
2460 SECTION( "state-vector" ) {
2461
2462 pauliZ(quregVec, target);
2463 applyReferenceOp(refVec, target, op);
2464 REQUIRE( areEqual(quregVec, refVec) );
2465 }
2466 SECTION( "density-matrix correctness" ) {
2467
2468 pauliZ(quregMatr, target);
2469 applyReferenceOp(refMatr, target, op);
2470 REQUIRE( areEqual(quregMatr, refMatr) );
2471 }
2472 }
2473 SECTION( "input validation" ) {
2474
2475 SECTION( "qubit indices" ) {
2476
2477 int target = GENERATE( -1, NUM_QUBITS );
2478 REQUIRE_THROWS_WITH( pauliZ(quregVec, target), ContainsSubstring("Invalid target") );
2479 }
2480 }
2481 CLEANUP_TEST( quregVec, quregMatr );
2482}

◆ TEST_CASE() [97/110]

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

Definition at line 2490 of file test_unitaries.cpp.

2490 {
2491
2492 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2493 qreal param = getRandomReal(-2*M_PI, 2*M_PI);
2494 QMatrix op{{1,0},{0,expI(param)}};
2495
2496 SECTION( "correctness" ) {
2497
2498 int target = GENERATE( range(0,NUM_QUBITS) );
2499
2500 SECTION( "state-vector ") {
2501
2502 phaseShift(quregVec, target, param);
2503 applyReferenceOp(refVec, target, op);
2504 REQUIRE( areEqual(quregVec, refVec) );
2505 }
2506 SECTION( "density-matrix" ) {
2507
2508 phaseShift(quregMatr, target, param);
2509 applyReferenceOp(refMatr, target, op);
2510 REQUIRE( areEqual(quregMatr, refMatr) );
2511 }
2512 }
2513 SECTION( "input validation" ) {
2514
2515 SECTION( "qubit indices" ) {
2516
2517 int target = GENERATE( -1, NUM_QUBITS );
2518 REQUIRE_THROWS_WITH( phaseShift(quregVec, target, param), ContainsSubstring("Invalid target") );
2519 }
2520 }
2521 CLEANUP_TEST( quregVec, quregMatr );
2522}

◆ TEST_CASE() [98/110]

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

Definition at line 2530 of file test_unitaries.cpp.

2530 {
2531
2532 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2533
2534 // each test will use a random parameter and axis vector
2535 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2536 Vector vec;
2537 vec.x=getRandomReal(1,2);
2538 vec.y=getRandomReal(-2,-1);
2539 vec.z=getRandomReal(-1,1); // lazily avoiding (x,y,z)=0
2540
2541 // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
2542 // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
2543 qreal c = cos(param/2);
2544 qreal s = sin(param/2);
2545 qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
2546
2547 // brackets defer division of m to improve numerical stability
2548 QMatrix op{{c - (qcomp(0,1)*vec.z*s)/m, -((vec.y + qcomp(0,1)*vec.x)*s)/m},
2549 {((vec.y - qcomp(0,1)*vec.x)*s)/m, c + (qcomp(0,1)*vec.z*s)/m}};
2550
2551 SECTION( "correctness" ) {
2552
2553 int target = GENERATE( range(0,NUM_QUBITS) );
2554
2555 SECTION( "state-vector ") {
2556
2557 rotateAroundAxis(quregVec, target, param, vec);
2558 applyReferenceOp(refVec, target, op);
2559 REQUIRE( areEqual(quregVec, refVec, 10*REAL_EPS) );
2560 }
2561 SECTION( "density-matrix" ) {
2562
2563 rotateAroundAxis(quregMatr, target, param, vec);
2564 applyReferenceOp(refMatr, target, op);
2565 REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
2566 }
2567 }
2568 SECTION( "input validation" ) {
2569
2570 SECTION( "qubit indices" ) {
2571
2572 int target = GENERATE( -1, NUM_QUBITS );
2573 REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), ContainsSubstring("Invalid target") );
2574 }
2575 SECTION( "zero rotation axis" ) {
2576
2577 int target = 0;
2578 vec.x=0; vec.y=0; vec.z=0;
2579 REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), ContainsSubstring("axis") && ContainsSubstring("zero") );
2580 }
2581 }
2582 CLEANUP_TEST( quregVec, quregMatr );
2583}

◆ TEST_CASE() [99/110]

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

Definition at line 2591 of file test_unitaries.cpp.

2591 {
2592
2593 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2594 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2595 QMatrix op{
2596 {cos(param/2), - sin(param/2)*qcomp(0,1)},
2597 {- sin(param/2)*qcomp(0,1), cos(param/2)}};
2598
2599 SECTION( "correctness" ) {
2600
2601 int target = GENERATE( range(0,NUM_QUBITS) );
2602
2603 SECTION( "state-vector ") {
2604
2605 rotateX(quregVec, target, param);
2606 applyReferenceOp(refVec, target, op);
2607 REQUIRE( areEqual(quregVec, refVec) );
2608 }
2609 SECTION( "density-matrix" ) {
2610
2611 rotateX(quregMatr, target, param);
2612 applyReferenceOp(refMatr, target, op);
2613 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2614 }
2615 }
2616 SECTION( "input validation" ) {
2617
2618 SECTION( "qubit indices" ) {
2619
2620 int target = GENERATE( -1, NUM_QUBITS );
2621 REQUIRE_THROWS_WITH( rotateX(quregVec, target, param), ContainsSubstring("Invalid target") );
2622 }
2623 }
2624 CLEANUP_TEST( quregVec, quregMatr );
2625}

◆ TEST_CASE() [100/110]

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

Definition at line 2633 of file test_unitaries.cpp.

2633 {
2634
2635 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2636 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2637 QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
2638
2639 SECTION( "correctness" ) {
2640
2641 int target = GENERATE( range(0,NUM_QUBITS) );
2642
2643 SECTION( "state-vector ") {
2644
2645 rotateY(quregVec, target, param);
2646 applyReferenceOp(refVec, target, op);
2647 REQUIRE( areEqual(quregVec, refVec) );
2648 }
2649 SECTION( "density-matrix" ) {
2650
2651 rotateY(quregMatr, target, param);
2652 applyReferenceOp(refMatr, target, op);
2653 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2654 }
2655 }
2656 SECTION( "input validation" ) {
2657
2658 SECTION( "qubit indices" ) {
2659
2660 int target = GENERATE( -1, NUM_QUBITS );
2661 REQUIRE_THROWS_WITH( rotateY(quregVec, target, param), ContainsSubstring("Invalid target") );
2662 }
2663 }
2664 CLEANUP_TEST( quregVec, quregMatr );
2665}

◆ TEST_CASE() [101/110]

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

Definition at line 2673 of file test_unitaries.cpp.

2673 {
2674
2675 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2676 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2677 QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
2678
2679 SECTION( "correctness" ) {
2680
2681 int target = GENERATE( range(0,NUM_QUBITS) );
2682
2683 SECTION( "state-vector ") {
2684
2685 rotateZ(quregVec, target, param);
2686 applyReferenceOp(refVec, target, op);
2687 REQUIRE( areEqual(quregVec, refVec) );
2688 }
2689 SECTION( "density-matrix" ) {
2690
2691 rotateZ(quregMatr, target, param);
2692 applyReferenceOp(refMatr, target, op);
2693 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2694 }
2695 }
2696 SECTION( "input validation" ) {
2697
2698 SECTION( "qubit indices" ) {
2699
2700 int target = GENERATE( -1, NUM_QUBITS );
2701 REQUIRE_THROWS_WITH( rotateZ(quregVec, target, param), ContainsSubstring("Invalid target") );
2702 }
2703 }
2704 CLEANUP_TEST( quregVec, quregMatr );
2705}

◆ TEST_CASE() [102/110]

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

Definition at line 380 of file test_state_initialisations.cpp.

380 {
381
382 Qureg vec = createForcedQureg(NUM_QUBITS);
383
384 int maxInd = vec.numAmps;
385 QVector amps = getRandomQVector(maxInd);
386
387 SECTION( "correctness" ) {
388
389 SECTION( "state-vector" ) {
390
391 // all valid number of amplitudes and offsets
392 int startInd = GENERATE_COPY( range(0,maxInd) );
393 int numAmps = GENERATE_COPY( range(0,1+maxInd-startInd) ); // upper-bound allows all amps specified
394
395 // check both specified and un-specified amplitudes are correctly handled
396 initDebugState(vec);
397 QVector vecRef = toQVector(vec);
398
399 setQuregAmps(vec, startInd, amps.data(), numAmps);
400 for (int i=0; i<numAmps; i++)
401 vecRef[startInd+i] = amps[i];
402
403 REQUIRE( areEqual(vec, vecRef) );
404 }
405 }
406 SECTION( "input validation" ) {
407
408 SECTION( "start index" ) {
409
410 int startInd = GENERATE_COPY( -1, maxInd );
411 int numAmps = 0;
412 REQUIRE_THROWS_WITH( setQuregAmps(vec, startInd, amps.data(), numAmps), ContainsSubstring("starting basis state index") );
413 }
414
415 SECTION( "number of amplitudes" ) {
416
417 // independent
418 int startInd = 0;
419 int numAmps = GENERATE_COPY( -1, maxInd+1 );
420 REQUIRE_THROWS_WITH( setQuregAmps(vec, startInd, amps.data(), numAmps), ContainsSubstring("number of amplitudes") );
421
422 // invalid considering start-index
423 startInd = maxInd - 1;
424 numAmps = 2;
425 REQUIRE_THROWS_WITH( setQuregAmps(vec, startInd, amps.data(), numAmps), ContainsSubstring("implies an end index") );
426 }
427 SECTION( "density-matrix" ) {
428
429 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
430 REQUIRE_THROWS_WITH( setQuregAmps(mat, 0, amps.data(), 0), ContainsSubstring("Expected a statevector Qureg but received a density matrix") );
431 destroyQureg(mat);
432 }
433 }
434 destroyQureg(vec);
435}
void setQuregAmps(Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)

◆ TEST_CASE() [103/110]

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

Definition at line 593 of file test_state_initialisations.cpp.

593 {
594
595 SECTION( "correctness" ) {
596
597 // repeat each test below 10 times
598 GENERATE( range(0,10) );
599
600 /* note tolerance in areEqual increases with tests, since
601 * small differences propogate in vecC which is not re-initialised
602 */
603
604 SECTION( "state-vector" ) {
605
606 // make three random vectors
607 Qureg vecA = createForcedQureg(NUM_QUBITS);
608 Qureg vecB = createForcedQureg(NUM_QUBITS);
609 Qureg vecC = createForcedQureg(NUM_QUBITS);
610 for (int j=0; j<vecA.numAmpsPerNode; j++) {
611 vecA.cpuAmps[j] = getRandomComplex();
612 vecB.cpuAmps[j] = getRandomComplex();
613 vecC.cpuAmps[j] = getRandomComplex();
614 }
615 copyStateToGPU(vecA); copyStateToGPU(vecB); copyStateToGPU(vecC);
616 QVector refA = toQVector(vecA);
617 QVector refB = toQVector(vecB);
618 QVector refC = toQVector(vecC);
619 QVector refOut;
620
621 // get three random factors
622 qcomp numA = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
623 qcomp numB = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
624 qcomp numC = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
625 Complex facA; facA.real = real(numA); facA.imag = imag(numA);
626 Complex facB; facB.real = real(numB); facB.imag = imag(numB);
627 Complex facC; facC.real = real(numC); facC.imag = imag(numC);
628
629 // check out-qureg is correct, when all quregs are unique...
630 setWeightedQureg(facA, vecA, facB, vecB, facC, vecC);
631 refOut = numA*refA + numB*refB + numC*refC;
632 REQUIRE( areEqual(vecC, refOut) );
633
634 // ... and that other qureg's aren't modified
635 REQUIRE( areEqual(vecA, refA) );
636 REQUIRE( areEqual(vecB, refB) );
637
638 // check quregOut correct, when it's also qureg2
639 refC = toQVector(vecC);
640 setWeightedQureg(facB, vecB, facC, vecC, facA, vecC);
641 refOut = numB*refB + numC*refC + numA*refC;
642 REQUIRE( areEqual(vecC, refOut, 10*REAL_EPS) );
643
644 // ... and that the remaining qureg is not modified
645 REQUIRE( areEqual(vecB, refB) );
646
647 // check quregOut correct, when it's also qureg1
648 refC = toQVector(vecC);
649 setWeightedQureg(facC, vecC, facB, vecB, facA, vecC);
650 refOut = numC*refC + numB*refB + numA*refC;
651 REQUIRE( areEqual(vecC, refOut, 10*REAL_EPS) );
652
653 // ... and that the remaining qureg is not modified
654 REQUIRE( areEqual(vecB, refB) );
655
656 // check quregOut is correct when it's both input quregs
657 refC = toQVector(vecC);
658 setWeightedQureg(facA, vecC, facB, vecC, facC, vecC);
659 refOut = numA*refC + numB*refC + numC*refC;
660 REQUIRE( areEqual(vecC, refOut, 1E3*REAL_EPS) );
661
662 // cleanup
663 destroyQureg(vecA);
664 destroyQureg(vecB);
665 destroyQureg(vecC);
666 }
667
668 // v4 does not permit superposing of density matrices
669
670 // SECTION( "density-matrix" ) {
671
672 // // make three random matrices
673 // Qureg matA = createForcedDensityQureg(NUM_QUBITS);
674 // Qureg matB = createForcedDensityQureg(NUM_QUBITS);
675 // Qureg matC = createForcedDensityQureg(NUM_QUBITS);
676 // for (int j=0; j<matA.numAmpsPerNode; j++) {
677 // matA.cpuAmps[j] = getRandomComplex();
678 // matB.cpuAmps[j] = getRandomComplex();
679 // matC.cpuAmps[j] = getRandomComplex();
680 // }
681 // copyStateToGPU(matA); copyStateToGPU(matB); copyStateToGPU(matC);
682 // QMatrix refA = toQMatrix(matA);
683 // QMatrix refB = toQMatrix(matB);
684 // QMatrix refC = toQMatrix(matC);
685 // QMatrix refOut;
686
687 // // get three random factors
688 // qcomp numA = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
689 // qcomp numB = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
690 // qcomp numC = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
691 // Complex facA; facA.real = real(numA); facA.imag = imag(numA);
692 // Complex facB; facB.real = real(numB); facB.imag = imag(numB);
693 // Complex facC; facC.real = real(numC); facC.imag = imag(numC);
694
695 // // check out-qureg is correct, when all quregs are unique...
696 // setWeightedQureg(facA, matA, facB, matB, facC, matC);
697 // refOut = numA*refA + numB*refB + numC*refC;
698 // REQUIRE( areEqual(matC, refOut) );
699
700 // // ... and that other qureg's aren't modified
701 // REQUIRE( areEqual(matA, refA) );
702 // REQUIRE( areEqual(matB, refB) );
703
704 // // check quregOut correct, when it's also qureg2
705 // refC = toQMatrix(matC);
706 // setWeightedQureg(facB, matB, facC, matC, facA, matC);
707 // refOut = numB*refB + numC*refC + numA*refC;
708 // REQUIRE( areEqual(matC, refOut, 10*REAL_EPS) );
709
710 // // ... and that the remaining qureg is not modified
711 // REQUIRE( areEqual(matB, refB) );
712
713 // // check quregOut correct, when it's also qureg1
714 // refC = toQMatrix(matC);
715 // setWeightedQureg(facC, matC, facB, matB, facA, matC);
716 // refOut = numC*refC + numB*refB + numA*refC;
717 // REQUIRE( areEqual(matC, refOut, 1E2*REAL_EPS) );
718
719 // // ... and that the remaining qureg is not modified
720 // REQUIRE( areEqual(matB, refB) );
721
722 // // check quregOut is correct when it's both input quregs
723 // refC = toQMatrix(matC);
724 // setWeightedQureg(facA, matC, facB, matC, facC, matC);
725 // refOut = numA*refC + numB*refC + numC*refC;
726 // REQUIRE( areEqual(matC, refOut, 1E3*REAL_EPS) );
727
728 // // cleanup
729 // destroyQureg(matA);
730 // destroyQureg(matB);
731 // destroyQureg(matC);
732 // }
733 }
734 SECTION( "input validation" ) {
735
736 SECTION( "qureg types" ) {
737
738 Qureg vec = createForcedQureg(NUM_QUBITS);
739 Qureg mat = createForcedDensityQureg(NUM_QUBITS);
740 Complex f; f.real = 0; f.imag = 0;
741
742 // two state-vecs, one density-matrix
743 REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, vec, f, vec), ContainsSubstring("inconsistent attributes") );
744 REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, mat, f, vec), ContainsSubstring("inconsistent attributes") );
745 REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, vec, f, mat), ContainsSubstring("inconsistent attributes") );
746
747 // one state-vec, two density-matrices
748 REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, mat, f, mat), ContainsSubstring("inconsistent attributes") );
749 REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, vec, f, mat), ContainsSubstring("inconsistent attributes") );
750 REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, mat, f, vec), ContainsSubstring("inconsistent attributes") );
751
752 destroyQureg(vec);
753 destroyQureg(mat);
754 }
755 SECTION( "qureg dimensions" ) {
756
757 Qureg vecA = createForcedQureg(NUM_QUBITS);
758 Qureg vecB = createForcedQureg(NUM_QUBITS + 1);
759 Qureg matA = createForcedDensityQureg(NUM_QUBITS);
760 Qureg matB = createForcedDensityQureg(NUM_QUBITS + 1);
761 Complex f; f.real = 0; f.imag = 0;
762
763 // state-vecs
764 REQUIRE_THROWS_WITH( setWeightedQureg(f, vecA, f, vecB, f, vecB), ContainsSubstring("inconsistent attributes") );
765 REQUIRE_THROWS_WITH( setWeightedQureg(f, vecB, f, vecA, f, vecB), ContainsSubstring("inconsistent attributes") );
766 REQUIRE_THROWS_WITH( setWeightedQureg(f, vecB, f, vecB, f, vecA), ContainsSubstring("inconsistent attributes") );
767
768 // v4 does not permit superposing density matrices
769
770 // // density-matrices
771 // REQUIRE_THROWS_WITH( setWeightedQureg(f, matA, f, matB, f, matB), ContainsSubstring("differing numbers of qubits") );
772 // REQUIRE_THROWS_WITH( setWeightedQureg(f, matB, f, matA, f, matB), ContainsSubstring("differing numbers of qubits") );
773 // REQUIRE_THROWS_WITH( setWeightedQureg(f, matB, f, matB, f, matA), ContainsSubstring("differing numbers of qubits") );
774
775 destroyQureg(vecA);
776 destroyQureg(vecB);
777 destroyQureg(matA);
778 destroyQureg(matB);
779 }
780 }
781}

◆ TEST_CASE() [104/110]

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

Definition at line 2713 of file test_unitaries.cpp.

2713 {
2714
2715 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2716 QMatrix op{{1,0},{0,qcomp(0,1)}};
2717
2718 SECTION( "correctness" ) {
2719
2720 int target = GENERATE( range(0,NUM_QUBITS) );
2721
2722 SECTION( "state-vector ") {
2723
2724 sGate(quregVec, target);
2725 applyReferenceOp(refVec, target, op);
2726 REQUIRE( areEqual(quregVec, refVec) );
2727 }
2728 SECTION( "density-matrix" ) {
2729
2730 sGate(quregMatr, target);
2731 applyReferenceOp(refMatr, target, op);
2732 REQUIRE( areEqual(quregMatr, refMatr) );
2733 }
2734 }
2735 SECTION( "input validation" ) {
2736
2737 SECTION( "qubit indices" ) {
2738
2739 int target = GENERATE( -1, NUM_QUBITS );
2740 REQUIRE_THROWS_WITH( sGate(quregVec, target), ContainsSubstring("Invalid target") );
2741 }
2742 }
2743 CLEANUP_TEST( quregVec, quregMatr );
2744}

◆ TEST_CASE() [105/110]

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

Definition at line 2752 of file test_unitaries.cpp.

2752 {
2753
2754 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2755 qcomp a = qcomp(.5, .5);
2756 qcomp b = qcomp(.5, -.5);
2757 QMatrix op{{1,0,0,0},{0,a,b,0},{0,b,a,0},{0,0,0,1}};
2758
2759 SECTION( "correctness" ) {
2760
2761 int targ1 = GENERATE( range(0,NUM_QUBITS) );
2762 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2763 int targs[] = {targ1, targ2};
2764
2765 SECTION( "state-vector" ) {
2766
2767 sqrtSwapGate(quregVec, targ1, targ2);
2768 applyReferenceOp(refVec, targs, 2, op);
2769 REQUIRE( areEqual(quregVec, refVec) );
2770 }
2771 SECTION( "density-matrix" ) {
2772
2773 sqrtSwapGate(quregMatr, targ1, targ2);
2774 applyReferenceOp(refMatr, targs, 2, op);
2775 REQUIRE( areEqual(quregMatr, refMatr) );
2776 }
2777 }
2778 SECTION( "input validation" ) {
2779
2780 SECTION( "qubit indices" ) {
2781
2782 int targ1 = GENERATE( -1, NUM_QUBITS );
2783 int targ2 = 0;
2784 REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ1, targ2), ContainsSubstring("Invalid target") );
2785 REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ2, targ1), ContainsSubstring("Invalid target") );
2786 }
2787 SECTION( "repetition of targets" ) {
2788
2789 int qb = 0;
2790 REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, qb, qb), ContainsSubstring("target") && ContainsSubstring("unique") );
2791 }
2792 }
2793 CLEANUP_TEST( quregVec, quregMatr );
2794}

◆ TEST_CASE() [106/110]

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

Definition at line 2802 of file test_unitaries.cpp.

2802 {
2803
2804 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2805 QMatrix op{{1,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1}};
2806
2807 SECTION( "correctness" ) {
2808
2809 int targ1 = GENERATE( range(0,NUM_QUBITS) );
2810 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2811 int targs[] = {targ1, targ2};
2812
2813 SECTION( "state-vector" ) {
2814
2815 swapGate(quregVec, targ1, targ2);
2816 applyReferenceOp(refVec, targs, 2, op);
2817 REQUIRE( areEqual(quregVec, refVec) );
2818 }
2819 SECTION( "density-matrix" ) {
2820
2821 swapGate(quregMatr, targ1, targ2);
2822 applyReferenceOp(refMatr, targs, 2, op);
2823 REQUIRE( areEqual(quregMatr, refMatr) );
2824 }
2825 }
2826 SECTION( "input validation" ) {
2827
2828 SECTION( "qubit indices" ) {
2829
2830 int targ1 = GENERATE( -1, NUM_QUBITS );
2831 int targ2 = 0;
2832 REQUIRE_THROWS_WITH( swapGate(quregVec, targ1, targ2), ContainsSubstring("Invalid target") );
2833 REQUIRE_THROWS_WITH( swapGate(quregVec, targ2, targ1), ContainsSubstring("Invalid target") );
2834 }
2835 SECTION( "repetition of targets" ) {
2836
2837 int qb = 0;
2838 REQUIRE_THROWS_WITH( swapGate(quregVec, qb, qb), ContainsSubstring("target") && ContainsSubstring("unique") );
2839 }
2840 }
2841 CLEANUP_TEST( quregVec, quregMatr );
2842}

◆ TEST_CASE() [107/110]

TEST_CASE ( "syncDiagonalOp" ,
"" [data_structures] )
See also
initComplexMatrixN
Author
Tyson Jones
See also
initDiagonalOp
Author
Tyson Jones
See also
initDiagonalOpFromPauliHamil
Author
Tyson Jones
See also
initPauliHamil
Author
Tyson Jones
See also
setDiagonalOpElems
Author
Tyson Jones
See also
syncDiagonalOp
Author
Tyson Jones

Definition at line 1198 of file test_data_structures.cpp.

1198 {
1199
1200 // must be at least one amplitude per node
1201 int minNumQb = calcLog2(getQuESTEnv().numNodes);
1202 if (minNumQb == 0)
1203 minNumQb = 1;
1204
1205 SECTION( "correctness" ) {
1206
1207 // try 10 valid number of qubits
1208 int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
1209
1210 // createDiagonalOp() redirects to createFullStateDiagMatr()
1211 // which auto-deploys and will auto disable distribution,
1212 // so we resort to custom invocation
1213
1214 QuESTEnv env = getQuESTEnv();
1215 DiagonalOp op = createCustomFullStateDiagMatr(numQb, env.isDistributed, env.isGpuAccelerated, env.isMultithreaded);
1216
1217 // check that changes get sync'd to the GPU...
1218 long long int n;
1219 for (n=0; n<op.numElemsPerNode; n++)
1220 op.cpuElems[n] = qcomp(n, -2*n);
1221 syncDiagonalOp(op);
1222
1223 // via if it modifies an all-unity state-vec correctly
1224 Qureg qureg = createForcedQureg(numQb);
1225 for (long long int i=0; i<qureg.numAmpsPerNode; i++)
1226 qureg.cpuAmps[i] = qcomp(1,1);
1227 copyStateToGPU(qureg);
1228
1229 // (n - 2n i) * (1 + 1i) = 3n - n*i
1230 applyDiagonalOp(qureg, op);
1231 copyStateFromGPU(qureg);
1232 for (n=0; n<qureg.numAmpsPerNode; n++) {
1233 REQUIRE( real(qureg.cpuAmps[n]) == 3*n );
1234 REQUIRE( imag(qureg.cpuAmps[n]) == -n );
1235 }
1236
1237 destroyQureg(qureg, getQuESTEnv());
1238 destroyDiagonalOp(op, getQuESTEnv());
1239 }
1240}
FullStateDiagMatr createCustomFullStateDiagMatr(int numQubits, int useDistrib, int useGpuAccel, int useMultithread)
Definition matrices.cpp:318

◆ TEST_CASE() [108/110]

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

Definition at line 2850 of file test_unitaries.cpp.

2850 {
2851
2852 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2853 QMatrix op{{1,0},{0,expI(M_PI/4.)}};
2854
2855 SECTION( "correctness" ) {
2856
2857 int target = GENERATE( range(0,NUM_QUBITS) );
2858
2859 SECTION( "state-vector ") {
2860
2861 tGate(quregVec, target);
2862 applyReferenceOp(refVec, target, op);
2863 REQUIRE( areEqual(quregVec, refVec) );
2864 }
2865 SECTION( "density-matrix" ) {
2866
2867 tGate(quregMatr, target);
2868 applyReferenceOp(refMatr, target, op);
2869 REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2870 }
2871 }
2872 SECTION( "input validation" ) {
2873
2874 SECTION( "qubit indices" ) {
2875
2876 int target = GENERATE( -1, NUM_QUBITS );
2877 REQUIRE_THROWS_WITH( tGate(quregVec, target), ContainsSubstring("Invalid target") );
2878 }
2879 }
2880 CLEANUP_TEST( quregVec, quregMatr );
2881}

◆ TEST_CASE() [109/110]

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

Definition at line 2889 of file test_unitaries.cpp.

2889 {
2890
2891 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2892
2893 // in distributed mode, each node must be able to fit all amps modified by unitary
2894 REQUIRE( quregVec.numAmpsPerNode >= 4 );
2895
2896 // every test will use a unique random matrix
2897 QMatrix op = getRandomUnitary(2);
2899
2900 SECTION( "correctness" ) {
2901
2902 int targ1 = GENERATE( range(0,NUM_QUBITS) );
2903 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2904 int targs[] = {targ1, targ2};
2905
2906 SECTION( "state-vector" ) {
2907
2908 twoQubitUnitary(quregVec, targ1, targ2, matr);
2909 applyReferenceOp(refVec, targs, 2, op);
2910 REQUIRE( areEqual(quregVec, refVec) );
2911 }
2912 SECTION( "density-matrix" ) {
2913
2914 twoQubitUnitary(quregMatr, targ1, targ2, matr);
2915 applyReferenceOp(refMatr, targs, 2, op);
2916 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2917 }
2918 }
2919 SECTION( "input validation" ) {
2920
2921 SECTION( "qubit indices" ) {
2922
2923 int targ1 = GENERATE( -1, NUM_QUBITS );
2924 int targ2 = 0;
2925 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ1, targ2, matr), ContainsSubstring("Invalid target") );
2926 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ2, targ1, matr), ContainsSubstring("Invalid target") );
2927 }
2928 SECTION( "repetition of targets" ) {
2929
2930 int qb = 0;
2931 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, qb, qb, matr), ContainsSubstring("target") && ContainsSubstring("unique") );
2932 }
2933 SECTION( "unitarity" ) {
2934
2935 matr.real[0][0] = 9999; // break matr unitarity
2936 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), ContainsSubstring("unitary") );
2937 }
2938 SECTION( "unitary fits in node" ) {
2939
2940 // pretend we have a very limited distributed memory
2941 quregVec.isDistributed = 1;
2942 quregVec.numAmpsPerNode = 1;
2943 quregVec.logNumAmpsPerNode = 0;
2944 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), ContainsSubstring("communication buffer") && ContainsSubstring("cannot simultaneously store") );
2945 }
2946 }
2947 CLEANUP_TEST( quregVec, quregMatr );
2948}

◆ TEST_CASE() [110/110]

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

Definition at line 2956 of file test_unitaries.cpp.

2956 {
2957
2958 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2959
2960 // every test will use a unique random matrix
2961 QMatrix op = getRandomUnitary(1);
2963
2964 SECTION( "correctness" ) {
2965
2966 int target = GENERATE( range(0,NUM_QUBITS) );
2967
2968 SECTION( "state-vector" ) {
2969
2970 unitary(quregVec, target, matr);
2971 applyReferenceOp(refVec, target, op);
2972 REQUIRE( areEqual(quregVec, refVec) );
2973 }
2974 SECTION( "density-matrix" ) {
2975
2976 unitary(quregMatr, target, matr);
2977 applyReferenceOp(refMatr, target, op);
2978 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2979 }
2980 }
2981 SECTION( "input validation" ) {
2982
2983 SECTION( "qubit indices" ) {
2984
2985 int target = GENERATE( -1, NUM_QUBITS );
2986 REQUIRE_THROWS_WITH( unitary(quregVec, target, matr), ContainsSubstring("Invalid target") );
2987 }
2988 SECTION( "unitarity" ) {
2989
2990 matr.real[0][0] = 9999999; // break matr unitarity
2991 REQUIRE_THROWS_WITH( unitary(quregVec, 0, matr), ContainsSubstring("unitary") );
2992 }
2993 }
2994 CLEANUP_TEST( quregVec, quregMatr );
2995}