The Quantum Exact Simulation Toolkit v4.0.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 55 of file test_operators.cpp.

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

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

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

◆ TEST_CASE() [4/110]

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

Definition at line 335 of file test_operators.cpp.

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

◆ TEST_CASE() [5/110]

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

Definition at line 439 of file test_operators.cpp.

439 {
440
441 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
442
443 // every test will use a unique random matrix
444 QMatrix op = getRandomQMatrix(2); // 2-by-2
446
447 SECTION( "correctness" ) {
448
449 int target = GENERATE( range(0,NUM_QUBITS) );
450
451 // reference boilerplate
452 int* ctrls = NULL;
453 int numCtrls = 0;
454 int targs[] = {target};
455 int numTargs = 1;
456
457 SECTION( "state-vector" ) {
458
459 applyMatrix2(quregVec, target, matr);
460 applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
461
462 REQUIRE( areEqual(quregVec, refVec) );
463 }
464 SECTION( "density-matrix" ) {
465
466 applyMatrix2(quregMatr, target, matr);
467 applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
468
469 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
470 }
471 }
472 SECTION( "input validation" ) {
473
474 SECTION( "qubit indices" ) {
475
476 int target = GENERATE( -1, NUM_QUBITS );
477 REQUIRE_THROWS_WITH( applyMatrix2(quregVec, target, matr), ContainsSubstring("Invalid target") );
478 }
479 }
480 CLEANUP_TEST( quregVec, quregMatr );
481}
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 489 of file test_operators.cpp.

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

◆ TEST_CASE() [7/110]

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

Definition at line 556 of file test_operators.cpp.

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

◆ TEST_CASE() [8/110]

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

Definition at line 670 of file test_operators.cpp.

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

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

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

◆ TEST_CASE() [11/110]

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

Definition at line 4059 of file test_operators.cpp.

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

◆ TEST_CASE() [12/110]

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

Definition at line 36 of file test_calculations.cpp.

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

◆ TEST_CASE() [13/110]

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

Definition at line 136 of file test_calculations.cpp.

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

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

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

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

◆ TEST_CASE() [17/110]

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

Definition at line 781 of file test_calculations.cpp.

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

◆ TEST_CASE() [18/110]

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

Definition at line 880 of file test_calculations.cpp.

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

◆ TEST_CASE() [19/110]

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

Definition at line 958 of file test_calculations.cpp.

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

◆ TEST_CASE() [20/110]

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

Definition at line 1090 of file test_calculations.cpp.

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

◆ TEST_CASE() [21/110]

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

Definition at line 1208 of file test_calculations.cpp.

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

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

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

◆ TEST_CASE() [24/110]

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

Definition at line 39 of file test_gates.cpp.

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

◆ TEST_CASE() [25/110]

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

Definition at line 57 of file test_unitaries.cpp.

57 {
58
59 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
60
61 qcomp a = getRandomReal(-1,1) * expI(getRandomReal(0,2*M_PI));
62 qcomp b = sqrt(1-abs(a)*abs(a)) * expI(getRandomReal(0,2*M_PI));
63 Complex alpha; alpha.real = real(a); alpha.imag = imag(a);
64 Complex beta; beta.real = real(b); beta.imag = imag(b);
65 QMatrix op{
66 {a, -conj(b)},
67 {b, conj(a)}};
68
69 SECTION( "correctness" ) {
70
71 int target = GENERATE( range(0,NUM_QUBITS) );
72
73 SECTION( "state-vector" ) {
74
75 compactUnitary(quregVec, target, alpha, beta);
76 applyReferenceOp(refVec, target, op);
77 REQUIRE( areEqual(quregVec, refVec) );
78 }
79 SECTION( "density-matrix" ) {
80
81 compactUnitary(quregMatr, target, alpha, beta);
82 applyReferenceOp(refMatr, target, op);
83 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
84 }
85 }
86 SECTION( "input validation" ) {
87
88 SECTION( "qubit indices" ) {
89
90 int target = GENERATE( -1, NUM_QUBITS );
91 REQUIRE_THROWS_WITH( compactUnitary(quregVec, target, alpha, beta), ContainsSubstring("Invalid target") );
92 }
93 SECTION( "unitarity" ) {
94
95 // unitary when |alpha|^2 + |beta|^2 = 1
96 alpha.real=1; alpha.imag=2;
97 beta.real=3; beta.imag=4;
98 REQUIRE_THROWS_WITH( compactUnitary(quregVec, 0, alpha, beta), ContainsSubstring("unitary") );
99 }
100 }
101 CLEANUP_TEST( quregVec, quregMatr );
102}
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 238 of file test_unitaries.cpp.

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

