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