The Quantum Exact Simulation Toolkit v4.2.0
Loading...
Searching...
No Matches
test_unitaries.cpp
1/** @file
2 * Ported tests of the deprecated QuEST v3 interface,
3 * unit testing the "unitaries" module.
4 *
5 * This file should be excluded from doxygen parsing so
6 * as not to conflict with the doc of the v4 unit tests.
7 *
8 * @author Tyson Jones
9 * @author Oliver Thomson Brown (ported to Catch2 v3)
10 * @author Ali Rezaei (tested porting to QuEST v4)
11 */
12
13#include <catch2/catch_test_macros.hpp>
14#include <catch2/generators/catch_generators_range.hpp>
15#include <catch2/generators/catch_generators_adapters.hpp>
16#include <catch2/matchers/catch_matchers_string.hpp>
17
18#include "quest.h"
19#include "test_utilities.hpp"
20
21/** Prepares the needed data structures for unit testing unitaries.
22 * This creates a statevector and density matrix of the size NUM_QUBITS,
23 * and corresponding QVector and QMatrix instances for analytic comparison.
24 */
25#define PREPARE_TEST(quregVec, quregMatr, refVec, refMatr) \
26 Qureg quregVec = createForcedQureg(NUM_QUBITS); \
27 Qureg quregMatr = createForcedDensityQureg(NUM_QUBITS); \
28 initDebugState(quregVec); \
29 initDebugState(quregMatr); \
30 QVector refVec = toQVector(quregVec); \
31 QMatrix refMatr = toQMatrix(quregMatr); \
32 assertQuregAndRefInDebugState(quregVec, refVec); \
33 assertQuregAndRefInDebugState(quregMatr, refMatr); \
34 setValidationEpsilon(REAL_EPS);
35
36/** Destroys the data structures made by PREPARE_TEST */
37#define CLEANUP_TEST(quregVec, quregMatr) \
38 destroyQureg(quregVec); \
39 destroyQureg(quregMatr); \
40 setValidationEpsilon(REAL_EPS);
41
42/* allows concise use of ContainsSubstring in catch's REQUIRE_THROWS_WITH */
43using Catch::Matchers::ContainsSubstring;
44
45
46
47/** @sa compactUnitary
48 * @ingroup deprecatedtests
49 * @author Tyson Jones
50 */
51TEST_CASE( "compactUnitary", "[unitaries]" ) {
52
53 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
54
55 qcomp a = getRandomReal(-1,1) * expI(getRandomReal(0,2*M_PI));
56 qcomp b = sqrt(1-abs(a)*abs(a)) * expI(getRandomReal(0,2*M_PI));
57 Complex alpha; alpha.real = real(a); alpha.imag = imag(a);
58 Complex beta; beta.real = real(b); beta.imag = imag(b);
59 QMatrix op{
60 {a, -conj(b)},
61 {b, conj(a)}};
62
63 SECTION( "correctness" ) {
64
65 int target = GENERATE( range(0,NUM_QUBITS) );
66
67 SECTION( "state-vector" ) {
68
69 compactUnitary(quregVec, target, alpha, beta);
70 applyReferenceOp(refVec, target, op);
71 REQUIRE( areEqual(quregVec, refVec) );
72 }
73 SECTION( "density-matrix" ) {
74
75 compactUnitary(quregMatr, target, alpha, beta);
76 applyReferenceOp(refMatr, target, op);
77 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
78 }
79 }
80 SECTION( "input validation" ) {
81
82 SECTION( "qubit indices" ) {
83
84 int target = GENERATE( -1, NUM_QUBITS );
85 REQUIRE_THROWS_WITH( compactUnitary(quregVec, target, alpha, beta), ContainsSubstring("Invalid target") );
86 }
87 SECTION( "unitarity" ) {
88
89 // unitary when |alpha|^2 + |beta|^2 = 1
90 alpha.real=1; alpha.imag=2;
91 beta.real=3; beta.imag=4;
92 REQUIRE_THROWS_WITH( compactUnitary(quregVec, 0, alpha, beta), ContainsSubstring("unitary") );
93 }
94 }
95 CLEANUP_TEST( quregVec, quregMatr );
96}
97
98
99
100/** @sa diagonalUnitary
101 * @ingroup deprecatedtests
102 * @author Tyson Jones
103 */
104TEST_CASE( "diagonalUnitary", "[unitaries]" ) {
105
106 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
107
108 SECTION( "correctness" ) {
109
110 // generate all possible targets
111 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
112 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
113
114 // initialise a random unitary diagonal op
115 SubDiagonalOp op = createSubDiagonalOp(numTargs);
116 for (long long int i=0; i<op.numElems; i++) {
117 qcomp elem = getRandomComplex();
118 elem /= abs(elem);
119 op.cpuElems[i] = elem;
120 }
121 syncDiagMatr(op);
122
123 QMatrix opMatr = toQMatrix(op);
124
125 SECTION( "state-vector" ) {
126
127 diagonalUnitary(quregVec, targs, numTargs, op);
128 applyReferenceOp(refVec, targs, numTargs, opMatr);
129 REQUIRE( areEqual(quregVec, refVec) );
130 }
131 SECTION( "density-matrix" ) {
132
133 diagonalUnitary(quregMatr, targs, numTargs, op);
134 applyReferenceOp(refMatr, targs, numTargs, opMatr);
135 REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
136 }
137
138 destroySubDiagonalOp(op);
139 }
140 SECTION( "input validation" ) {
141
142 SECTION( "diagonal dimension" ) {
143
144 int numTargs = 3;
145 SubDiagonalOp op = createSubDiagonalOp(numTargs);
146 syncDiagMatr(op);
147
148 int badNumTargs = GENERATE_COPY( numTargs-1, numTargs+1 );
149 int badTargs[NUM_QUBITS+1];
150 for (int i=0; i<NUM_QUBITS+1; i++)
151 badTargs[i]=i;
152
153 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, badTargs, badNumTargs, op), ContainsSubstring("matrix has an inconsistent size") );
154 destroySubDiagonalOp(op);
155 }
156 SECTION( "number of targets" ) {
157
158 // make too many targets (which are otherwise valid)
159 SubDiagonalOp badOp = createSubDiagonalOp(NUM_QUBITS + 1);
160 int targs[NUM_QUBITS + 1];
161 for (int t=0; t<badOp.numQubits; t++)
162 targs[t] = t;
163 for (int i=0; i<badOp.numElems; i++)
164 badOp.cpuElems[i] = 1;
165 syncDiagMatr(badOp);
166
167 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, badOp.numQubits, badOp), ContainsSubstring("number of target qubits") );
168 destroySubDiagonalOp(badOp);
169 }
170 SECTION( "repetition in targets" ) {
171
172 // make a valid unitary diagonal op
173 SubDiagonalOp op = createSubDiagonalOp(3);
174 for (int i=0; i<op.numElems; i++)
175 op.cpuElems[i] = 1;
176 syncDiagMatr(op);
177
178 // make a repetition in the target list
179 int targs[] = {2,1,2};
180
181 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, op.numQubits, op), ContainsSubstring("target qubits contained duplicates") );
182 destroySubDiagonalOp(op);
183 }
184 SECTION( "qubit indices" ) {
185
186 // make a valid unitary diagonal op
187 SubDiagonalOp op = createSubDiagonalOp(3);
188 for (int i=0; i<op.numElems; i++)
189 op.cpuElems[i] = 1;
190 syncDiagMatr(op);
191
192 int targs[] = {0,1,2};
193
194 // make each target in-turn invalid
195 int badIndex = GENERATE( range(0,3) );
196 int badValue = GENERATE( -1, NUM_QUBITS );
197 targs[badIndex] = badValue;
198
199 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, op.numQubits, op), ContainsSubstring("Invalid target qubit") );
200 destroySubDiagonalOp(op);
201 }
202 SECTION( "unitarity" ) {
203
204 // make a valid unitary diagonal op
205 SubDiagonalOp op = createSubDiagonalOp(3);
206 int targs[] = {0,1,2};
207 for (int i=0; i<op.numElems; i++)
208 op.cpuElems[i] = 1;
209 syncDiagMatr(op);
210
211 // break unitarity via reals
212 op.cpuElems[2] = -9999.1;
213 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, op.numQubits, op), ContainsSubstring("unitary") );
214
215 // restore reals and break unitarity via imag
216 op.cpuElems[2] = 1;
217 op.cpuElems[3] = -9999.5;
218 REQUIRE_THROWS_WITH( diagonalUnitary(quregVec, targs, op.numQubits, op), ContainsSubstring("unitary") );
219
220 destroySubDiagonalOp(op);
221 }
222 }
223 CLEANUP_TEST( quregVec, quregMatr );
224}
225
226
227
228/** @sa controlledCompactUnitary
229 * @ingroup deprecatedtests
230 * @author Tyson Jones
231 */
232TEST_CASE( "controlledCompactUnitary", "[unitaries]" ) {
233
234 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
235
236 qcomp a = getRandomReal(-1,1) * expI(getRandomReal(0,2*M_PI));
237 qcomp b = sqrt(1-abs(a)*abs(a)) * expI(getRandomReal(0,2*M_PI));
238 Complex alpha; alpha.real = real(a); alpha.imag = imag(a);
239 Complex beta; beta.real = real(b); beta.imag = imag(b);
240 QMatrix op{
241 {a, -conj(b)},
242 {b, conj(a)}};
243
244 SECTION( "correctness" ) {
245
246 int target = GENERATE( range(0,NUM_QUBITS) );
247 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
248
249 SECTION( "state-vector" ) {
250
251 controlledCompactUnitary(quregVec, control, target, alpha, beta);
252 applyReferenceOp(refVec, control, target, op);
253 REQUIRE( areEqual(quregVec, refVec) );
254 }
255 SECTION( "density-matrix" ) {
256
257 controlledCompactUnitary(quregMatr, control, target, alpha, beta);
258 applyReferenceOp(refMatr, control, target, op);
259 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
260 }
261 }
262 SECTION( "input validation" ) {
263
264 SECTION( "control and target collision" ) {
265
266 int qb = 0;
267 REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, qb, qb, alpha, beta), ContainsSubstring("control and target") );
268 }
269 SECTION( "qubit indices" ) {
270
271 int qb = GENERATE( -1, NUM_QUBITS );
272 REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, qb, 0, alpha, beta), ContainsSubstring("Invalid control") );
273 REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, 0, qb, alpha, beta), ContainsSubstring("Invalid target") );
274 }
275 SECTION( "unitarity" ) {
276
277 // unitary when |a|^2 + |b^2 = 1
278 alpha.real=1; alpha.imag=2;
279 beta.real=3; beta.imag=4;
280 REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, 0, 1, alpha, beta), ContainsSubstring("unitary") );
281 }
282 }
283 CLEANUP_TEST( quregVec, quregMatr );
284}
285
286
287
288/** @sa controlledMultiQubitUnitary
289 * @ingroup deprecatedtests
290 * @author Tyson Jones
291 */
292TEST_CASE( "controlledMultiQubitUnitary", "[unitaries]" ) {
293
294 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
295
296 // figure out max-num targs (inclusive) allowed by hardware backend
297 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
298 if (maxNumTargs >= NUM_QUBITS)
299 maxNumTargs = NUM_QUBITS - 1; // make space for control qubit
300
301 SECTION( "correctness" ) {
302
303 // generate all possible qubit arrangements
304 int ctrl = GENERATE( range(0,NUM_QUBITS) );
305 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
306 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs, ctrl) );
307
308 // for each qubit arrangement, use a new random unitary
309 QMatrix op = getRandomUnitary(numTargs);
310 ComplexMatrixN matr = createComplexMatrixN(numTargs);
311 toComplexMatrixN(op, matr);
312
313 SECTION( "state-vector" ) {
314
315 controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr);
316 applyReferenceOp(refVec, ctrl, targs, numTargs, op);
317 REQUIRE( areEqual(quregVec, refVec) );
318 }
319 SECTION( "density-matrix" ) {
320
321 controlledMultiQubitUnitary(quregMatr, ctrl, targs, numTargs, matr);
322 applyReferenceOp(refMatr, ctrl, targs, numTargs, op);
323 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
324 }
325 destroyComplexMatrixN(matr);
326 }
327 SECTION( "input validation" ) {
328
329 SECTION( "number of targets" ) {
330
331 // there cannot be more targets than qubits in register
332 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrl is invalid)
333 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
334 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
335 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
336 syncCompMatr(matr);
337
338 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, targs, numTargs, matr), ContainsSubstring("number of target qubits"));
339
340 destroyComplexMatrixN(matr);
341 }
342 SECTION( "repetition in targets" ) {
343
344 int ctrl = 0;
345 int numTargs = 3;
346 int targs[] = {1,2,2};
347 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
348 syncCompMatr(matr);
349
350 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
351 destroyComplexMatrixN(matr);
352 }
353 SECTION( "control and target collision" ) {
354
355 int numTargs = 3;
356 int targs[] = {0,1,2};
357 int ctrl = targs[GENERATE_COPY( range(0,numTargs) )];
358 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
359 syncCompMatr(matr);
360
361 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("control and target"));
362 destroyComplexMatrixN(matr);
363 }
364 SECTION( "qubit indices" ) {
365
366 int ctrl = 0;
367 int numTargs = 3;
368 int targs[] = {1,2,3};
369 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
370 syncCompMatr(matr);
371
372 int inv = GENERATE( -1, NUM_QUBITS );
373 ctrl = inv;
374 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("Invalid control") );
375
376 ctrl = 0; // restore valid ctrl
377 targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
378 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("Invalid target") );
379
380 destroyComplexMatrixN(matr);
381 }
382 SECTION( "unitarity" ) {
383
384 int ctrl = 0;
385 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
386 ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
387 syncCompMatr(matr);
388
389 int targs[NUM_QUBITS];
390 for (int i=0; i<numTargs; i++)
391 targs[i] = i+1;
392
393 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), ContainsSubstring("unitary") );
394 destroyComplexMatrixN(matr);
395 }
396 SECTION( "unitary creation" ) {
397
398 int numTargs = 3;
399 int targs[] = {1,2,3};
400
401 ComplexMatrixN matr;
402 matr.cpuElems = NULL;
403 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, targs, numTargs, matr), ContainsSubstring("created") );
404 }
405 SECTION( "unitary dimensions" ) {
406
407 int ctrl = 0;
408 int targs[2] = {1,2};
409 ComplexMatrixN matr = createComplexMatrixN(3);
410 syncCompMatr(matr);
411
412 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size"));
413 destroyComplexMatrixN(matr);
414 }
415 SECTION( "unitary fits in node" ) {
416
417 // pretend we have a very limited distributed memory (judged by matr size)
418 quregVec.isDistributed = 1;
419 quregVec.numAmpsPerNode = 1;
420 quregVec.logNumAmpsPerNode = 0;
421 int qb[] = {1,2};
422
423 ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
424 for (int i=0; i<4; i++)
425 matr.cpuElems[i][i] = 1;
426 syncCompMatr(matr);
427
428 REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, qb, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
429 destroyComplexMatrixN(matr);
430 }
431 }
432 CLEANUP_TEST( quregVec, quregMatr );
433}
434
435
436
437/** @sa controlledNot
438 * @ingroup deprecatedtests
439 * @author Tyson Jones
440 */
441TEST_CASE( "controlledNot", "[unitaries]" ) {
442
443 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
444 QMatrix op{{0,1},{1,0}};
445
446 SECTION( "correctness" ) {
447
448 int target = GENERATE( range(0,NUM_QUBITS) );
449 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
450
451 SECTION( "state-vector" ) {
452
453 controlledNot(quregVec, control, target);
454 applyReferenceOp(refVec, control, target, op);
455 REQUIRE( areEqual(quregVec, refVec) );
456 }
457 SECTION( "density-matrix" ) {
458
459 controlledNot(quregMatr, control, target);
460 applyReferenceOp(refMatr, control, target, op);
461 REQUIRE( areEqual(quregMatr, refMatr) );
462 }
463 }
464 SECTION( "input validation" ) {
465
466 SECTION( "control and target collision" ) {
467
468 int qb = GENERATE( range(0,NUM_QUBITS) );
469 REQUIRE_THROWS_WITH( controlledNot(quregVec, qb, qb), ContainsSubstring("control and target") );
470 }
471 SECTION( "qubit indices" ) {
472
473 int qb = GENERATE( -1, NUM_QUBITS );
474 REQUIRE_THROWS_WITH( controlledNot(quregVec, qb, 0), ContainsSubstring("Invalid control") );
475 REQUIRE_THROWS_WITH( controlledNot(quregVec, 0, qb), ContainsSubstring("Invalid target") );
476 }
477 }
478 CLEANUP_TEST( quregVec, quregMatr );
479}
480
481
482
483/** @sa controlledPauliY
484 * @ingroup deprecatedtests
485 * @author Tyson Jones
486 */
487TEST_CASE( "controlledPauliY", "[unitaries]" ) {
488
489 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
490 QMatrix op{{0,-qcomp(0,1)},{qcomp(0,1),0}};
491
492 SECTION( "correctness" ) {
493
494 int target = GENERATE( range(0,NUM_QUBITS) );
495 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
496
497 SECTION( "state-vector" ) {
498
499 controlledPauliY(quregVec, control, target);
500 applyReferenceOp(refVec, control, target, op);
501 REQUIRE( areEqual(quregVec, refVec) );
502 }
503 SECTION( "density-matrix" ) {
504
505 controlledPauliY(quregMatr, control, target);
506 applyReferenceOp(refMatr, control, target, op);
507 REQUIRE( areEqual(quregMatr, refMatr) );
508 }
509 }
510 SECTION( "input validation" ) {
511
512 SECTION( "control and target collision" ) {
513
514 int qb = GENERATE( range(0,NUM_QUBITS) );
515 REQUIRE_THROWS_WITH( controlledPauliY(quregVec, qb, qb), ContainsSubstring("control and target") );
516 }
517 SECTION( "qubit indices" ) {
518
519 int qb = GENERATE( -1, NUM_QUBITS );
520 REQUIRE_THROWS_WITH( controlledPauliY(quregVec, qb, 0), ContainsSubstring("Invalid control") );
521 REQUIRE_THROWS_WITH( controlledPauliY(quregVec, 0, qb), ContainsSubstring("Invalid target") );
522 }
523 }
524 CLEANUP_TEST( quregVec, quregMatr );
525}
526
527
528
529/** @sa controlledPhaseFlip
530 * @ingroup deprecatedtests
531 * @author Tyson Jones
532 */
533TEST_CASE( "controlledPhaseFlip", "[unitaries]" ) {
534
535 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
536 QMatrix op{{1,0},{0,-1}};
537
538 SECTION( "correctness" ) {
539
540 int target = GENERATE( range(0,NUM_QUBITS) );
541 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
542
543 SECTION( "state-vector" ) {
544
545 controlledPhaseFlip(quregVec, control, target);
546 applyReferenceOp(refVec, control, target, op);
547 REQUIRE( areEqual(quregVec, refVec) );
548 }
549 SECTION( "density-matrix" ) {
550
551 controlledPhaseFlip(quregMatr, control, target);
552 applyReferenceOp(refMatr, control, target, op);
553 REQUIRE( areEqual(quregMatr, refMatr) );
554 }
555 }
556 SECTION( "input validation" ) {
557
558 // in v4, all arguments are considered targets, not controls
559
560 SECTION( "target collision" ) {
561
562 int qb = GENERATE( range(0,NUM_QUBITS) );
563 REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, qb, qb), ContainsSubstring("target qubits contained duplicates") );
564 }
565
566 SECTION( "target indices" ) {
567
568 int qb = GENERATE( -1, NUM_QUBITS );
569 REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, qb, 0), ContainsSubstring("Invalid target") );
570 REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, 0, qb), ContainsSubstring("Invalid target") );
571 }
572 }
573 CLEANUP_TEST( quregVec, quregMatr );
574}
575
576
577
578/** @sa controlledPhaseShift
579 * @ingroup deprecatedtests
580 * @author Tyson Jones
581 */
582TEST_CASE( "controlledPhaseShift", "[unitaries]" ) {
583
584 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
585 qreal param = getRandomReal(-2*M_PI, 2*M_PI);
586 QMatrix op{{1,0},{0,expI(param)}};
587
588 SECTION( "correctness" ) {
589
590 int target = GENERATE( range(0,NUM_QUBITS) );
591 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
592
593 SECTION( "state-vector" ) {
594
595 controlledPhaseShift(quregVec, control, target, param);
596 applyReferenceOp(refVec, control, target, op);
597 REQUIRE( areEqual(quregVec, refVec) );
598 }
599 SECTION( "density-matrix" ) {
600
601 controlledPhaseShift(quregMatr, control, target, param);
602 applyReferenceOp(refMatr, control, target, op);
603 REQUIRE( areEqual(quregMatr, refMatr) );
604 }
605 }
606 SECTION( "input validation" ) {
607
608 // in v4, all arguments are considered targets
609
610 SECTION( "target collision" ) {
611
612 int qb = GENERATE( range(0,NUM_QUBITS) );
613 REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, qb, qb, param), ContainsSubstring("target qubits contained duplicates") );
614 }
615 SECTION( "qubit indices" ) {
616
617 int qb = GENERATE( -1, NUM_QUBITS );
618 REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, qb, 0, param), ContainsSubstring("Invalid target") );
619 REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, 0, qb, param), ContainsSubstring("Invalid target") );
620 }
621 }
622 CLEANUP_TEST( quregVec, quregMatr );
623}
624
625
626
627/** @sa controlledRotateAroundAxis
628 * @ingroup deprecatedtests
629 * @author Tyson Jones
630 */
631TEST_CASE( "controlledRotateAroundAxis", "[unitaries]" ) {
632
633 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
634
635 // each test will use a random parameter and axis vector
636 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
637 Vector vec;
638 vec.x=getRandomReal(1,2);
639 vec.y=getRandomReal(-2,-1);
640 vec.z=getRandomReal(-1,1); // lazily avoiding (x,y,z)=0
641
642 // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
643 // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
644 qreal c = cos(param/2);
645 qreal s = sin(param/2);
646 qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
647 QMatrix op{{c - qcomp(0,1)*vec.z*s/m, -(vec.y + qcomp(0,1)*vec.x)*s/m},
648 {(vec.y - qcomp(0,1)*vec.x)*s/m, c + qcomp(0,1)*vec.z*s/m}};
649
650 SECTION( "correctness" ) {
651
652 int target = GENERATE( range(0,NUM_QUBITS) );
653 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
654
655 SECTION( "state-vector" ) {
656
657 controlledRotateAroundAxis(quregVec, control, target, param, vec);
658 applyReferenceOp(refVec, control, target, op);
659 REQUIRE( areEqual(quregVec, refVec) );
660 }
661 SECTION( "density-matrix" ) {
662
663 controlledRotateAroundAxis(quregMatr, control, target, param, vec);
664 applyReferenceOp(refMatr, control, target, op);
665 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
666 }
667 }
668 SECTION( "input validation" ) {
669
670 SECTION( "control and target collision" ) {
671
672 int qb = GENERATE( range(0,NUM_QUBITS) );
673 REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, qb, qb, param, vec), ContainsSubstring("control and target") );
674 }
675 SECTION( "qubit indices" ) {
676
677 int qb = GENERATE( -1, NUM_QUBITS );
678 REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, qb, 0, param, vec), ContainsSubstring("Invalid control") );
679 REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, 0, qb, param, vec), ContainsSubstring("Invalid target") );
680 }
681 SECTION( "zero rotation axis" ) {
682
683 vec.x=0; vec.y=0; vec.z=0;
684 REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, 0, 1, param, vec), ContainsSubstring("axis") && ContainsSubstring("zero") );
685 }
686 }
687 CLEANUP_TEST( quregVec, quregMatr );
688}
689
690
691
692/** @sa controlledRotateX
693 * @ingroup deprecatedtests
694 * @author Tyson Jones
695 */
696TEST_CASE( "controlledRotateX", "[unitaries]" ) {
697
698 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
699 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
700 QMatrix op{
701 {cos(param/2), -sin(param/2)*qcomp(0,1)},
702 {-sin(param/2)*qcomp(0,1), cos(param/2)}};
703
704 SECTION( "correctness" ) {
705
706 int target = GENERATE( range(0,NUM_QUBITS) );
707 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
708
709 SECTION( "state-vector" ) {
710
711 controlledRotateX(quregVec, control, target, param);
712 applyReferenceOp(refVec, control, target, op);
713 REQUIRE( areEqual(quregVec, refVec) );
714 }
715 SECTION( "density-matrix" ) {
716
717 controlledRotateX(quregMatr, control, target, param);
718 applyReferenceOp(refMatr, control, target, op);
719 REQUIRE( areEqual(quregMatr, refMatr) );
720 }
721 }
722 SECTION( "input validation" ) {
723
724 SECTION( "control and target collision" ) {
725
726 int qb = GENERATE( range(0,NUM_QUBITS) );
727 REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, qb, param), ContainsSubstring("control and target") );
728 }
729 SECTION( "qubit indices" ) {
730
731 int qb = GENERATE( -1, NUM_QUBITS );
732 REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, 0, param), ContainsSubstring("Invalid control") );
733 REQUIRE_THROWS_WITH( controlledRotateX(quregVec, 0, qb, param), ContainsSubstring("Invalid target") );
734 }
735 }
736 CLEANUP_TEST( quregVec, quregMatr );
737}
738
739
740
741/** @sa controlledRotateY
742 * @ingroup deprecatedtests
743 * @author Tyson Jones
744 */
745TEST_CASE( "controlledRotateY", "[unitaries]" ) {
746
747 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
748 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
749 QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
750
751 SECTION( "correctness" ) {
752
753 int target = GENERATE( range(0,NUM_QUBITS) );
754 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
755
756 SECTION( "state-vector" ) {
757
758 controlledRotateY(quregVec, control, target, param);
759 applyReferenceOp(refVec, control, target, op);
760 REQUIRE( areEqual(quregVec, refVec) );
761 }
762 SECTION( "density-matrix" ) {
763
764 controlledRotateY(quregMatr, control, target, param);
765 applyReferenceOp(refMatr, control, target, op);
766 REQUIRE( areEqual(quregMatr, refMatr, 4*REAL_EPS) );
767 }
768 }
769 SECTION( "input validation" ) {
770
771 SECTION( "control and target collision" ) {
772
773 int qb = GENERATE( range(0,NUM_QUBITS) );
774 REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, qb, param), ContainsSubstring("control and target") );
775 }
776 SECTION( "qubit indices" ) {
777
778 int qb = GENERATE( -1, NUM_QUBITS );
779 REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, 0, param), ContainsSubstring("Invalid control") );
780 REQUIRE_THROWS_WITH( controlledRotateY(quregVec, 0, qb, param), ContainsSubstring("Invalid target") );
781 }
782 }
783 CLEANUP_TEST( quregVec, quregMatr );
784}
785
786
787
788/** @sa controlledRotateZ
789 * @ingroup deprecatedtests
790 * @author Tyson Jones
791 */
792TEST_CASE( "controlledRotateZ", "[unitaries]" ) {
793
794 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
795 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
796 QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
797
798 SECTION( "correctness" ) {
799
800 int target = GENERATE( range(0,NUM_QUBITS) );
801 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
802
803 SECTION( "state-vector" ) {
804
805 controlledRotateZ(quregVec, control, target, param);
806 applyReferenceOp(refVec, control, target, op);
807 REQUIRE( areEqual(quregVec, refVec) );
808 }
809 SECTION( "density-matrix" ) {
810
811 controlledRotateZ(quregMatr, control, target, param);
812 applyReferenceOp(refMatr, control, target, op);
813 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
814 }
815 }
816 SECTION( "input validation" ) {
817
818 SECTION( "control and target collision" ) {
819
820 int qb = GENERATE( range(0,NUM_QUBITS) );
821 REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, qb, param), ContainsSubstring("control and target") );
822 }
823 SECTION( "qubit indices" ) {
824
825 int qb = GENERATE( -1, NUM_QUBITS );
826 REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, 0, param), ContainsSubstring("Invalid control") );
827 REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, 0, qb, param), ContainsSubstring("Invalid target") );
828 }
829 }
830 CLEANUP_TEST( quregVec, quregMatr );
831}
832
833
834
835/** @sa controlledTwoQubitUnitary
836 * @ingroup deprecatedtests
837 * @author Tyson Jones
838 */
839TEST_CASE( "controlledTwoQubitUnitary", "[unitaries]" ) {
840
841 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
842
843 // in distributed mode, each node must be able to fit all amps modified by unitary
844 REQUIRE( quregVec.numAmpsPerNode >= 4 );
845
846 // every test will use a unique random matrix
849
850 SECTION( "correctness" ) {
851
852 int targ1 = GENERATE( range(0,NUM_QUBITS) );
853 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
854 int control = GENERATE_COPY( filter([=](int c){ return c!=targ1 && c!=targ2; }, range(0,NUM_QUBITS)) );
855
856 SECTION( "state-vector" ) {
857
858 controlledTwoQubitUnitary(quregVec, control, targ1, targ2, matr);
859 applyReferenceOp(refVec, control, targ1, targ2, op);
860 REQUIRE( areEqual(quregVec, refVec) );
861 }
862 SECTION( "density-matrix" ) {
863
864 controlledTwoQubitUnitary(quregMatr, control, targ1, targ2, matr);
865 applyReferenceOp(refMatr, control, targ1, targ2, op);
866 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
867 }
868 }
869 SECTION( "input validation" ) {
870
871 SECTION( "repetition of targets" ) {
872 int targ = 0;
873 int ctrl = 1;
874 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ, targ, matr), ContainsSubstring("target") && ContainsSubstring("unique") );
875 }
876 SECTION( "control and target collision" ) {
877
878 int targ1 = 1;
879 int targ2 = 2;
880 int ctrl = GENERATE( 1,2 ); // catch2 bug; can't do GENERATE_COPY( targ1, targ2 )
881 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, targ2, matr), ContainsSubstring("control and target") );
882 }
883 SECTION( "qubit indices" ) {
884
885 // valid config
886 int ctrl = 0;
887 int targ1 = 1;
888 int targ2 = 2;
889
890 int qb = GENERATE( -1, NUM_QUBITS );
891 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, qb, targ1, targ2, matr), ContainsSubstring("Invalid control") );
892 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, qb, targ2, matr), ContainsSubstring("Invalid target") );
893 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, qb, matr), ContainsSubstring("Invalid target") );
894 }
895 SECTION( "unitarity" ) {
896
897 matr.real[0][0] = 999; // break matr unitarity
898 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), ContainsSubstring("unitary") );
899 }
900 SECTION( "unitary fits in node" ) {
901
902 // pretend we have a very limited distributed memory
903 quregVec.isDistributed = 1;
904 quregVec.numAmpsPerNode = 1;
905 quregVec.logNumAmpsPerNode = 0;
906
907 REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
908 }
909 }
910 CLEANUP_TEST( quregVec, quregMatr );
911}
912
913
914
915/** @sa controlledUnitary
916 * @ingroup deprecatedtests
917 * @author Tyson Jones
918 */
919TEST_CASE( "controlledUnitary", "[unitaries]" ) {
920
921 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
924
925 SECTION( "correctness" ) {
926
927 int target = GENERATE( range(0,NUM_QUBITS) );
928 int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
929
930 SECTION( "state-vector" ) {
931
932 controlledUnitary(quregVec, control, target, matr);
933 applyReferenceOp(refVec, control, target, op);
934 REQUIRE( areEqual(quregVec, refVec) );
935 }
936 SECTION( "density-matrix" ) {
937
938 controlledUnitary(quregMatr, control, target, matr);
939 applyReferenceOp(refMatr, control, target, op);
940 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
941 }
942 }
943 SECTION( "input validation" ) {
944
945 SECTION( "control and target collision" ) {
946
947 int qb = GENERATE( range(0,NUM_QUBITS) );
948 REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, qb, matr), ContainsSubstring("control and target") );
949 }
950 SECTION( "qubit indices" ) {
951
952 int qb = GENERATE( -1, NUM_QUBITS );
953 REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, 0, matr), ContainsSubstring("Invalid control") );
954 REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, qb, matr), ContainsSubstring("Invalid target") );
955 }
956 SECTION( "unitarity" ) {
957
958 matr.real[0][0] = 9999; // break unitarity
959 REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, 1, matr), ContainsSubstring("unitary") );
960 }
961 }
962 CLEANUP_TEST( quregVec, quregMatr );
963}
964
965
966
967/** @sa hadamard
968 * @ingroup deprecatedtests
969 * @author Tyson Jones
970 */
971TEST_CASE( "hadamard", "[unitaries]" ) {
972
973 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
974 qreal a = 1/sqrt(2);
975 QMatrix op{{a,a},{a,-a}};
976
977 SECTION( "correctness" ) {
978
979 int target = GENERATE( range(0,NUM_QUBITS) );
980
981 SECTION( "state-vector ") {
982
983 hadamard(quregVec, target);
984 applyReferenceOp(refVec, target, op);
985 REQUIRE( areEqual(quregVec, refVec) );
986 }
987 SECTION( "density-matrix" ) {
988
989 hadamard(quregMatr, target);
990 applyReferenceOp(refMatr, target, op);
991 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
992 }
993 }
994 SECTION( "input validation" ) {
995
996 SECTION( "qubit indices" ) {
997
998 int target = GENERATE( -1, NUM_QUBITS );
999 REQUIRE_THROWS_WITH( hadamard(quregVec, target), ContainsSubstring("Invalid target") );
1000 }
1001 }
1002 CLEANUP_TEST( quregVec, quregMatr );
1003}
1004
1005
1006
1007/** @sa multiControlledMultiQubitNot
1008 * @ingroup deprecatedtests
1009 * @author Tyson Jones
1010 */
1011TEST_CASE( "multiControlledMultiQubitNot", "[unitaries]" ) {
1012
1013 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1014
1015 SECTION( "correctness" ) {
1016
1017 // try all possible numbers of targets and controls
1018 int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for 1 ctrl
1019 int maxNumCtrls = NUM_QUBITS - numTargs;
1020 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1021
1022 // generate all possible valid qubit arrangements
1023 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1024 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1025
1026 // for each qubit arrangement, use a new random unitary
1027 QMatrix notOp{{0, 1},{1,0}};
1028
1029 SECTION( "state-vector" ) {
1030
1031 multiControlledMultiQubitNot(quregVec, ctrls, numCtrls, targs, numTargs);
1032 for (int t=0; t<numTargs; t++)
1033 applyReferenceOp(refVec, ctrls, numCtrls, targs[t], notOp);
1034
1035 REQUIRE( areEqual(quregVec, refVec) );
1036 }
1037 SECTION( "density-matrix" ) {
1038
1039 multiControlledMultiQubitNot(quregMatr, ctrls, numCtrls, targs, numTargs);
1040 for (int t=0; t<numTargs; t++)
1041 applyReferenceOp(refMatr, ctrls, numCtrls, targs[t], notOp);
1042
1043 REQUIRE( areEqual(quregMatr, refMatr) );
1044 }
1045 }
1046 SECTION( "input validation" ) {
1047
1048 SECTION( "number of targets" ) {
1049
1050 // there cannot be more targets than qubits in register
1051 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1052 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1053 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1054 int ctrls[] = {0};
1055 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 1, targs, numTargs), ContainsSubstring("number of target qubits"));
1056 }
1057 SECTION( "repetition in targets" ) {
1058
1059 int ctrls[] = {0};
1060 int numTargs = 3;
1061 int targs[] = {1,2,2};
1062 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 1, targs, numTargs), ContainsSubstring("target") && ContainsSubstring("unique"));
1063 }
1064 SECTION( "number of controls" ) {
1065
1066 // v4 API permits passing zero controls
1067 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1068 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1069 for (int i=0; i<NUM_QUBITS+1; i++)
1070 ctrls[i] = i+1;
1071 int targs[1] = {0};
1072 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, numCtrls, targs, 1), ContainsSubstring("number of control qubits"));
1073 }
1074 SECTION( "repetition in controls" ) {
1075
1076 int ctrls[] = {0,1,1};
1077 int targs[] = {3};
1078 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 3, targs, 1), ContainsSubstring("control") && ContainsSubstring("unique"));
1079 }
1080 SECTION( "control and target collision" ) {
1081
1082 int ctrls[] = {0,1,2};
1083 int targs[] = {3,1,4};
1084 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 3, targs, 3), ContainsSubstring("control and target"));
1085 }
1086 SECTION( "qubit indices" ) {
1087
1088 // valid inds
1089 int numQb = 2;
1090 int qb1[2] = {0,1};
1091 int qb2[2] = {2,3};
1092
1093 // make qb1 invalid
1094 int inv = GENERATE( -1, NUM_QUBITS );
1095 qb1[GENERATE_COPY(range(0,numQb))] = inv;
1096
1097 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, qb1, numQb, qb2, numQb), ContainsSubstring("Invalid control") );
1098 REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, qb2, numQb, qb1, numQb), ContainsSubstring("Invalid target") );
1099 }
1100 }
1101 CLEANUP_TEST( quregVec, quregMatr );
1102}
1103
1104
1105
1106/** @sa multiControlledMultiQubitUnitary
1107 * @ingroup deprecatedtests
1108 * @author Tyson Jones
1109 */
1110TEST_CASE( "multiControlledMultiQubitUnitary", "[unitaries]" ) {
1111
1112 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1113
1114 // figure out max-num targs (inclusive) allowed by hardware backend
1115 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
1116 if (maxNumTargs >= NUM_QUBITS)
1117 maxNumTargs = NUM_QUBITS - 1; // leave room for min-number of control qubits
1118
1119 SECTION( "correctness" ) {
1120
1121 // try all possible numbers of targets and controls
1122 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
1123 int maxNumCtrls = NUM_QUBITS - numTargs;
1124 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1125
1126 // generate all possible valid qubit arrangements
1127 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1128 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1129
1130 // for each qubit arrangement, use a new random unitary
1131 QMatrix op = getRandomUnitary(numTargs);
1132 ComplexMatrixN matr = createComplexMatrixN(numTargs);
1133 toComplexMatrixN(op, matr);
1134
1135 SECTION( "state-vector" ) {
1136
1137 multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, numTargs, matr);
1138 applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
1139 REQUIRE( areEqual(quregVec, refVec) );
1140 }
1141 SECTION( "density-matrix" ) {
1142
1143 multiControlledMultiQubitUnitary(quregMatr, ctrls, numCtrls, targs, numTargs, matr);
1144 applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
1145 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1146 }
1147 destroyComplexMatrixN(matr);
1148 }
1149 SECTION( "input validation" ) {
1150
1151 SECTION( "number of targets" ) {
1152
1153 // there cannot be more targets than qubits in register
1154 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1155 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1156 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1157 int ctrls[] = {0};
1158 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
1159 toComplexMatrixN(getRandomUnitary(NUM_QUBITS+1), matr); // ensure unitary
1160
1161 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), ContainsSubstring("number of target qubits"));
1162 destroyComplexMatrixN(matr);
1163 }
1164 SECTION( "repetition in targets" ) {
1165
1166 int ctrls[] = {0};
1167 int numTargs = 3;
1168 int targs[] = {1,2,2};
1169 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1170 toComplexMatrixN(getRandomUnitary(numTargs), matr); // ensure unitary
1171
1172 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
1173 destroyComplexMatrixN(matr);
1174 }
1175 SECTION( "number of controls" ) {
1176
1177 // v4 API permits passing zero controls
1178 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1179 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1180 for (int i=0; i<NUM_QUBITS+1; i++)
1181 ctrls[i] = i+1;
1182 int targs[1] = {0};
1183 ComplexMatrixN matr = createComplexMatrixN(1);
1184 toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
1185
1186 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, 1, matr), ContainsSubstring("number of control qubits"));
1187 destroyComplexMatrixN(matr);
1188 }
1189 SECTION( "repetition in controls" ) {
1190
1191 int ctrls[] = {0,1,1};
1192 int targs[] = {3};
1193 ComplexMatrixN matr = createComplexMatrixN(1);
1194 toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
1195
1196 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 1, matr), ContainsSubstring("control") && ContainsSubstring("unique"));
1197 destroyComplexMatrixN(matr);
1198 }
1199 SECTION( "control and target collision" ) {
1200
1201 int ctrls[] = {0,1,2};
1202 int targs[] = {3,1,4};
1203 ComplexMatrixN matr = createComplexMatrixN(3);
1204 toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
1205
1206 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 3, matr), ContainsSubstring("control and target"));
1207 destroyComplexMatrixN(matr);
1208 }
1209 SECTION( "qubit indices" ) {
1210
1211 // valid inds
1212 int numQb = 2;
1213 int qb1[2] = {0,1};
1214 int qb2[2] = {2,3};
1215 ComplexMatrixN matr = createComplexMatrixN(numQb);
1216 toComplexMatrixN(getRandomUnitary(numQb), matr); // ensure unitary
1217
1218 // make qb1 invalid
1219 int inv = GENERATE( -1, NUM_QUBITS );
1220 qb1[GENERATE_COPY(range(0,numQb))] = inv;
1221
1222 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb1, numQb, qb2, numQb, matr), ContainsSubstring("Invalid control") );
1223 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb2, numQb, qb1, numQb, matr), ContainsSubstring("Invalid target") );
1224 destroyComplexMatrixN(matr);
1225 }
1226 SECTION( "unitarity" ) {
1227
1228 int ctrls[1] = {0};
1229 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
1230 int targs[NUM_QUBITS];
1231 for (int i=0; i<numTargs; i++)
1232 targs[i] = i+1;
1233
1234 ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
1235 syncCompMatr(matr);
1236
1237 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), ContainsSubstring("unitary") );
1238
1239 destroyComplexMatrixN(matr);
1240 }
1241 SECTION( "unitary creation" ) {
1242
1243 int ctrls[1] = {0};
1244 int targs[3] = {1,2,3};
1245
1246 ComplexMatrixN matr;
1247 matr.cpuElems = NULL;
1248 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 3, matr), ContainsSubstring("created") );
1249 }
1250 SECTION( "unitary dimensions" ) {
1251
1252 int ctrls[1] = {0};
1253 int targs[2] = {1,2};
1254 ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
1255 toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
1256
1257 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size"));
1258 destroyComplexMatrixN(matr);
1259 }
1260 SECTION( "unitary fits in node" ) {
1261
1262 // pretend we have a very limited distributed memory (judged by matr size)
1263 quregVec.isDistributed = 1;
1264 quregVec.numAmpsPerNode = 1;
1265 quregVec.logNumAmpsPerNode = 0;
1266
1267 int ctrls[1] = {0};
1268 int targs[2] = {1,2};
1269 ComplexMatrixN matr = createComplexMatrixN(2);
1270 for (int i=0; i<4; i++)
1271 matr.cpuElems[i][i] = 1;
1272 syncCompMatr(matr);
1273
1274 REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
1275 destroyComplexMatrixN(matr);
1276 }
1277 }
1278 CLEANUP_TEST( quregVec, quregMatr );
1279}
1280
1281
1282
1283/** @sa multiControlledMultiRotatePauli
1284 * @ingroup deprecatedtests
1285 * @author Tyson Jones
1286 */
1287TEST_CASE( "multiControlledMultiRotatePauli", "[unitaries]" ) {
1288
1289 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1290 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1291
1292 SECTION( "correctness" ) {
1293
1294 // try all possible numbers of targets and controls
1295 int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for min 1 control qubit
1296 int maxNumCtrls = NUM_QUBITS - numTargs;
1297 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1298
1299 // generate all possible valid qubit arrangements
1300 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1301 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1302
1303 /* it's too expensive to try ALL Pauli sequences, via
1304 * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
1305 * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
1306 * Hence, we instead opt to randomly generate pauliseqs
1307 */
1308 pauliOpType paulis[NUM_QUBITS];
1309 for (int i=0; i<numTargs; i++)
1310 paulis[i] = (pauliOpType) getRandomInt(1,4); // exclude 0=Id
1311
1312 // exclude identities from reference matrix exp (they apply unwanted global phase)
1313 int refTargs[NUM_QUBITS];
1314 int numRefTargs = 0;
1315
1316 QMatrix xMatr{{0,1},{1,0}};
1317 QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
1318 QMatrix zMatr{{1,0},{0,-1}};
1319
1320 // build correct reference matrix by pauli-matrix exponentiation...
1321 QMatrix pauliProd{{1}};
1322 for (int i=0; i<numTargs; i++) {
1323 QMatrix fac;
1324 if (paulis[i] == PAULI_I) continue; // exclude I-targets from ref list
1325 if (paulis[i] == PAULI_X) fac = xMatr;
1326 if (paulis[i] == PAULI_Y) fac = yMatr;
1327 if (paulis[i] == PAULI_Z) fac = zMatr;
1328 pauliProd = getKroneckerProduct(fac, pauliProd);
1329
1330 // include this target in ref list
1331 refTargs[numRefTargs++] = targs[i];
1332 }
1333
1334 // produces exp(-i param/2 pauliProd), unless pauliProd = I
1335 QMatrix op;
1336 if (numRefTargs > 0)
1337 op = getExponentialOfPauliMatrix(param, pauliProd);
1338
1339 SECTION( "state-vector" ) {
1340
1341 multiControlledMultiRotatePauli(quregVec, ctrls, numCtrls, targs, paulis, numTargs, param);
1342 if (numRefTargs > 0)
1343 applyReferenceOp(refVec, ctrls, numCtrls, refTargs, numRefTargs, op);
1344 REQUIRE( areEqual(quregVec, refVec) );
1345 }
1346 SECTION( "density-matrix" ) {
1347
1348 multiControlledMultiRotatePauli(quregMatr, ctrls, numCtrls, targs, paulis, numTargs, param);
1349 if (numRefTargs > 0)
1350 applyReferenceOp(refMatr, ctrls, numCtrls, refTargs, numRefTargs, op);
1351 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1352 }
1353 }
1354 SECTION( "input validation" ) {
1355
1356 // test all validation on both state-vector and density-matrix.
1357 // want GENERATE_COPY( quregVec, quregMatr ), but too lazy to patch
1358 // using github.com/catchorg/Catch2/issues/1809
1359 Qureg regs[] = {quregVec, quregMatr};
1360 Qureg qureg = regs[GENERATE(0,1)];
1361
1362 // over-sized array to prevent seg-fault in case of validation fail below
1363 pauliOpType paulis[NUM_QUBITS+1];
1364 for (int q=0; q<NUM_QUBITS+1; q++)
1365 paulis[q] = PAULI_I;
1366
1367 SECTION( "pauli codes" ) {
1368
1369 int numCtrls = 1;
1370 int ctrls[] = {3};
1371 int numTargs = 3;
1372 int targs[3] = {0, 1, 2};
1373
1374 // make a single Pauli invalid
1375 paulis[GENERATE_COPY(range(0,numTargs))] = (pauliOpType) GENERATE( -1, 4 );
1376
1377 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("invalid Pauli code"));
1378 }
1379 SECTION( "number of targets" ) {
1380
1381 // zero non-Id Paulis are permitted in v4 (effecting Identity)
1382
1383 // there cannot be more targets than qubits in register
1384 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1385 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1386 for (int i=0; i<NUM_QUBITS+1; i++)
1387 targs[i] = i+1;
1388 int numCtrls = 1;
1389 int ctrls[] = {0};
1390
1391 // in v4, Id Paulis do not contribute to numTargets
1392 for (int i=0; i<NUM_QUBITS; i++)
1393 paulis[i] = PAULI_X;
1394
1395 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, -1, param), ContainsSubstring("must contain at least one Pauli operator") );
1396 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, NUM_QUBITS+1, param), ContainsSubstring("non-identity Pauli operator") && ContainsSubstring("exceeds the maximum target") );
1397 }
1398 SECTION( "repetition in targets" ) {
1399
1400 int numCtrls = 1;
1401 int numTargs = 3;
1402 int ctrls[] = {0};
1403 int targs[] = {1,2,2};
1404
1405 for (int i=0; i<NUM_QUBITS; i++)
1406 paulis[i] = PAULI_X;
1407
1408 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("Pauli indices") && ContainsSubstring("duplicate"));
1409 }
1410 SECTION( "number of controls" ) {
1411
1412 // v4 API permits passing zero and NUM_QUBITS controls
1413 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1414 int numTargs = 1;
1415 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1416 for (int i=0; i<NUM_QUBITS+1; i++)
1417 ctrls[i] = i+1;
1418 int targs[1] = {0};
1419
1420 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("number of control qubits"));
1421 }
1422 SECTION( "repetition in controls" ) {
1423
1424 int numCtrls = 3;
1425 int numTargs = 1;
1426 int ctrls[] = {0,1,1};
1427 int targs[] = {3};
1428
1429 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("control") && ContainsSubstring("unique"));
1430 }
1431 SECTION( "control and target collision" ) {
1432
1433 int numCtrls = 3;
1434 int numTargs = 3;
1435 int ctrls[] = {0,1,2};
1436 int targs[] = {3,1,4};
1437 for (int i=0; i<numTargs; i++)
1438 paulis[i] = PAULI_X;
1439
1440 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), ContainsSubstring("control qubit overlaps a non-identity Pauli"));
1441 }
1442 SECTION( "qubit indices" ) {
1443
1444 // valid inds
1445 int numQb = 2;
1446 int qb1[2] = {0,1};
1447 int qb2[2] = {2,3};
1448
1449 for (int i=0; i<NUM_QUBITS; i++)
1450 paulis[i] = PAULI_X;
1451
1452 // make qb1 invalid
1453 int inv = GENERATE( -1, NUM_QUBITS );
1454 qb1[GENERATE_COPY(range(0,numQb))] = inv;
1455
1456 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, qb1, numQb, qb2, paulis, numQb, param), ContainsSubstring("Invalid control") );
1457 REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, qb2, numQb, qb1, paulis, numQb, param), ContainsSubstring("Invalid index") || ContainsSubstring("exceeds the maximum") );
1458 }
1459 }
1460 CLEANUP_TEST( quregVec, quregMatr );
1461}
1462
1463
1464
1465/** @sa multiControlledMultiRotateZ
1466 * @ingroup deprecatedtests
1467 * @author Tyson Jones
1468 */
1469TEST_CASE( "multiControlledMultiRotateZ", "[unitaries]" ) {
1470
1471 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1472 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1473
1474 SECTION( "correctness" ) {
1475
1476 // try all possible numbers of targets and controls
1477 int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for min 1 control qubit
1478 int maxNumCtrls = NUM_QUBITS - numTargs;
1479 int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1480
1481 // generate all possible valid qubit arrangements
1482 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1483 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1484
1485 // build correct reference matrix by diagonal-matrix exponentiation...
1486 QMatrix zMatr{{1,0},{0,-1}};
1487 QMatrix zProd = zMatr;
1488 for (int t=0; t<numTargs-1; t++)
1489 zProd = getKroneckerProduct(zMatr, zProd); // Z . Z ... Z
1490
1491 // exp( -i param/2 Z . Z ... Z)
1492 QMatrix op = getExponentialOfDiagonalMatrix(qcomp(0, -param/2) * zProd);
1493
1494 SECTION( "state-vector" ) {
1495
1496 multiControlledMultiRotateZ(quregVec, ctrls, numCtrls, targs, numTargs, param);
1497 applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
1498 REQUIRE( areEqual(quregVec, refVec) );
1499 }
1500 SECTION( "density-matrix" ) {
1501
1502 multiControlledMultiRotateZ(quregMatr, ctrls, numCtrls, targs, numTargs, param);
1503 applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
1504 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1505 }
1506 }
1507 SECTION( "input validation" ) {
1508
1509 // test all validation on both state-vector and density-matrix.
1510 // want GENERATE_COPY( quregVec, quregMatr ), but too lazy to patch
1511 // using github.com/catchorg/Catch2/issues/1809
1512 Qureg regs[] = {quregVec, quregMatr};
1513 Qureg qureg = regs[GENERATE(0,1)];
1514
1515 SECTION( "number of targets" ) {
1516
1517 // there cannot be more targets than qubits in register
1518 // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1519 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1520 int numCtrls = 1;
1521 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1522 int ctrls[] = {0};
1523
1524 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("number of target qubits") );
1525 }
1526 SECTION( "repetition in targets" ) {
1527
1528 int numCtrls = 1;
1529 int numTargs = 3;
1530 int ctrls[] = {0};
1531 int targs[] = {1,2,2};
1532
1533 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("target") && ContainsSubstring("unique"));
1534 }
1535 SECTION( "number of controls" ) {
1536
1537 // v4 API permits passing zero and NUM_QUBITS controls
1538 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1539 int numTargs = 1;
1540 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1541 for (int i=0; i<NUM_QUBITS+1; i++)
1542 ctrls[i] = i+1;
1543 int targs[1] = {0};
1544
1545 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("number of control qubits"));
1546 }
1547 SECTION( "repetition in controls" ) {
1548
1549 int numCtrls = 3;
1550 int numTargs = 1;
1551 int ctrls[] = {0,1,1};
1552 int targs[] = {3};
1553
1554 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("control") && ContainsSubstring("unique"));
1555 }
1556 SECTION( "control and target collision" ) {
1557
1558 int numCtrls = 3;
1559 int numTargs = 3;
1560 int ctrls[] = {0,1,2};
1561 int targs[] = {3,1,4};
1562
1563 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), ContainsSubstring("control and target"));
1564 }
1565 SECTION( "qubit indices" ) {
1566
1567 // valid inds
1568 int numQb = 2;
1569 int qb1[2] = {0,1};
1570 int qb2[2] = {2,3};
1571
1572 // make qb1 invalid
1573 int inv = GENERATE( -1, NUM_QUBITS );
1574 qb1[GENERATE_COPY(range(0,numQb))] = inv;
1575
1576 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, qb1, numQb, qb2, numQb, param), ContainsSubstring("Invalid control") );
1577 REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, qb2, numQb, qb1, numQb, param), ContainsSubstring("Invalid target") );
1578 }
1579 }
1580 CLEANUP_TEST( quregVec, quregMatr );
1581}
1582
1583
1584
1585/** @sa multiControlledPhaseFlip
1586 * @ingroup deprecatedtests
1587 * @author Tyson Jones
1588 */
1589TEST_CASE( "multiControlledPhaseFlip", "[unitaries]" ) {
1590
1591 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1592
1593 // acts on the final control qubit
1594 QMatrix op{{1,0},{0,-1}};
1595
1596 SECTION( "correctness" ) {
1597
1598 // generate ALL valid qubit arrangements
1599 int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1600 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1601
1602 SECTION( "state-vector" ) {
1603
1604 multiControlledPhaseFlip(quregVec, ctrls, numCtrls);
1605 applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1606 REQUIRE( areEqual(quregVec, refVec) );
1607 }
1608 SECTION( "density-matrix" ) {
1609
1610 multiControlledPhaseFlip(quregMatr, ctrls, numCtrls);
1611 applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1612 REQUIRE( areEqual(quregMatr, refMatr) );
1613 }
1614 }
1615 SECTION( "input validation" ) {
1616
1617 SECTION( "number of targets" ) {
1618
1619 // in v4, all qubits are considered targets
1620
1621 // v4 API permits passing zero controls
1622 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1623 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1624 REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), ContainsSubstring("number of target qubits"));
1625 }
1626 SECTION( "repetition of targets" ) {
1627
1628 int numCtrls = 3;
1629 int ctrls[] = {0,1,1};
1630 REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), ContainsSubstring("qubits must be unique"));
1631 }
1632 SECTION( "qubit indices" ) {
1633
1634 int numCtrls = 3;
1635 int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1636 REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), ContainsSubstring("Invalid target qubit") );
1637 }
1638 }
1639 CLEANUP_TEST( quregVec, quregMatr );
1640}
1641
1642
1643
1644/** @sa multiControlledPhaseShift
1645 * @ingroup deprecatedtests
1646 * @author Tyson Jones
1647 */
1648TEST_CASE( "multiControlledPhaseShift", "[unitaries]" ) {
1649
1650 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1651 qreal param = getRandomReal(-2*M_PI, 2*M_PI);
1652 QMatrix op{{1,0},{0,expI(param)}};
1653
1654 SECTION( "correctness" ) {
1655
1656 // generate ALL valid qubit arrangements
1657 int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1658 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1659
1660 SECTION( "state-vector" ) {
1661
1662 multiControlledPhaseShift(quregVec, ctrls, numCtrls, param);
1663 applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1664 REQUIRE( areEqual(quregVec, refVec) );
1665 }
1666 SECTION( "density-matrix" ) {
1667
1668 multiControlledPhaseShift(quregMatr, ctrls, numCtrls, param);
1669 applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1670 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1671 }
1672 }
1673 SECTION( "input validation" ) {
1674
1675 // in v4, all arguments are considered targets (not controls)
1676
1677 SECTION( "number of targets" ) {
1678
1679 // v4 API permits passing zero controls
1680 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1681 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1682 REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), ContainsSubstring("number of target qubits"));
1683 }
1684 SECTION( "repetition of targets" ) {
1685
1686 int numCtrls = 3;
1687 int ctrls[] = {0,1,1};
1688 REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), ContainsSubstring("qubits must be unique"));
1689 }
1690 SECTION( "qubit indices" ) {
1691
1692 int numCtrls = 3;
1693 int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1694 REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), ContainsSubstring("Invalid target qubit") );
1695 }
1696 }
1697 CLEANUP_TEST( quregVec, quregMatr );
1698}
1699
1700
1701
1702/** @sa multiControlledTwoQubitUnitary
1703 * @ingroup deprecatedtests
1704 * @author Tyson Jones
1705 */
1706TEST_CASE( "multiControlledTwoQubitUnitary", "[unitaries]" ) {
1707
1708 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1709
1710 // in distributed mode, each node must be able to fit all amps modified by unitary
1711 REQUIRE( quregVec.numAmpsPerNode >= 4 );
1712
1713 // every test will use a unique random matrix
1714 QMatrix op = getRandomUnitary(2);
1716
1717 SECTION( "correctness" ) {
1718
1719 // generate ALL valid qubit arrangements
1720 int targ1 = GENERATE( range(0,NUM_QUBITS) );
1721 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
1722 int targs[] = {targ1, targ2};
1723 int numCtrls = GENERATE( range(1,NUM_QUBITS-1) ); // leave room for 2 targets (upper bound is exclusive)
1724 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, 2) );
1725
1726 SECTION( "state-vector" ) {
1727
1728 multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr);
1729 applyReferenceOp(refVec, ctrls, numCtrls, targ1, targ2, op);
1730 REQUIRE( areEqual(quregVec, refVec) );
1731 }
1732 SECTION( "density-matrix" ) {
1733
1734 multiControlledTwoQubitUnitary(quregMatr, ctrls, numCtrls, targ1, targ2, matr);
1735 applyReferenceOp(refMatr, ctrls, numCtrls, targ1, targ2, op);
1736 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1737 }
1738 }
1739 SECTION( "input validation" ) {
1740
1741 SECTION( "number of controls" ) {
1742
1743 // v4 API permits passing zero and NUM_QUBITS controls
1744
1745 // numCtrls=(NUM_QUBITS-1) is ok since requires ctrl qubit inds are invalid
1746 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1747 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1748 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, 0, 1, matr), ContainsSubstring("number of control qubits"));
1749 }
1750 SECTION( "repetition of controls" ) {
1751
1752 int numCtrls = 3;
1753 int ctrls[] = {0,1,1};
1754 int targ1 = 2;
1755 int targ2 = 3;
1756 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), ContainsSubstring("control") && ContainsSubstring("unique"));;
1757 }
1758 SECTION( "repetition of targets" ) {
1759
1760 int numCtrls = 3;
1761 int ctrls[] = {0,1,2};
1762 int targ1 = 3;
1763 int targ2 = targ1;
1764 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
1765 }
1766 SECTION( "control and target collision" ) {
1767
1768 int numCtrls = 3;
1769 int ctrls[] = {0,1,2};
1770 int targ1 = 3;
1771 int targ2 = ctrls[GENERATE_COPY( range(0,numCtrls) )];
1772 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), ContainsSubstring("control and target") );
1773 }
1774 SECTION( "qubit indices" ) {
1775
1776 // valid indices
1777 int targ1 = 0;
1778 int targ2 = 1;
1779 int numCtrls = 3;
1780 int ctrls[] = { 2, 3, 4 };
1781
1782 int inv = GENERATE( -1, NUM_QUBITS );
1783 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, inv, targ2, matr), ContainsSubstring("Invalid target") );
1784 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, inv, matr), ContainsSubstring("Invalid target") );
1785
1786 ctrls[numCtrls-1] = inv; // make ctrls invalid
1787 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), ContainsSubstring("Invalid control") );
1788 }
1789 SECTION( "unitarity " ) {
1790
1791 int ctrls[1] = {0};
1792 matr.real[0][0] = 99999; // break unitarity
1793 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), ContainsSubstring("unitary") );
1794 }
1795 SECTION( "unitary fits in node" ) {
1796
1797 // pretend we have a very limited distributed memory
1798 quregVec.isDistributed = 1;
1799 quregVec.numAmpsPerNode = 1;
1800 quregVec.logNumAmpsPerNode = 0;
1801
1802 int ctrls[1] = {0};
1803 REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
1804 }
1805 }
1806 CLEANUP_TEST( quregVec, quregMatr );
1807}
1808
1809
1810
1811/** @sa multiControlledUnitary
1812 * @ingroup deprecatedtests
1813 * @author Tyson Jones
1814 */
1815TEST_CASE( "multiControlledUnitary", "[unitaries]" ) {
1816
1817 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1818
1819 // every test will use a unique random matrix
1820 QMatrix op = getRandomUnitary(1);
1822
1823 SECTION( "correctness" ) {
1824
1825 int target = GENERATE( range(0,NUM_QUBITS) );
1826 int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
1827 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
1828
1829 SECTION( "state-vector" ) {
1830
1831 multiControlledUnitary(quregVec, ctrls, numCtrls, target, matr);
1832 applyReferenceOp(refVec, ctrls, numCtrls, target, op);
1833 REQUIRE( areEqual(quregVec, refVec) );
1834 }
1835 SECTION( "density-matrix" ) {
1836
1837 multiControlledUnitary(quregMatr, ctrls, numCtrls, target, matr);
1838 applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
1839 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1840 }
1841 }
1842 SECTION( "input validation" ) {
1843
1844 SECTION( "number of controls" ) {
1845
1846 // v4 API permits passing zero and NUM_QUBITS controls
1847 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
1848 int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1849 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, numCtrls, 0, matr), ContainsSubstring("number of control qubits"));
1850 }
1851 SECTION( "repetition of controls" ) {
1852
1853 int ctrls[] = {0,1,1};
1854 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 2, matr), ContainsSubstring("control") && ContainsSubstring("unique"));
1855 }
1856 SECTION( "control and target collision" ) {
1857
1858 int ctrls[] = {0,1,2};
1859 int targ = ctrls[GENERATE( range(0,3) )];
1860 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), ContainsSubstring("control and target") );
1861 }
1862 SECTION( "qubit indices" ) {
1863
1864 int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1865 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 0, matr), ContainsSubstring("Invalid control") );
1866
1867 ctrls[2] = 3; // make ctrls valid
1868 int targ = GENERATE( -1, NUM_QUBITS );
1869 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), ContainsSubstring("Invalid target") );
1870 }
1871 SECTION( "unitarity" ) {
1872
1873 matr.real[0][0] = 9999; // break matr unitarity
1874 int ctrls[] = {0};
1875 REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 1, 1, matr), ContainsSubstring("unitary") );
1876 }
1877 }
1878 CLEANUP_TEST( quregVec, quregMatr );
1879}
1880
1881
1882
1883/** @sa multiQubitNot
1884 * @ingroup deprecatedtests
1885 * @author Tyson Jones
1886 */
1887TEST_CASE( "multiQubitNot", "[unitaries]" ) {
1888
1889 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1890
1891 SECTION( "correctness" ) {
1892
1893 // try all possible numbers of targets and controls
1894 int numTargs = GENERATE_COPY( range(1,NUM_QUBITS+1) ); // leave space for 1 ctrl
1895
1896 // generate all possible valid qubit arrangements
1897 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1898
1899 // for each qubit arrangement, use a new random unitary
1900 QMatrix notOp{{0, 1},{1,0}};
1901
1902 SECTION( "state-vector" ) {
1903
1904 multiQubitNot(quregVec, targs, numTargs);
1905 for (int t=0; t<numTargs; t++)
1906 applyReferenceOp(refVec, targs[t], notOp);
1907
1908 REQUIRE( areEqual(quregVec, refVec) );
1909 }
1910 SECTION( "density-matrix" ) {
1911
1912 multiQubitNot(quregMatr, targs, numTargs);
1913 for (int t=0; t<numTargs; t++)
1914 applyReferenceOp(refMatr, targs[t], notOp);
1915
1916 REQUIRE( areEqual(quregMatr, refMatr) );
1917 }
1918 }
1919 SECTION( "input validation" ) {
1920
1921 SECTION( "number of targets" ) {
1922
1923 // there cannot be more targets than qubits in register
1924 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1925 int targs[NUM_QUBITS+1];
1926 REQUIRE_THROWS_WITH( multiQubitNot(quregVec, targs, numTargs), ContainsSubstring("number of target qubits"));
1927 }
1928 SECTION( "repetition in targets" ) {
1929
1930 int numTargs = 3;
1931 int targs[] = {1,2,2};
1932 REQUIRE_THROWS_WITH( multiQubitNot(quregVec, targs, numTargs), ContainsSubstring("target") && ContainsSubstring("unique"));
1933 }
1934 SECTION( "target indices" ) {
1935
1936 // valid inds
1937 int numQb = 5;
1938 int qubits[] = {0,1,2,3,4};
1939
1940 // make one index invalid
1941 qubits[GENERATE_COPY(range(0,numQb))] = GENERATE( -1, NUM_QUBITS );
1942 REQUIRE_THROWS_WITH( multiQubitNot(quregVec, qubits, numQb), ContainsSubstring("Invalid target") );
1943 }
1944 }
1945 CLEANUP_TEST( quregVec, quregMatr );
1946}
1947
1948
1949
1950/** @sa multiQubitUnitary
1951 * @ingroup deprecatedtests
1952 * @author Tyson Jones
1953 */
1954TEST_CASE( "multiQubitUnitary", "[unitaries]" ) {
1955
1956 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1957
1958 // figure out max-num (inclusive) targs allowed by hardware backend
1959 int maxNumTargs = calcLog2(quregVec.numAmpsPerNode);
1960
1961 SECTION( "correctness" ) {
1962
1963 // generate all possible qubit arrangements
1964 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
1965 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1966
1967 // for each qubit arrangement, use a new random unitary
1968 QMatrix op = getRandomUnitary(numTargs);
1969 ComplexMatrixN matr = createComplexMatrixN(numTargs);
1970 toComplexMatrixN(op, matr);
1971
1972 SECTION( "state-vector" ) {
1973
1974 multiQubitUnitary(quregVec, targs, numTargs, matr);
1975 applyReferenceOp(refVec, targs, numTargs, op);
1976 REQUIRE( areEqual(quregVec, refVec) );
1977 }
1978 SECTION( "density-matrix" ) {
1979
1980 multiQubitUnitary(quregMatr, targs, numTargs, matr);
1981 applyReferenceOp(refMatr, targs, numTargs, op);
1982 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1983 }
1984 destroyComplexMatrixN(matr);
1985 }
1986 SECTION( "input validation" ) {
1987
1988 SECTION( "number of targets" ) {
1989
1990 // there cannot be more targets than qubits in register
1991 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1992 int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1993 ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
1994 syncCompMatr(matr);
1995
1996 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("number of target qubits"));
1997 destroyComplexMatrixN(matr);
1998 }
1999 SECTION( "repetition in targets" ) {
2000
2001 int numTargs = 3;
2002 int targs[] = {1,2,2};
2003 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
2004 syncCompMatr(matr);
2005
2006 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("target") && ContainsSubstring("unique"));
2007 destroyComplexMatrixN(matr);
2008 }
2009 SECTION( "qubit indices" ) {
2010
2011 int numTargs = 3;
2012 int targs[] = {1,2,3};
2013 ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
2014 syncCompMatr(matr);
2015
2016 int inv = GENERATE( -1, NUM_QUBITS );
2017 targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
2018 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("Invalid target") );
2019
2020 destroyComplexMatrixN(matr);
2021 }
2022 SECTION( "unitarity" ) {
2023
2024 int numTargs = GENERATE_COPY( range(1,maxNumTargs) );
2025 int targs[NUM_QUBITS];
2026 for (int i=0; i<numTargs; i++)
2027 targs[i] = i+1;
2028
2029 ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
2030 syncCompMatr(matr);
2031
2032 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("unitary") );
2033 destroyComplexMatrixN(matr);
2034 }
2035 SECTION( "unitary creation" ) {
2036
2037 int numTargs = 3;
2038 int targs[] = {1,2,3};
2039
2040 ComplexMatrixN matr;
2041 matr.cpuElems = NULL;
2042 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), ContainsSubstring("created") );
2043 }
2044 SECTION( "unitary dimensions" ) {
2045
2046 int targs[2] = {1,2};
2047 ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
2048 syncCompMatr(matr);
2049
2050 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, 2, matr), ContainsSubstring("matrix has an inconsistent size"));
2051 destroyComplexMatrixN(matr);
2052 }
2053 SECTION( "unitary fits in node" ) {
2054
2055 // pretend we have a very limited distributed memory (judged by matr size)
2056 quregVec.isDistributed = 1;
2057 quregVec.numAmpsPerNode = 1;
2058 quregVec.logNumAmpsPerNode = 0;
2059
2060 int qb[] = {1,2};
2061 ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
2062 for (int i=0; i<4; i++)
2063 matr.cpuElems[i][i] = 1;
2064 syncCompMatr(matr);
2065
2066 REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, qb, 2, matr), ContainsSubstring("communication buffer") && ContainsSubstring("simultaneously store"));
2067 destroyComplexMatrixN(matr);
2068 }
2069 }
2070 CLEANUP_TEST( quregVec, quregMatr );
2071}
2072
2073
2074
2075/** @sa multiRotatePauli
2076 * @ingroup deprecatedtests
2077 * @author Tyson Jones
2078 */
2079TEST_CASE( "multiRotatePauli", "[unitaries]" ) {
2080
2081 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2082 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2083
2084 SECTION( "correctness" ) {
2085
2086 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
2087 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
2088
2089 /* it's too expensive to try ALL Pauli sequences, via
2090 * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
2091 * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
2092 * Hence, we instead opt to repeatedlyrandomly generate pauliseqs
2093 */
2094 GENERATE( range(0,10) ); // gen 10 random pauli-codes for every targs
2095 pauliOpType paulis[NUM_QUBITS];
2096 for (int i=0; i<numTargs; i++)
2097 paulis[i] = (pauliOpType) getRandomInt(1,4); // exclude Id=0
2098
2099 // exclude identities from reference matrix exp (they apply unwanted global phase)
2100 int refTargs[NUM_QUBITS];
2101 int numRefTargs = 0;
2102
2103 QMatrix xMatr{{0,1},{1,0}};
2104 QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
2105 QMatrix zMatr{{1,0},{0,-1}};
2106
2107 // build correct reference matrix by pauli-matrix exponentiation...
2108 QMatrix pauliProd{{1}};
2109 for (int i=0; i<numTargs; i++) {
2110 QMatrix fac;
2111 if (paulis[i] == PAULI_I) continue; // exclude I-targets from ref list
2112 if (paulis[i] == PAULI_X) fac = xMatr;
2113 if (paulis[i] == PAULI_Y) fac = yMatr;
2114 if (paulis[i] == PAULI_Z) fac = zMatr;
2115 pauliProd = getKroneckerProduct(fac, pauliProd);
2116
2117 // include this target in ref list
2118 refTargs[numRefTargs++] = targs[i];
2119 }
2120
2121 // produces exp(-i param/2 pauliProd), unless pauliProd = I
2122 QMatrix op;
2123 if (numRefTargs > 0)
2124 op = getExponentialOfPauliMatrix(param, pauliProd);
2125
2126 SECTION( "state-vector" ) {
2127
2128 multiRotatePauli(quregVec, targs, paulis, numTargs, param);
2129 if (numRefTargs > 0)
2130 applyReferenceOp(refVec, refTargs, numRefTargs, op);
2131 REQUIRE( areEqual(quregVec, refVec) );
2132 }
2133 SECTION( "density-matrix" ) {
2134
2135 multiRotatePauli(quregMatr, targs, paulis, numTargs, param);
2136 if (numRefTargs > 0)
2137 applyReferenceOp(refMatr, refTargs, numRefTargs, op);
2138 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2139 }
2140 }
2141 SECTION( "input validation" ) {
2142
2143 SECTION( "number of targets" ) {
2144
2145 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
2146 int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
2147 for (int i=0; i<NUM_QUBITS+1; i++)
2148 targs[i] = i;
2149 pauliOpType paulis[NUM_QUBITS+1];
2150 for (int i=0; i<NUM_QUBITS+1; i++)
2151 paulis[i] = PAULI_X;
2152
2153 REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), (ContainsSubstring("Pauli operator") && ContainsSubstring("exceeds the maximum target")) || ContainsSubstring("Invalid number of Paulis") );
2154 }
2155 SECTION( "repetition of targets" ) {
2156
2157 int numTargs = 3;
2158 int targs[3] = {0, 1, 1};
2159 pauliOpType paulis[3] = {PAULI_X, PAULI_X, PAULI_X};
2160 REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), ContainsSubstring("Pauli indices contained a duplicate"));
2161 }
2162 SECTION( "qubit indices" ) {
2163
2164 int numTargs = 3;
2165 int targs[3] = {0, 1, 2};
2166 targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
2167 pauliOpType paulis[NUM_QUBITS];
2168 for (int i=0; i<NUM_QUBITS; i++)
2169 paulis[i] = PAULI_X;
2170
2171 REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), (ContainsSubstring("non-identity Pauli operator") && ContainsSubstring("exceeds the maximum")) || ContainsSubstring("Invalid index"));
2172 }
2173 SECTION( "pauli codes" ) {
2174 int numTargs = 3;
2175 int targs[3] = {0, 1, 2};
2176 pauliOpType paulis[3] = {PAULI_X, PAULI_X, PAULI_X};
2177 paulis[GENERATE_COPY(range(0,numTargs))] = (pauliOpType) GENERATE( -1, 4 );
2178 REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), ContainsSubstring("invalid Pauli code"));
2179 }
2180 }
2181 CLEANUP_TEST( quregVec, quregMatr );
2182}
2183
2184
2185
2186/** @sa multiRotateZ
2187 * @ingroup deprecatedtests
2188 * @author Tyson Jones
2189 */
2190TEST_CASE( "multiRotateZ", "[unitaries]" ) {
2191
2192 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2193 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2194
2195 SECTION( "correctness" ) {
2196
2197 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
2198 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
2199
2200 // build correct reference matrix by diagonal-matrix exponentiation...
2201 QMatrix zMatr{{1,0},{0,-1}};
2202 QMatrix zProd = zMatr;
2203 for (int t=0; t<numTargs-1; t++)
2204 zProd = getKroneckerProduct(zMatr, zProd); // Z . Z ... Z
2205
2206 // (-i param/2) Z . I . Z ...
2207 QMatrix expArg = qcomp(0, -param/2) *
2208 getFullOperatorMatrix(NULL, 0, targs, numTargs, zProd, NUM_QUBITS);
2209
2210 // exp( -i param/2 Z . I . Z ...)
2212
2213 // all qubits to specify full operator matrix on reference structures
2214 int allQubits[NUM_QUBITS];
2215 for (int i=0; i<NUM_QUBITS; i++)
2216 allQubits[i] = i;
2217
2218 SECTION( "state-vector" ) {
2219
2220 multiRotateZ(quregVec, targs, numTargs, param);
2221 applyReferenceOp(refVec, allQubits, NUM_QUBITS, op);
2222 REQUIRE( areEqual(quregVec, refVec) );
2223 }
2224 SECTION( "density-matrix" ) {
2225
2226 multiRotateZ(quregMatr, targs, numTargs, param);
2227 applyReferenceOp(refMatr, allQubits, NUM_QUBITS, op);
2228 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2229 }
2230 }
2231 SECTION( "input validation" ) {
2232
2233 SECTION( "number of targets" ) {
2234
2235 int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
2236 int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
2237 REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), ContainsSubstring("number of target qubits"));
2238
2239 }
2240 SECTION( "repetition of targets" ) {
2241
2242 int numTargs = 3;
2243 int targs[3] = {0, 1, 1};
2244 REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), ContainsSubstring("target") && ContainsSubstring("unique"));
2245 }
2246 SECTION( "qubit indices" ) {
2247
2248 int numTargs = 3;
2249 int targs[3] = {0, 1, 2};
2250 targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
2251 REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), ContainsSubstring("Invalid target"));
2252 }
2253 }
2254 CLEANUP_TEST( quregVec, quregMatr );
2255}
2256
2257
2258
2259/** @sa multiStateControlledUnitary
2260 * @ingroup deprecatedtests
2261 * @author Tyson Jones
2262 */
2263TEST_CASE( "multiStateControlledUnitary", "[unitaries]" ) {
2264
2265 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2266
2267 // every test will use a unique random matrix
2268 QMatrix op = getRandomUnitary(1);
2270
2271 // the zero-conditioned control qubits can be effected by notting before/after ctrls
2272 QMatrix notOp{{0,1},{1,0}};
2273
2274 SECTION( "correctness" ) {
2275
2276 int target = GENERATE( range(0,NUM_QUBITS) );
2277 int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
2278 int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
2279 int* ctrlState = GENERATE_COPY( bitsets(numCtrls) );
2280
2281 SECTION( "state-vector" ) {
2282
2283 multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, target, matr);
2284
2285 // simulate controlled-state by notting before & after controls
2286 for (int i=0; i<numCtrls; i++)
2287 if (ctrlState[i] == 0)
2288 applyReferenceOp(refVec, ctrls[i], notOp);
2289 applyReferenceOp(refVec, ctrls, numCtrls, target, op);
2290 for (int i=0; i<numCtrls; i++)
2291 if (ctrlState[i] == 0)
2292 applyReferenceOp(refVec, ctrls[i], notOp);
2293
2294 REQUIRE( areEqual(quregVec, refVec) );
2295 }
2296 SECTION( "density-matrix" ) {
2297
2298 multiStateControlledUnitary(quregMatr, ctrls, ctrlState, numCtrls, target, matr);
2299
2300 // simulate controlled-state by notting before & after controls
2301 for (int i=0; i<numCtrls; i++)
2302 if (ctrlState[i] == 0)
2303 applyReferenceOp(refMatr, ctrls[i], notOp);
2304 applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
2305 for (int i=0; i<numCtrls; i++)
2306 if (ctrlState[i] == 0)
2307 applyReferenceOp(refMatr, ctrls[i], notOp);
2308
2309 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2310 }
2311 }
2312 SECTION( "input validation" ) {
2313
2314 SECTION( "number of controls" ) {
2315
2316 // v4 API permits passing zero and NUM_QUBITS controls
2317 int numCtrls = GENERATE( -1, NUM_QUBITS+1 );
2318 int ctrls[NUM_QUBITS+1];
2319 int ctrlState[NUM_QUBITS+1] = {0};
2320 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, 0, matr), ContainsSubstring("number of control qubits"));
2321 }
2322 SECTION( "repetition of controls" ) {
2323
2324 int ctrls[] = {0,1,1};
2325 int ctrlState[] = {0, 1, 0};
2326 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 2, matr), ContainsSubstring("control") && ContainsSubstring("unique"));
2327 }
2328 SECTION( "control and target collision" ) {
2329
2330 int ctrls[] = {0,1,2};
2331 int ctrlState[] = {0, 1, 0};
2332 int targ = ctrls[GENERATE( range(0,3) )];
2333 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), ContainsSubstring("control and target") );
2334 }
2335 SECTION( "qubit indices" ) {
2336
2337 int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
2338 int ctrlState[] = {0, 1, 0};
2339 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 0, matr), ContainsSubstring("Invalid control") );
2340
2341 ctrls[2] = 3; // make ctrls valid
2342 int targ = GENERATE( -1, NUM_QUBITS );
2343 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), ContainsSubstring("Invalid target") );
2344 }
2345 SECTION( "unitarity" ) {
2346
2347 matr.real[0][0] = 99999; // break matr unitarity
2348 int ctrls[] = {0};
2349 int ctrlState[1] = {0};
2350 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 1, 1, matr), ContainsSubstring("unitary") );
2351 }
2352 SECTION( "control state bits" ) {
2353
2354 // valid qubits
2355 int ctrls[] = {0, 1, 2};
2356 int ctrlState[] = {0, 0, 0};
2357 int targ = 3;
2358
2359 // make invalid
2360 ctrlState[2] = GENERATE(-1, 2);
2361 REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), ContainsSubstring("state") );
2362 }
2363 }
2364 CLEANUP_TEST( quregVec, quregMatr );
2365}
2366
2367
2368
2369/** @sa pauliX
2370 * @ingroup deprecatedtests
2371 * @author Tyson Jones
2372 */
2373TEST_CASE( "pauliX", "[unitaries]" ) {
2374
2375 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2376 QMatrix op{{0,1},{1,0}};
2377
2378 SECTION( "correctness" ) {
2379
2380 int target = GENERATE( range(0,NUM_QUBITS) );
2381
2382 SECTION( "state-vector" ) {
2383
2384 pauliX(quregVec, target);
2385 applyReferenceOp(refVec, target, op);
2386 REQUIRE( areEqual(quregVec, refVec) );
2387 }
2388 SECTION( "density-matrix correctness" ) {
2389
2390 pauliX(quregMatr, target);
2391 applyReferenceOp(refMatr, target, op);
2392 REQUIRE( areEqual(quregMatr, refMatr) );
2393 }
2394 }
2395 SECTION( "input validation" ) {
2396
2397 SECTION( "qubit indices" ) {
2398
2399 int target = GENERATE( -1, NUM_QUBITS );
2400 REQUIRE_THROWS_WITH( pauliX(quregVec, target), ContainsSubstring("Invalid target") );
2401 }
2402 }
2403 CLEANUP_TEST( quregVec, quregMatr );
2404}
2405
2406
2407
2408/** @sa pauliY
2409 * @ingroup deprecatedtests
2410 * @author Tyson Jones
2411 */
2412TEST_CASE( "pauliY", "[unitaries]" ) {
2413
2414 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2415 QMatrix op{{0,-qcomp(0,1)},{qcomp(0,1),0}};
2416
2417 SECTION( "correctness" ) {
2418
2419 int target = GENERATE( range(0,NUM_QUBITS) );
2420
2421 SECTION( "state-vector" ) {
2422
2423 pauliY(quregVec, target);
2424 applyReferenceOp(refVec, target, op);
2425 REQUIRE( areEqual(quregVec, refVec) );
2426 }
2427 SECTION( "density-matrix correctness" ) {
2428
2429 pauliY(quregMatr, target);
2430 applyReferenceOp(refMatr, target, op);
2431 REQUIRE( areEqual(quregMatr, refMatr) );
2432 }
2433 }
2434 SECTION( "input validation" ) {
2435
2436 SECTION( "qubit indices" ) {
2437
2438 int target = GENERATE( -1, NUM_QUBITS );
2439 REQUIRE_THROWS_WITH( pauliY(quregVec, target), ContainsSubstring("Invalid target") );
2440 }
2441 }
2442 CLEANUP_TEST( quregVec, quregMatr );
2443}
2444
2445
2446
2447/** @sa pauliZ
2448 * @ingroup deprecatedtests
2449 * @author Tyson Jones
2450 */
2451TEST_CASE( "pauliZ", "[unitaries]" ) {
2452
2453 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2454 QMatrix op{{1,0},{0,-1}};
2455
2456 SECTION( "correctness" ) {
2457
2458 int target = GENERATE( range(0,NUM_QUBITS) );
2459
2460 SECTION( "state-vector" ) {
2461
2462 pauliZ(quregVec, target);
2463 applyReferenceOp(refVec, target, op);
2464 REQUIRE( areEqual(quregVec, refVec) );
2465 }
2466 SECTION( "density-matrix correctness" ) {
2467
2468 pauliZ(quregMatr, target);
2469 applyReferenceOp(refMatr, target, op);
2470 REQUIRE( areEqual(quregMatr, refMatr) );
2471 }
2472 }
2473 SECTION( "input validation" ) {
2474
2475 SECTION( "qubit indices" ) {
2476
2477 int target = GENERATE( -1, NUM_QUBITS );
2478 REQUIRE_THROWS_WITH( pauliZ(quregVec, target), ContainsSubstring("Invalid target") );
2479 }
2480 }
2481 CLEANUP_TEST( quregVec, quregMatr );
2482}
2483
2484
2485
2486/** @sa phaseShift
2487 * @ingroup deprecatedtests
2488 * @author Tyson Jones
2489 */
2490TEST_CASE( "phaseShift", "[unitaries]" ) {
2491
2492 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2493 qreal param = getRandomReal(-2*M_PI, 2*M_PI);
2494 QMatrix op{{1,0},{0,expI(param)}};
2495
2496 SECTION( "correctness" ) {
2497
2498 int target = GENERATE( range(0,NUM_QUBITS) );
2499
2500 SECTION( "state-vector ") {
2501
2502 phaseShift(quregVec, target, param);
2503 applyReferenceOp(refVec, target, op);
2504 REQUIRE( areEqual(quregVec, refVec) );
2505 }
2506 SECTION( "density-matrix" ) {
2507
2508 phaseShift(quregMatr, target, param);
2509 applyReferenceOp(refMatr, target, op);
2510 REQUIRE( areEqual(quregMatr, refMatr) );
2511 }
2512 }
2513 SECTION( "input validation" ) {
2514
2515 SECTION( "qubit indices" ) {
2516
2517 int target = GENERATE( -1, NUM_QUBITS );
2518 REQUIRE_THROWS_WITH( phaseShift(quregVec, target, param), ContainsSubstring("Invalid target") );
2519 }
2520 }
2521 CLEANUP_TEST( quregVec, quregMatr );
2522}
2523
2524
2525
2526/** @sa rotateAroundAxis
2527 * @ingroup deprecatedtests
2528 * @author Tyson Jones
2529 */
2530TEST_CASE( "rotateAroundAxis", "[unitaries]" ) {
2531
2532 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2533
2534 // each test will use a random parameter and axis vector
2535 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2536 Vector vec;
2537 vec.x=getRandomReal(1,2);
2538 vec.y=getRandomReal(-2,-1);
2539 vec.z=getRandomReal(-1,1); // lazily avoiding (x,y,z)=0
2540
2541 // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
2542 // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
2543 qreal c = cos(param/2);
2544 qreal s = sin(param/2);
2545 qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
2546
2547 // brackets defer division of m to improve numerical stability
2548 QMatrix op{{c - (qcomp(0,1)*vec.z*s)/m, -((vec.y + qcomp(0,1)*vec.x)*s)/m},
2549 {((vec.y - qcomp(0,1)*vec.x)*s)/m, c + (qcomp(0,1)*vec.z*s)/m}};
2550
2551 SECTION( "correctness" ) {
2552
2553 int target = GENERATE( range(0,NUM_QUBITS) );
2554
2555 SECTION( "state-vector ") {
2556
2557 rotateAroundAxis(quregVec, target, param, vec);
2558 applyReferenceOp(refVec, target, op);
2559 REQUIRE( areEqual(quregVec, refVec, 10*REAL_EPS) );
2560 }
2561 SECTION( "density-matrix" ) {
2562
2563 rotateAroundAxis(quregMatr, target, param, vec);
2564 applyReferenceOp(refMatr, target, op);
2565 REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
2566 }
2567 }
2568 SECTION( "input validation" ) {
2569
2570 SECTION( "qubit indices" ) {
2571
2572 int target = GENERATE( -1, NUM_QUBITS );
2573 REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), ContainsSubstring("Invalid target") );
2574 }
2575 SECTION( "zero rotation axis" ) {
2576
2577 int target = 0;
2578 vec.x=0; vec.y=0; vec.z=0;
2579 REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), ContainsSubstring("axis") && ContainsSubstring("zero") );
2580 }
2581 }
2582 CLEANUP_TEST( quregVec, quregMatr );
2583}
2584
2585
2586
2587/** @sa rotateX
2588 * @ingroup deprecatedtests
2589 * @author Tyson Jones
2590 */
2591TEST_CASE( "rotateX", "[unitaries]" ) {
2592
2593 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2594 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2595 QMatrix op{
2596 {cos(param/2), - sin(param/2)*qcomp(0,1)},
2597 {- sin(param/2)*qcomp(0,1), cos(param/2)}};
2598
2599 SECTION( "correctness" ) {
2600
2601 int target = GENERATE( range(0,NUM_QUBITS) );
2602
2603 SECTION( "state-vector ") {
2604
2605 rotateX(quregVec, target, param);
2606 applyReferenceOp(refVec, target, op);
2607 REQUIRE( areEqual(quregVec, refVec) );
2608 }
2609 SECTION( "density-matrix" ) {
2610
2611 rotateX(quregMatr, target, param);
2612 applyReferenceOp(refMatr, target, op);
2613 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2614 }
2615 }
2616 SECTION( "input validation" ) {
2617
2618 SECTION( "qubit indices" ) {
2619
2620 int target = GENERATE( -1, NUM_QUBITS );
2621 REQUIRE_THROWS_WITH( rotateX(quregVec, target, param), ContainsSubstring("Invalid target") );
2622 }
2623 }
2624 CLEANUP_TEST( quregVec, quregMatr );
2625}
2626
2627
2628
2629/** @sa rotateY
2630 * @ingroup deprecatedtests
2631 * @author Tyson Jones
2632 */
2633TEST_CASE( "rotateY", "[unitaries]" ) {
2634
2635 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2636 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2637 QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
2638
2639 SECTION( "correctness" ) {
2640
2641 int target = GENERATE( range(0,NUM_QUBITS) );
2642
2643 SECTION( "state-vector ") {
2644
2645 rotateY(quregVec, target, param);
2646 applyReferenceOp(refVec, target, op);
2647 REQUIRE( areEqual(quregVec, refVec) );
2648 }
2649 SECTION( "density-matrix" ) {
2650
2651 rotateY(quregMatr, target, param);
2652 applyReferenceOp(refMatr, target, op);
2653 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2654 }
2655 }
2656 SECTION( "input validation" ) {
2657
2658 SECTION( "qubit indices" ) {
2659
2660 int target = GENERATE( -1, NUM_QUBITS );
2661 REQUIRE_THROWS_WITH( rotateY(quregVec, target, param), ContainsSubstring("Invalid target") );
2662 }
2663 }
2664 CLEANUP_TEST( quregVec, quregMatr );
2665}
2666
2667
2668
2669/** @sa rotateZ
2670 * @ingroup deprecatedtests
2671 * @author Tyson Jones
2672 */
2673TEST_CASE( "rotateZ", "[unitaries]" ) {
2674
2675 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2676 qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2677 QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
2678
2679 SECTION( "correctness" ) {
2680
2681 int target = GENERATE( range(0,NUM_QUBITS) );
2682
2683 SECTION( "state-vector ") {
2684
2685 rotateZ(quregVec, target, param);
2686 applyReferenceOp(refVec, target, op);
2687 REQUIRE( areEqual(quregVec, refVec) );
2688 }
2689 SECTION( "density-matrix" ) {
2690
2691 rotateZ(quregMatr, target, param);
2692 applyReferenceOp(refMatr, target, op);
2693 REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2694 }
2695 }
2696 SECTION( "input validation" ) {
2697
2698 SECTION( "qubit indices" ) {
2699
2700 int target = GENERATE( -1, NUM_QUBITS );
2701 REQUIRE_THROWS_WITH( rotateZ(quregVec, target, param), ContainsSubstring("Invalid target") );
2702 }
2703 }
2704 CLEANUP_TEST( quregVec, quregMatr );
2705}
2706
2707
2708
2709/** @sa sGate
2710 * @ingroup deprecatedtests
2711 * @author Tyson Jones
2712 */
2713TEST_CASE( "sGate", "[unitaries]" ) {
2714
2715 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2716 QMatrix op{{1,0},{0,qcomp(0,1)}};
2717
2718 SECTION( "correctness" ) {
2719
2720 int target = GENERATE( range(0,NUM_QUBITS) );
2721
2722 SECTION( "state-vector ") {
2723
2724 sGate(quregVec, target);
2725 applyReferenceOp(refVec, target, op);
2726 REQUIRE( areEqual(quregVec, refVec) );
2727 }
2728 SECTION( "density-matrix" ) {
2729
2730 sGate(quregMatr, target);
2731 applyReferenceOp(refMatr, target, op);
2732 REQUIRE( areEqual(quregMatr, refMatr) );
2733 }
2734 }
2735 SECTION( "input validation" ) {
2736
2737 SECTION( "qubit indices" ) {
2738
2739 int target = GENERATE( -1, NUM_QUBITS );
2740 REQUIRE_THROWS_WITH( sGate(quregVec, target), ContainsSubstring("Invalid target") );
2741 }
2742 }
2743 CLEANUP_TEST( quregVec, quregMatr );
2744}
2745
2746
2747
2748/** @sa sqrtSwapGate
2749 * @ingroup deprecatedtests
2750 * @author Tyson Jones
2751 */
2752TEST_CASE( "sqrtSwapGate", "[unitaries]" ) {
2753
2754 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2755 qcomp a = qcomp(.5, .5);
2756 qcomp b = qcomp(.5, -.5);
2757 QMatrix op{{1,0,0,0},{0,a,b,0},{0,b,a,0},{0,0,0,1}};
2758
2759 SECTION( "correctness" ) {
2760
2761 int targ1 = GENERATE( range(0,NUM_QUBITS) );
2762 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2763 int targs[] = {targ1, targ2};
2764
2765 SECTION( "state-vector" ) {
2766
2767 sqrtSwapGate(quregVec, targ1, targ2);
2768 applyReferenceOp(refVec, targs, 2, op);
2769 REQUIRE( areEqual(quregVec, refVec) );
2770 }
2771 SECTION( "density-matrix" ) {
2772
2773 sqrtSwapGate(quregMatr, targ1, targ2);
2774 applyReferenceOp(refMatr, targs, 2, op);
2775 REQUIRE( areEqual(quregMatr, refMatr) );
2776 }
2777 }
2778 SECTION( "input validation" ) {
2779
2780 SECTION( "qubit indices" ) {
2781
2782 int targ1 = GENERATE( -1, NUM_QUBITS );
2783 int targ2 = 0;
2784 REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ1, targ2), ContainsSubstring("Invalid target") );
2785 REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ2, targ1), ContainsSubstring("Invalid target") );
2786 }
2787 SECTION( "repetition of targets" ) {
2788
2789 int qb = 0;
2790 REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, qb, qb), ContainsSubstring("target") && ContainsSubstring("unique") );
2791 }
2792 }
2793 CLEANUP_TEST( quregVec, quregMatr );
2794}
2795
2796
2797
2798/** @sa swapGate
2799 * @ingroup deprecatedtests
2800 * @author Tyson Jones
2801 */
2802TEST_CASE( "swapGate", "[unitaries]" ) {
2803
2804 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2805 QMatrix op{{1,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1}};
2806
2807 SECTION( "correctness" ) {
2808
2809 int targ1 = GENERATE( range(0,NUM_QUBITS) );
2810 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2811 int targs[] = {targ1, targ2};
2812
2813 SECTION( "state-vector" ) {
2814
2815 swapGate(quregVec, targ1, targ2);
2816 applyReferenceOp(refVec, targs, 2, op);
2817 REQUIRE( areEqual(quregVec, refVec) );
2818 }
2819 SECTION( "density-matrix" ) {
2820
2821 swapGate(quregMatr, targ1, targ2);
2822 applyReferenceOp(refMatr, targs, 2, op);
2823 REQUIRE( areEqual(quregMatr, refMatr) );
2824 }
2825 }
2826 SECTION( "input validation" ) {
2827
2828 SECTION( "qubit indices" ) {
2829
2830 int targ1 = GENERATE( -1, NUM_QUBITS );
2831 int targ2 = 0;
2832 REQUIRE_THROWS_WITH( swapGate(quregVec, targ1, targ2), ContainsSubstring("Invalid target") );
2833 REQUIRE_THROWS_WITH( swapGate(quregVec, targ2, targ1), ContainsSubstring("Invalid target") );
2834 }
2835 SECTION( "repetition of targets" ) {
2836
2837 int qb = 0;
2838 REQUIRE_THROWS_WITH( swapGate(quregVec, qb, qb), ContainsSubstring("target") && ContainsSubstring("unique") );
2839 }
2840 }
2841 CLEANUP_TEST( quregVec, quregMatr );
2842}
2843
2844
2845
2846/** @sa tGate
2847 * @ingroup deprecatedtests
2848 * @author Tyson Jones
2849 */
2850TEST_CASE( "tGate", "[unitaries]" ) {
2851
2852 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2853 QMatrix op{{1,0},{0,expI(M_PI/4.)}};
2854
2855 SECTION( "correctness" ) {
2856
2857 int target = GENERATE( range(0,NUM_QUBITS) );
2858
2859 SECTION( "state-vector ") {
2860
2861 tGate(quregVec, target);
2862 applyReferenceOp(refVec, target, op);
2863 REQUIRE( areEqual(quregVec, refVec) );
2864 }
2865 SECTION( "density-matrix" ) {
2866
2867 tGate(quregMatr, target);
2868 applyReferenceOp(refMatr, target, op);
2869 REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2870 }
2871 }
2872 SECTION( "input validation" ) {
2873
2874 SECTION( "qubit indices" ) {
2875
2876 int target = GENERATE( -1, NUM_QUBITS );
2877 REQUIRE_THROWS_WITH( tGate(quregVec, target), ContainsSubstring("Invalid target") );
2878 }
2879 }
2880 CLEANUP_TEST( quregVec, quregMatr );
2881}
2882
2883
2884
2885/** @sa twoQubitUnitary
2886 * @ingroup deprecatedtests
2887 * @author Tyson Jones
2888 */
2889TEST_CASE( "twoQubitUnitary", "[unitaries]" ) {
2890
2891 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2892
2893 // in distributed mode, each node must be able to fit all amps modified by unitary
2894 REQUIRE( quregVec.numAmpsPerNode >= 4 );
2895
2896 // every test will use a unique random matrix
2897 QMatrix op = getRandomUnitary(2);
2899
2900 SECTION( "correctness" ) {
2901
2902 int targ1 = GENERATE( range(0,NUM_QUBITS) );
2903 int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2904 int targs[] = {targ1, targ2};
2905
2906 SECTION( "state-vector" ) {
2907
2908 twoQubitUnitary(quregVec, targ1, targ2, matr);
2909 applyReferenceOp(refVec, targs, 2, op);
2910 REQUIRE( areEqual(quregVec, refVec) );
2911 }
2912 SECTION( "density-matrix" ) {
2913
2914 twoQubitUnitary(quregMatr, targ1, targ2, matr);
2915 applyReferenceOp(refMatr, targs, 2, op);
2916 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2917 }
2918 }
2919 SECTION( "input validation" ) {
2920
2921 SECTION( "qubit indices" ) {
2922
2923 int targ1 = GENERATE( -1, NUM_QUBITS );
2924 int targ2 = 0;
2925 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ1, targ2, matr), ContainsSubstring("Invalid target") );
2926 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ2, targ1, matr), ContainsSubstring("Invalid target") );
2927 }
2928 SECTION( "repetition of targets" ) {
2929
2930 int qb = 0;
2931 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, qb, qb, matr), ContainsSubstring("target") && ContainsSubstring("unique") );
2932 }
2933 SECTION( "unitarity" ) {
2934
2935 matr.real[0][0] = 9999; // break matr unitarity
2936 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), ContainsSubstring("unitary") );
2937 }
2938 SECTION( "unitary fits in node" ) {
2939
2940 // pretend we have a very limited distributed memory
2941 quregVec.isDistributed = 1;
2942 quregVec.numAmpsPerNode = 1;
2943 quregVec.logNumAmpsPerNode = 0;
2944 REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), ContainsSubstring("communication buffer") && ContainsSubstring("cannot simultaneously store") );
2945 }
2946 }
2947 CLEANUP_TEST( quregVec, quregMatr );
2948}
2949
2950
2951
2952/** @sa unitary
2953 * @ingroup deprecatedtests
2954 * @author Tyson Jones
2955 */
2956TEST_CASE( "unitary", "[unitaries]" ) {
2957
2958 PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2959
2960 // every test will use a unique random matrix
2961 QMatrix op = getRandomUnitary(1);
2963
2964 SECTION( "correctness" ) {
2965
2966 int target = GENERATE( range(0,NUM_QUBITS) );
2967
2968 SECTION( "state-vector" ) {
2969
2970 unitary(quregVec, target, matr);
2971 applyReferenceOp(refVec, target, op);
2972 REQUIRE( areEqual(quregVec, refVec) );
2973 }
2974 SECTION( "density-matrix" ) {
2975
2976 unitary(quregMatr, target, matr);
2977 applyReferenceOp(refMatr, target, op);
2978 REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2979 }
2980 }
2981 SECTION( "input validation" ) {
2982
2983 SECTION( "qubit indices" ) {
2984
2985 int target = GENERATE( -1, NUM_QUBITS );
2986 REQUIRE_THROWS_WITH( unitary(quregVec, target, matr), ContainsSubstring("Invalid target") );
2987 }
2988 SECTION( "unitarity" ) {
2989
2990 matr.real[0][0] = 9999999; // break matr unitarity
2991 REQUIRE_THROWS_WITH( unitary(quregVec, 0, matr), ContainsSubstring("unitary") );
2992 }
2993 }
2994 CLEANUP_TEST( quregVec, quregMatr );
2995}
TEST_CASE("compactUnitary", "[unitaries]")
QMatrix getFullOperatorMatrix(int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op, int numQubits)
ComplexMatrix4 toComplexMatrix4(QMatrix qm)
unsigned int calcLog2(long unsigned int res)
bool areEqual(QVector a, QVector b)
vector< vector< qcomp > > QMatrix
ComplexMatrix2 toComplexMatrix2(QMatrix qm)
void applyReferenceOp(QVector &state, int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op)
void toComplexMatrixN(QMatrix qm, ComplexMatrixN cm)
QMatrix toQMatrix(CompMatr1 src)
Catch::Generators::GeneratorWrapper< int * > bitsets(int numBits)
void syncDiagMatr(DiagMatr matr)
Definition matrices.cpp:374
void syncCompMatr(CompMatr matr)
Definition matrices.cpp:373
qmatrix getKroneckerProduct(qmatrix a, qmatrix b)
Definition linalg.cpp:523
qmatrix getExponentialOfDiagonalMatrix(qmatrix m)
Definition linalg.cpp:336
qcomp getRandomComplex()
Definition random.cpp:107
qmatrix getRandomUnitary(int numQb)
Definition random.cpp:348
qreal getRandomReal(qreal min, qreal maxExcl)
Definition random.cpp:63
int getRandomInt(int min, int maxExcl)
Definition random.cpp:90
Definition qureg.h:49