◆ TEST_CASE() [27/110]

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

Definition at line 298 of file test_unitaries.cpp.

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

◆ TEST_CASE() [28/110]

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

Definition at line 447 of file test_unitaries.cpp.

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

◆ TEST_CASE() [29/110]

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

Definition at line 493 of file test_unitaries.cpp.

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

◆ TEST_CASE() [30/110]

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

Definition at line 539 of file test_unitaries.cpp.

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

◆ TEST_CASE() [31/110]

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

Definition at line 588 of file test_unitaries.cpp.

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

◆ TEST_CASE() [32/110]

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

Definition at line 637 of file test_unitaries.cpp.

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

◆ TEST_CASE() [33/110]

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

Definition at line 702 of file test_unitaries.cpp.

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

◆ TEST_CASE() [34/110]

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

Definition at line 751 of file test_unitaries.cpp.

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

◆ TEST_CASE() [35/110]

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

Definition at line 798 of file test_unitaries.cpp.

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

◆ TEST_CASE() [36/110]

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

Definition at line 845 of file test_unitaries.cpp.

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

◆ TEST_CASE() [37/110]

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

Definition at line 925 of file test_unitaries.cpp.

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

◆ 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 91 of file test_data_structures.cpp.

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

◆ TEST_CASE() [39/110]

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

Definition at line 159 of file test_data_structures.cpp.

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

◆ TEST_CASE() [40/110]

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

Definition at line 187 of file test_data_structures.cpp.

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

◆ TEST_CASE() [41/110]

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

Definition at line 257 of file test_data_structures.cpp.

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

◆ 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 689 of file test_data_structures.cpp.

689 {
690
691 /* there is no meaningful way to test this */
692 SUCCEED( );
693}

◆ TEST_CASE() [43/110]

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

Definition at line 701 of file test_data_structures.cpp.

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

◆ TEST_CASE() [44/110]

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

Definition at line 769 of file test_data_structures.cpp.

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

◆ TEST_CASE() [45/110]

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

Definition at line 802 of file test_data_structures.cpp.

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

◆ TEST_CASE() [46/110]

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

Definition at line 833 of file test_data_structures.cpp.

833 {
834
835 /* there is no meaningful way to test this */
836 SUCCEED( );
837}

◆ TEST_CASE() [47/110]

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

Definition at line 845 of file test_data_structures.cpp.

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

◆ TEST_CASE() [48/110]

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

Definition at line 862 of file test_data_structures.cpp.

862 {
863
864 /* there is no meaningful way to test this */
865 SUCCEED( );
866}

◆ TEST_CASE() [49/110]

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

Definition at line 874 of file test_data_structures.cpp.

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

◆ TEST_CASE() [50/110]

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

Definition at line 891 of file test_data_structures.cpp.

891 {
892
893 /* there is no meaningful way to test this */
894 SUCCEED( );
895}

◆ TEST_CASE() [51/110]

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

Definition at line 110 of file test_unitaries.cpp.

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

◆ TEST_CASE() [52/110]

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

Definition at line 1349 of file test_calculations.cpp.

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

◆ TEST_CASE() [53/110]

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

Definition at line 1388 of file test_calculations.cpp.

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

◆ TEST_CASE() [54/110]

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

Definition at line 1431 of file test_calculations.cpp.

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

◆ TEST_CASE() [55/110]

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

Definition at line 1469 of file test_calculations.cpp.

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

◆ TEST_CASE() [56/110]

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

Definition at line 1502 of file test_calculations.cpp.

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

◆ TEST_CASE() [57/110]

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

Definition at line 1539 of file test_calculations.cpp.

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

◆ TEST_CASE() [58/110]

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

Definition at line 1582 of file test_calculations.cpp.

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

◆ TEST_CASE() [59/110]

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

Definition at line 977 of file test_unitaries.cpp.

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

◆ TEST_CASE() [60/110]

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

Definition at line 303 of file test_state_initialisations.cpp.

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

◆ TEST_CASE() [61/110]

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

Definition at line 107 of file test_state_initialisations.cpp.

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

◆ TEST_CASE() [62/110]

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

Definition at line 140 of file test_state_initialisations.cpp.

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

◆ TEST_CASE() [63/110]

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

Definition at line 183 of file test_state_initialisations.cpp.

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

◆ TEST_CASE() [64/110]

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

Definition at line 228 of file test_state_initialisations.cpp.

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

◆ TEST_CASE() [65/110]

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

Definition at line 342 of file test_state_initialisations.cpp.

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

◆ TEST_CASE() [66/110]

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

Definition at line 145 of file test_gates.cpp.

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

◆ TEST_CASE() [67/110]

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

Definition at line 237 of file test_gates.cpp.

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

◆ TEST_CASE() [68/110]

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

Definition at line 51 of file test_decoherence.cpp.

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

◆ TEST_CASE() [69/110]

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

Definition at line 102 of file test_decoherence.cpp.

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

◆ TEST_CASE() [70/110]

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

Definition at line 166 of file test_decoherence.cpp.

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

◆ TEST_CASE() [71/110]

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

Definition at line 213 of file test_decoherence.cpp.

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

◆ TEST_CASE() [72/110]

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

Definition at line 591 of file test_decoherence.cpp.

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

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

◆ TEST_CASE() [74/110]

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

Definition at line 672 of file test_decoherence.cpp.

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

◆ TEST_CASE() [75/110]

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

Definition at line 741 of file test_decoherence.cpp.

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

◆ TEST_CASE() [76/110]

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

Definition at line 959 of file test_decoherence.cpp.

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

◆ TEST_CASE() [77/110]

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

Definition at line 510 of file test_decoherence.cpp.

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

◆ TEST_CASE() [78/110]

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

Definition at line 1039 of file test_decoherence.cpp.

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

◆ TEST_CASE() [79/110]

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

Definition at line 1099 of file test_decoherence.cpp.

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

◆ TEST_CASE() [80/110]

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

Definition at line 1167 of file test_decoherence.cpp.

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

◆ TEST_CASE() [81/110]

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

Definition at line 1017 of file test_unitaries.cpp.

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

◆ TEST_CASE() [82/110]

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

Definition at line 1116 of file test_unitaries.cpp.

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

◆ TEST_CASE() [83/110]

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

Definition at line 1293 of file test_unitaries.cpp.

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

◆ TEST_CASE() [84/110]

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

Definition at line 1475 of file test_unitaries.cpp.

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

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

◆ TEST_CASE() [86/110]

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

Definition at line 1654 of file test_unitaries.cpp.

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

◆ TEST_CASE() [87/110]

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

Definition at line 1712 of file test_unitaries.cpp.

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

◆ TEST_CASE() [88/110]

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

Definition at line 1821 of file test_unitaries.cpp.

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

◆ TEST_CASE() [89/110]

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

Definition at line 1893 of file test_unitaries.cpp.

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

◆ TEST_CASE() [90/110]

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

Definition at line 1960 of file test_unitaries.cpp.

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

◆ TEST_CASE() [91/110]

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

Definition at line 2085 of file test_unitaries.cpp.

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

◆ TEST_CASE() [92/110]

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

Definition at line 2196 of file test_unitaries.cpp.

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

◆ TEST_CASE() [93/110]

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

Definition at line 2269 of file test_unitaries.cpp.

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

◆ TEST_CASE() [94/110]

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

Definition at line 2379 of file test_unitaries.cpp.

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

◆ TEST_CASE() [95/110]

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

Definition at line 2418 of file test_unitaries.cpp.

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

◆ TEST_CASE() [96/110]

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

Definition at line 2457 of file test_unitaries.cpp.

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

◆ TEST_CASE() [97/110]

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

Definition at line 2496 of file test_unitaries.cpp.

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

◆ TEST_CASE() [98/110]

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

Definition at line 2536 of file test_unitaries.cpp.

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

◆ TEST_CASE() [99/110]

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

Definition at line 2597 of file test_unitaries.cpp.

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

◆ TEST_CASE() [100/110]

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

Definition at line 2639 of file test_unitaries.cpp.

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

◆ TEST_CASE() [101/110]

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

Definition at line 2679 of file test_unitaries.cpp.

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

◆ TEST_CASE() [102/110]

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

Definition at line 383 of file test_state_initialisations.cpp.

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

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

◆ TEST_CASE() [104/110]

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

Definition at line 2719 of file test_unitaries.cpp.

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

◆ TEST_CASE() [105/110]

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

Definition at line 2758 of file test_unitaries.cpp.

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

◆ TEST_CASE() [106/110]

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

Definition at line 2808 of file test_unitaries.cpp.

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

◆ 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 1204 of file test_data_structures.cpp.

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

◆ TEST_CASE() [108/110]

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

Definition at line 2856 of file test_unitaries.cpp.

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

◆ TEST_CASE() [109/110]

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

Definition at line 2895 of file test_unitaries.cpp.

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

◆ TEST_CASE() [110/110]

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

Definition at line 2962 of file test_unitaries.cpp.

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