The Quantum Exact Simulation Toolkit v4.2.0
Loading...
Searching...
No Matches
 TEST_CASE ("createQureg", TEST_CATEGORY)
 
 TEST_CASE ("createDensityQureg", TEST_CATEGORY)
 
 TEST_CASE ("createForcedQureg", TEST_CATEGORY)
 
 TEST_CASE ("createForcedDensityQureg", TEST_CATEGORY)
 
 TEST_CASE ("createCustomQureg", TEST_CATEGORY)
 
 TEST_CASE ("createCloneQureg", TEST_CATEGORY)
 
 TEST_CASE ("destroyQureg", TEST_CATEGORY)
 
 TEST_CASE ("getQuregAmp", TEST_CATEGORY)
 
 TEST_CASE ("getDensityQuregAmp", TEST_CATEGORY)
 
 TEST_CASE ("getQuregAmps", TEST_CATEGORY)
 
 TEST_CASE ("getDensityQuregAmps", TEST_CATEGORY)
 

Detailed Description

Function Documentation

◆ TEST_CASE() [1/11]

TEST_CASE ( "createCloneQureg" ,
TEST_CATEGORY  )

Definition at line 566 of file qureg.cpp.

566 {
567
568 SECTION( LABEL_CORRECTNESS ) {
569
570 auto cache = GENERATE( getCachedStatevecs(), getCachedDensmatrs() );
571
572 for (auto& [label, qureg]: cache) {
573
574 initRandomPureState(qureg);
575 Qureg clone = createCloneQureg(qureg);
576
577 // check identical fields
578 REQUIRE( clone.isMultithreaded == qureg.isMultithreaded );
579 REQUIRE( clone.isGpuAccelerated == qureg.isGpuAccelerated );
580 REQUIRE( clone.isDistributed == qureg.isDistributed );
581 REQUIRE( clone.rank == qureg.rank );
582 REQUIRE( clone.numNodes == qureg.numNodes );
583 REQUIRE( clone.logNumNodes == qureg.logNumNodes );
584 REQUIRE( clone.isDensityMatrix == qureg.isDensityMatrix );
585 REQUIRE( clone.numQubits == qureg.numQubits );
586 REQUIRE( clone.numAmps == qureg.numAmps );
587 REQUIRE( clone.logNumAmps == qureg.logNumAmps );
588 REQUIRE( clone.numAmpsPerNode == qureg.numAmpsPerNode );
589 REQUIRE( clone.logNumAmpsPerNode == qureg.logNumAmpsPerNode );
590 REQUIRE( clone.logNumColsPerNode == qureg.logNumColsPerNode );
591
592 // check memory is different
593 REQUIRE( clone.cpuAmps != qureg.cpuAmps );
594 if (clone.isGpuAccelerated)
595 REQUIRE( clone.gpuAmps != qureg.gpuAmps );
596 if (clone.isDistributed)
597 REQUIRE( clone.cpuCommBuffer != qureg.cpuCommBuffer );
598 if (clone.isGpuAccelerated && clone.isDistributed)
599 REQUIRE( clone.gpuCommBuffer != qureg.gpuCommBuffer );
600
601 // check identical states
602 REQUIRE_AGREE( clone, qureg );
603
604 destroyQureg(clone);
605 }
606 }
607}
void initRandomPureState(Qureg qureg)
Qureg createCloneQureg(Qureg qureg)
Definition qureg.cpp:319
void destroyQureg(Qureg qureg)
Definition qureg.cpp:334
Definition qureg.h:49

◆ TEST_CASE() [2/11]

TEST_CASE ( "createCustomQureg" ,
TEST_CATEGORY  )

Definition at line 421 of file qureg.cpp.

421 {
422
423 SECTION( LABEL_CORRECTNESS ) {
424
425 QuESTEnv env = getQuESTEnv();
426
427 for (auto [deployLabel, mpi, gpu, omp] : getSupportedDeployments()) {
428
429 int isDenseMatr = GENERATE( 0, 1 );
430
431 std::string quregLabel = (isDenseMatr)? LABEL_STATEVEC : LABEL_DENSMATR;
432 std::string secLabel = quregLabel + LABEL_DELIMITER + deployLabel;
433
434 SECTION( secLabel ) {
435
436 int minNumQubits = std::max({1, mpi? getLog2(env.numNodes) : 1});
437 int maxNumQubits = std::min({minNumQubits + 3, isDenseMatr? 6 : 12});
438 int numQubits = GENERATE_COPY( range(minNumQubits, maxNumQubits) );
439 CAPTURE( numQubits );
440
441 Qureg qureg = createCustomQureg(numQubits, isDenseMatr, mpi, gpu, omp);
442
443 // check fixed fields
444 REQUIRE( qureg.numQubits == numQubits );
445 REQUIRE( qureg.isDensityMatrix == isDenseMatr );
446 REQUIRE( qureg.numAmps == getPow2(numQubits * (isDenseMatr? 2:1)) );
447 REQUIRE( qureg.logNumNodes == getLog2(qureg.numNodes) );
448 REQUIRE( qureg.logNumAmps == getLog2(qureg.numAmps) );
449 REQUIRE( qureg.logNumAmpsPerNode == getLog2(qureg.numAmpsPerNode) );
450 REQUIRE( qureg.logNumColsPerNode == (isDenseMatr? getLog2(getPow2(numQubits) / qureg.numNodes) : 0) );
451
452 // check deployments
453 REQUIRE( qureg.isMultithreaded == omp );
454 REQUIRE( qureg.isGpuAccelerated == gpu );
455 REQUIRE( (qureg.isDistributed == mpi || env.numNodes == 1) ); // permit auto-disable MPI
456
457 // check deployment-specific fields
458 if (mpi) {
459 REQUIRE( qureg.rank == env.rank );
460 REQUIRE( qureg.numNodes == env.numNodes );
461 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps / env.numNodes );
462 } else {
463 REQUIRE( qureg.rank == 0 );
464 REQUIRE( qureg.numNodes == 1 );
465 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps );
466 }
467
468 // check memory allocs
469 REQUIRE( qureg.cpuAmps != nullptr );
470 if (qureg.isGpuAccelerated)
471 REQUIRE( qureg.gpuAmps != nullptr );
472 if (qureg.isDistributed)
473 REQUIRE( qureg.cpuCommBuffer != nullptr );
474 if (qureg.isGpuAccelerated && qureg.isDistributed)
475 REQUIRE( qureg.gpuCommBuffer != nullptr );
476
477 // check begins in zero state
478 if (isDenseMatr) {
479 qmatrix ref = getZeroMatrix(getPow2(numQubits)); ref[0][0] = 1; // |0><0|
480 REQUIRE_AGREE( qureg, ref );
481 } else {
482 qvector ref = getZeroVector(getPow2(numQubits)); ref[0] = 1; // |0>
483 REQUIRE_AGREE( qureg, ref );
484 }
485
486 destroyQureg(qureg);
487 }
488 }
489 }
490
491 SECTION( LABEL_VALIDATION ) {
492
493 SECTION( "env not initialised" ) {
494
495 // impossible to test
496 SUCCEED( );
497 }
498
499 SECTION( "invalid isDensityMatrix flag" ) {
500
501 int isDensMatr = GENERATE( -1, 2 );
502
503 REQUIRE_THROWS_WITH( createCustomQureg(10, isDensMatr, 0,0,0), ContainsSubstring("isDensityMatrix") );
504 }
505
506 SECTION( "unsupported deployment" ) {
507
508 QuESTEnv env = getQuESTEnv();
509 const int numQubits = 10;
510 const int isDensMatr = 0;
511
512 if (!env.isDistributed)
513 REQUIRE_THROWS_WITH( createCustomQureg(numQubits,isDensMatr, 1,0,0), ContainsSubstring("non-distributed") );
514
515 if (!env.isGpuAccelerated)
516 REQUIRE_THROWS_WITH( createCustomQureg(numQubits,isDensMatr, 0,1,0), ContainsSubstring("non-GPU") );
517
518 if (!env.isMultithreaded)
519 REQUIRE_THROWS_WITH( createCustomQureg(numQubits,isDensMatr, 0,0,1), ContainsSubstring("non-multithreaded") );
520 }
521
522 SECTION( "too few qubits" ) {
523
524 REQUIRE_THROWS_WITH( createCustomQureg(-1, 0,0,0,0), ContainsSubstring("must contain one or more qubits") );
525 REQUIRE_THROWS_WITH( createCustomQureg(+0, 0,0,0,0), ContainsSubstring("must contain one or more qubits") );
526
527 int numNodes = getQuESTEnv().numNodes;
528 if (numNodes > 2) { // nodes=2 => min=1
529 int minNumQubits = getLog2(numNodes);
530 int useDistrib = 1;
531 REQUIRE_THROWS_WITH( createCustomQureg(minNumQubits-1,0, useDistrib,0,0), ContainsSubstring("each node would contain fewer than one amplitude") );
532 }
533 }
534
535 SECTION( "too many qubits" ) {
536
537 // overflows qindex in all precisions
538 REQUIRE_THROWS_WITH( createCustomQureg(100, 0, 0,0,0), ContainsSubstring("qindex") );
539 REQUIRE_THROWS_WITH( createCustomQureg(50, 1, 0,0,0), ContainsSubstring("qindex") );
540
541 // overflows size_t in single precision (and ergo also in double and quad)
542 REQUIRE_THROWS_WITH( createCustomQureg(62, 0, 0,0,0), ContainsSubstring("memory would overflow size_t") );
543 REQUIRE_THROWS_WITH( createCustomQureg(31, 1, 0,0,0), ContainsSubstring("memory would overflow size_t") );
544
545 // no overflows, but definitely exceeds local RAM and fails to allocate; frightens address sanitizer!
546 // note the specific error message depends on the what backend the auto-deployer tried to use (e.g.
547 // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in
548 // advance or whether it proceeded to malloc() which subsequently failed
549 #ifndef SANITIZER_IS_ACTIVE
550 REQUIRE_THROWS_WITH( createCustomQureg(50, 0, 0,0,0),
551 ContainsSubstring("failed") ||
552 ContainsSubstring("insufficient available memory") ||
553 ContainsSubstring("available GPU memory") ||
554 ContainsSubstring("RAM") );
555 REQUIRE_THROWS_WITH( createCustomQureg(25, 1, 0,0,0),
556 ContainsSubstring("failed") ||
557 ContainsSubstring("insufficient available memory") ||
558 ContainsSubstring("available GPU memory") ||
559 ContainsSubstring("RAM") );
560 #endif
561 }
562 }
563}
QuESTEnv getQuESTEnv()
Qureg createCustomQureg(int numQubits, int isDensMatr, int useDistrib, int useGpuAccel, int useMultithread)
Definition qureg.cpp:277
qmatrix getZeroMatrix(size_t dim)
Definition qmatrix.cpp:18

◆ TEST_CASE() [3/11]

TEST_CASE ( "createDensityQureg" ,
TEST_CATEGORY  )

Definition at line 139 of file qureg.cpp.

139 {
140
141 SECTION( LABEL_CORRECTNESS ) {
142
143 int numQubits = GENERATE( range(1, 7) ); // 7qb densematr = 14qb statevec
144 CAPTURE( numQubits );
145
146 Qureg qureg = createDensityQureg(numQubits);
147 QuESTEnv env = getQuESTEnv();
148
149 // check fixed fields
150 REQUIRE( qureg.numQubits == numQubits );
151 REQUIRE( qureg.isDensityMatrix == 1 );
152 REQUIRE( qureg.numAmps == getPow2(2*numQubits) );
153 REQUIRE( qureg.logNumAmps == getLog2(qureg.numAmps) );
154 REQUIRE( qureg.logNumAmpsPerNode == getLog2(qureg.numAmpsPerNode) );
155 REQUIRE( qureg.logNumNodes == getLog2(qureg.numNodes) );
156 REQUIRE( qureg.logNumColsPerNode == getLog2(getPow2(numQubits) / qureg.numNodes) );
157 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps / qureg.numNodes );
158 REQUIRE( (qureg.isMultithreaded == 0 || qureg.isMultithreaded == 1) );
159 REQUIRE( (qureg.isGpuAccelerated == 0 || qureg.isGpuAccelerated == 1) );
160 REQUIRE( (qureg.isDistributed == 0 || qureg.isDistributed == 1) );
161
162 // check deployment-specific fields
163 if (qureg.isDistributed) {
164 REQUIRE( qureg.rank == env.rank );
165 REQUIRE( qureg.numNodes == env.numNodes );
166 } else {
167 REQUIRE( qureg.rank == 0 );
168 REQUIRE( qureg.numNodes == 1 );
169 }
170
171 // check memory allocs
172 REQUIRE( qureg.cpuAmps != nullptr );
173 if (qureg.isGpuAccelerated)
174 REQUIRE( qureg.gpuAmps != nullptr );
175 if (qureg.isDistributed)
176 REQUIRE( qureg.cpuCommBuffer != nullptr );
177 if (qureg.isGpuAccelerated && qureg.isDistributed)
178 REQUIRE( qureg.gpuCommBuffer != nullptr );
179
180 /// @todo check autodeployments
181
182 // check begins in zero state
183 qmatrix ref = getZeroMatrix(getPow2(numQubits)); ref[0][0] = 1; // |0><0|
184 REQUIRE_AGREE( qureg, ref );
185
186 destroyQureg(qureg);
187 }
188
189 SECTION( LABEL_VALIDATION ) {
190
191 SECTION( "env not initialised" ) {
192
193 // impossible to test
194 SUCCEED( );
195 }
196
197 SECTION( "too few qubits" ) {
198
199 int numQubits = GENERATE( -1, 0 );
200
201 REQUIRE_THROWS_WITH( createDensityQureg(numQubits), ContainsSubstring("must contain one or more qubits") );
202 }
203
204 SECTION( "too many qubits" ) {
205
206 // overflows qindex in all precisions
207 REQUIRE_THROWS_WITH( createDensityQureg(50), ContainsSubstring("qindex type") );
208
209 // overflows size_t in single precision (and ergo also in double and quad)
210 REQUIRE_THROWS_WITH( createDensityQureg(31), ContainsSubstring("memory would overflow size_t") );
211
212 // no overflows, but definitely exceeds local RAM and fails to allocate; frightens address sanitizer!
213 // note the specific error message depends on the what backend the auto-deployer tried to use (e.g.
214 // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in
215 // advance or whether it proceeded to malloc() which subsequently failed
216 #ifndef SANITIZER_IS_ACTIVE
217 REQUIRE_THROWS_WITH( createDensityQureg(25),
218 ContainsSubstring("failed") ||
219 ContainsSubstring("insufficient available memory") ||
220 ContainsSubstring("available GPU memory") ||
221 ContainsSubstring("RAM") );
222 #endif
223 }
224 }
225}
Qureg createDensityQureg(int numQubits)
Definition qureg.cpp:291

◆ TEST_CASE() [4/11]

TEST_CASE ( "createForcedDensityQureg" ,
TEST_CATEGORY  )

Definition at line 324 of file qureg.cpp.

324 {
325
326 SECTION( LABEL_CORRECTNESS ) {
327
328 QuESTEnv env = getQuESTEnv();
329
330 int minNumQubits = std::max({1, env.isDistributed? getLog2(env.numNodes) : 1});
331 int maxNumQubits = std::min({minNumQubits + 5, 8}); // 8qb densmatr = 16qb statevec
332 int numQubits = GENERATE_COPY( range(minNumQubits, maxNumQubits) );
333 CAPTURE( numQubits );
334
335 Qureg qureg = createForcedDensityQureg(numQubits);
336
337 // check fixed fields
338 REQUIRE( qureg.numQubits == numQubits );
339 REQUIRE( qureg.isDensityMatrix == 1 );
340 REQUIRE( qureg.numAmps == getPow2(2*numQubits) );
341 REQUIRE( qureg.logNumAmps == getLog2(qureg.numAmps) );
342 REQUIRE( qureg.logNumAmpsPerNode == getLog2(qureg.numAmpsPerNode) );
343 REQUIRE( qureg.logNumColsPerNode == getLog2(getPow2(numQubits) / qureg.numNodes) );
344
345 // check deployments
346 REQUIRE( qureg.numNodes == env.numNodes );
347 REQUIRE( qureg.logNumNodes == getLog2(env.numNodes) );
348 REQUIRE( qureg.isMultithreaded == env.isMultithreaded);
349 REQUIRE( qureg.isGpuAccelerated == env.isGpuAccelerated);
350 REQUIRE( (qureg.isDistributed == env.isDistributed || env.numNodes == 1) ); // permit auto-disable MPI
351
352 // check deployment-specific fields
353 if (qureg.isDistributed) {
354 REQUIRE( qureg.rank == env.rank );
355 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps / env.numNodes );
356 } else {
357 REQUIRE( qureg.rank == 0 );
358 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps );
359 }
360
361 // check memory allocs
362 REQUIRE( qureg.cpuAmps != nullptr );
363 if (qureg.isGpuAccelerated)
364 REQUIRE( qureg.gpuAmps != nullptr );
365 if (qureg.isDistributed)
366 REQUIRE( qureg.cpuCommBuffer != nullptr );
367 if (qureg.isGpuAccelerated && qureg.isDistributed)
368 REQUIRE( qureg.gpuCommBuffer != nullptr );
369
370 // check begins in zero state
371 qmatrix ref = getZeroMatrix(getPow2(numQubits)); ref[0][0] = 1; // |0><0|
372 REQUIRE_AGREE( qureg, ref );
373
374 destroyQureg(qureg);
375 }
376
377 SECTION( LABEL_VALIDATION ) {
378
379 SECTION( "env not initialised" ) {
380
381 // impossible to test
382 SUCCEED( );
383 }
384
385 SECTION( "too few qubits" ) {
386
387 REQUIRE_THROWS_WITH( createForcedDensityQureg(-1), ContainsSubstring("must contain one or more qubits") );
388 REQUIRE_THROWS_WITH( createForcedDensityQureg(+0), ContainsSubstring("must contain one or more qubits") );
389
390 int numNodes = getQuESTEnv().numNodes;
391 if (numNodes > 2) { // nodes=2 => min=1
392 int minNumQubits = getLog2(numNodes);
393 REQUIRE_THROWS_WITH( createForcedDensityQureg(minNumQubits-1), ContainsSubstring("each node would contain fewer than a column") );
394 }
395 }
396
397 SECTION( "too many qubits" ) {
398
399 // overflows qindex in all precisions
400 REQUIRE_THROWS_WITH( createForcedDensityQureg(50), ContainsSubstring("qindex type") );
401
402 // overflows size_t in single precision (and ergo also in double and quad)
403 REQUIRE_THROWS_WITH( createForcedDensityQureg(31), ContainsSubstring("memory would overflow size_t") );
404
405 // no overflows, but definitely exceeds local RAM and fails to allocate; frightens address sanitizer!
406 // note the specific error message depends on the what backend the auto-deployer tried to use (e.g.
407 // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in
408 // advance or whether it proceeded to malloc() which subsequently failed
409 #ifndef SANITIZER_IS_ACTIVE
410 REQUIRE_THROWS_WITH( createForcedDensityQureg(25),
411 ContainsSubstring("failed") ||
412 ContainsSubstring("insufficient available memory") ||
413 ContainsSubstring("available GPU memory") ||
414 ContainsSubstring("RAM") );
415 #endif
416 }
417 }
418}
Qureg createForcedDensityQureg(int numQubits)
Definition qureg.cpp:309

◆ TEST_CASE() [5/11]

TEST_CASE ( "createForcedQureg" ,
TEST_CATEGORY  )

Definition at line 228 of file qureg.cpp.

228 {
229
230 SECTION( LABEL_CORRECTNESS ) {
231
232 QuESTEnv env = getQuESTEnv();
233
234 int minNumQubits = std::max({1, env.isDistributed? getLog2(env.numNodes) : 1});
235 int maxNumQubits = std::min({minNumQubits + 10, 14});
236 int numQubits = GENERATE_COPY( range(minNumQubits, maxNumQubits) );
237 CAPTURE( numQubits );
238
239 Qureg qureg = createForcedQureg(numQubits);
240
241 // check fixed fields
242 REQUIRE( qureg.numQubits == numQubits );
243 REQUIRE( qureg.isDensityMatrix == 0 );
244 REQUIRE( qureg.numAmps == getPow2(numQubits) );
245 REQUIRE( qureg.logNumAmps == getLog2(qureg.numAmps) );
246 REQUIRE( qureg.logNumAmpsPerNode == getLog2(qureg.numAmpsPerNode) );
247
248 // check deployments
249 REQUIRE( qureg.numNodes == env.numNodes );
250 REQUIRE( qureg.logNumNodes == getLog2(env.numNodes) );
251 REQUIRE( qureg.isMultithreaded == env.isMultithreaded);
252 REQUIRE( qureg.isGpuAccelerated == env.isGpuAccelerated);
253 REQUIRE( (qureg.isDistributed == env.isDistributed || env.numNodes == 1) ); // permit auto-disable MPI
254
255 // check deployment-specific fields
256 if (qureg.isDistributed) {
257 REQUIRE( qureg.rank == env.rank );
258 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps / env.numNodes );
259 } else {
260 REQUIRE( qureg.rank == 0 );
261 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps );
262 }
263
264 // check memory allocs
265 REQUIRE( qureg.cpuAmps != nullptr );
266 if (qureg.isGpuAccelerated)
267 REQUIRE( qureg.gpuAmps != nullptr );
268 if (qureg.isDistributed)
269 REQUIRE( qureg.cpuCommBuffer != nullptr );
270 if (qureg.isGpuAccelerated && qureg.isDistributed)
271 REQUIRE( qureg.gpuCommBuffer != nullptr );
272
273 // check begins in zero state
274 qvector ref = getZeroVector(getPow2(numQubits)); ref[0] = 1; // |0>
275 REQUIRE_AGREE( qureg, ref );
276
277 destroyQureg(qureg);
278 }
279
280 SECTION( LABEL_VALIDATION ) {
281
282 SECTION( "env not initialised" ) {
283
284 // impossible to test
285 SUCCEED( );
286 }
287
288 SECTION( "too few qubits" ) {
289
290 REQUIRE_THROWS_WITH( createForcedQureg(-1), ContainsSubstring("must contain one or more qubits") );
291 REQUIRE_THROWS_WITH( createForcedQureg(+0), ContainsSubstring("must contain one or more qubits") );
292
293 int numNodes = getQuESTEnv().numNodes;
294 if (numNodes > 2) { // nodes=2 => min=1
295 int minNumQubits = getLog2(numNodes);
296 REQUIRE_THROWS_WITH( createForcedQureg(minNumQubits-1), ContainsSubstring("each node would contain fewer than one amplitude") );
297 }
298 }
299
300 SECTION( "too many qubits" ) {
301
302 // overflows qindex in all precisions
303 REQUIRE_THROWS_WITH( createForcedQureg(100), ContainsSubstring("maximum which can be addressed by the qindex type") );
304
305 // overflows size_t in single precision (and ergo also in double and quad)
306 REQUIRE_THROWS_WITH( createForcedQureg(62), ContainsSubstring("memory would overflow size_t") );
307
308 // no overflows, but definitely exceeds local RAM and fails to allocate; frightens address sanitizer!
309 // note the specific error message depends on the what backend the auto-deployer tried to use (e.g.
310 // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in
311 // advance or whether it proceeded to malloc() which subsequently failed
312 #ifndef SANITIZER_IS_ACTIVE
313 REQUIRE_THROWS_WITH( createForcedQureg(50),
314 ContainsSubstring("failed") ||
315 ContainsSubstring("insufficient available memory") ||
316 ContainsSubstring("available GPU memory") ||
317 ContainsSubstring("RAM") );
318 #endif
319 }
320 }
321}
Qureg createForcedQureg(int numQubits)
Definition qureg.cpp:299

◆ TEST_CASE() [6/11]

TEST_CASE ( "createQureg" ,
TEST_CATEGORY  )

TESTS

Definition at line 49 of file qureg.cpp.

49 {
50
51 SECTION( LABEL_CORRECTNESS ) {
52
53 int numQubits = GENERATE( range(1, 10) );
54 CAPTURE( numQubits );
55
56 Qureg qureg = createQureg(numQubits);
57 QuESTEnv env = getQuESTEnv();
58
59 // check fixed fields
60 REQUIRE( qureg.numQubits == numQubits );
61 REQUIRE( qureg.isDensityMatrix == 0 );
62 REQUIRE( qureg.numAmps == getPow2(numQubits) );
63 REQUIRE( qureg.logNumAmps == getLog2(qureg.numAmps) );
64 REQUIRE( qureg.logNumAmpsPerNode == getLog2(qureg.numAmpsPerNode) );
65 REQUIRE( (qureg.isMultithreaded == 0 || qureg.isMultithreaded == 1) );
66 REQUIRE( (qureg.isGpuAccelerated == 0 || qureg.isGpuAccelerated == 1) );
67 REQUIRE( (qureg.isDistributed == 0 || qureg.isDistributed == 1) );
68
69 // check deployment-specific fields
70 if (qureg.isDistributed) {
71 REQUIRE( qureg.rank == env.rank );
72 REQUIRE( qureg.numNodes == env.numNodes );
73 REQUIRE( qureg.logNumNodes == getLog2(env.numNodes) );
74 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps / env.numNodes );
75 } else {
76 REQUIRE( qureg.rank == 0 );
77 REQUIRE( qureg.numNodes == 1 );
78 REQUIRE( qureg.logNumNodes == 0 );
79 REQUIRE( qureg.numAmpsPerNode == qureg.numAmps );
80 }
81
82 // check memory allocs
83 REQUIRE( qureg.cpuAmps != nullptr );
84 if (qureg.isGpuAccelerated)
85 REQUIRE( qureg.gpuAmps != nullptr );
86 if (qureg.isDistributed)
87 REQUIRE( qureg.cpuCommBuffer != nullptr );
88 if (qureg.isGpuAccelerated && qureg.isDistributed)
89 REQUIRE( qureg.gpuCommBuffer != nullptr );
90
91 /// @todo check autodeployments
92
93 // check begins in zero state
94 qvector ref = getZeroVector(qureg.numAmps); ref[0] = 1; // |0>
95 REQUIRE_AGREE( qureg, ref );
96
97 destroyQureg(qureg);
98 }
99
100 SECTION( LABEL_VALIDATION ) {
101
102 SECTION( "env not initialised" ) {
103
104 // impossible to test
105 SUCCEED( );
106 }
107
108 SECTION( "too few qubits" ) {
109
110 int numQubits = GENERATE( -1, 0 );
111
112 REQUIRE_THROWS_WITH( createQureg(numQubits), ContainsSubstring("must contain one or more qubits") );
113 }
114
115 SECTION( "too many qubits" ) {
116
117 // overflows qindex in all precisions
118 REQUIRE_THROWS_WITH( createQureg(100), ContainsSubstring("maximum which can be addressed by the qindex type") );
119
120 // overflows size_t in single precision (and ergo also in double and quad)
121 REQUIRE_THROWS_WITH( createQureg(62), ContainsSubstring("memory would overflow size_t") );
122
123 // no overflows, but definitely exceeds local RAM and fails to allocate; frightens address sanitizer!
124 // note the specific error message depends on the what backend the auto-deployer tried to use (e.g.
125 // GPU-accel or distributed) and whether memory-probers realised there was insufficient memory in
126 // advance or whether it proceeded to malloc() which subsequently failed
127 #ifndef SANITIZER_IS_ACTIVE
128 REQUIRE_THROWS_WITH( createQureg(50),
129 ContainsSubstring("failed") ||
130 ContainsSubstring("insufficient available memory") ||
131 ContainsSubstring("available GPU memory") ||
132 ContainsSubstring("RAM") );
133 #endif
134 }
135 }
136}
Qureg createQureg(int numQubits)
Definition qureg.cpp:283

◆ TEST_CASE() [7/11]

TEST_CASE ( "destroyQureg" ,
TEST_CATEGORY  )

Definition at line 610 of file qureg.cpp.

610 {
611
612 SECTION( LABEL_CORRECTNESS ) {
613
614 Qureg qureg = createQureg(5);
615 REQUIRE_NOTHROW( destroyQureg(qureg) );
616 }
617
618 SECTION( LABEL_VALIDATION ) {
619
620 /// @todo fails in MSVC for unknown reason
621 #ifndef _MSC_VER
622 // sanitizer messes with default initialisation
623 #ifndef SANITIZER_IS_ACTIVE
624 SECTION( "not created" ) {
625
626 Qureg qureg;
627 REQUIRE_THROWS_WITH( destroyQureg(qureg), ContainsSubstring("invalid Qureg") );
628 }
629 #endif
630 #endif
631 }
632}

◆ TEST_CASE() [8/11]

TEST_CASE ( "getDensityQuregAmp" ,
TEST_CATEGORY  )

Definition at line 690 of file qureg.cpp.

690 {
691
692 SECTION( LABEL_CORRECTNESS ) {
693
694 for (auto& [label, qureg]: getCachedDensmatrs()) {
695
696 qmatrix ref = getRefDensmatr();
697 initDebugState(qureg);
698 setToDebugState(ref);
699
700 int dim = (int) getPow2(qureg.numQubits);
701 int row = getRandomInt(0, dim);
702 int col = getRandomInt(0, dim);
703
704 GENERATE( range(0,100) );
705 CAPTURE( row, col );
706
707 // not necessarily identical when qureg is GPU-accelerated
708 REQUIRE_AGREE( getDensityQuregAmp(qureg, row, col), ref[row][col] );
709 }
710 }
711
712 SECTION( LABEL_VALIDATION ) {
713
714 /// @todo fails in MSVC for unknown reason
715 #ifndef _MSC_VER
716 // sanitizer messes with default initialisation
717 #ifndef SANITIZER_IS_ACTIVE
718 SECTION( "not created" ) {
719
720 Qureg qureg;
721 REQUIRE_THROWS_WITH( getDensityQuregAmp(qureg,0,0), ContainsSubstring("invalid Qureg") );
722 }
723 #endif
724 #endif
725
726 SECTION( "invalid indices" ) {
727
728 int numQubits = GENERATE( range(1,5) );
729 Qureg qureg = createDensityQureg(numQubits);
730 qindex index = GENERATE_COPY( -1, getPow2(numQubits), getPow2(numQubits) + 1 );
731
732 REQUIRE_THROWS_WITH( getDensityQuregAmp(qureg,0,index), ContainsSubstring("A") );
733 REQUIRE_THROWS_WITH( getDensityQuregAmp(qureg,index,0), ContainsSubstring("B") );
734
735 destroyQureg(qureg);
736 }
737
738 SECTION( "statevector" ) {
739
740 Qureg qureg = createQureg(1);
741
742 REQUIRE_THROWS_WITH( getDensityQuregAmp(qureg,0,0), ContainsSubstring("received a statevector") );
743
744 destroyQureg(qureg);
745 }
746 }
747}
void initDebugState(Qureg qureg)
qcomp getDensityQuregAmp(Qureg qureg, qindex row, qindex column)
Definition qureg.cpp:501
int getRandomInt(int min, int maxExcl)
Definition random.cpp:90

◆ TEST_CASE() [9/11]

TEST_CASE ( "getDensityQuregAmps" ,
TEST_CATEGORY  )

Definition at line 814 of file qureg.cpp.

814 {
815
816 SECTION( LABEL_CORRECTNESS ) {
817
818 for (auto& [label, qureg]: getCachedDensmatrs()) {
819
820 qmatrix ref = getRefDensmatr();
821 initDebugState(qureg);
822 setToDebugState(ref);
823
824 GENERATE( range(0,100) );
825
826 auto startRow = getRandomInt(0, ref.size());
827 auto startCol = getRandomInt(0, ref.size());
828 auto numRows = getRandomInt(1, ref.size() - startRow);
829 auto numCols = getRandomInt(1, ref.size() - startCol);
830
831 qcomp** out = (qcomp**) malloc(numRows * sizeof *out);
832 for (int i=0; i<numRows; i++)
833 out[i] = (qcomp*) malloc(numCols * sizeof **out);
834
835 getDensityQuregAmps(out, qureg, startRow, startCol, numRows, numCols);
836
837 bool agrees = true;
838 for (int r=0; r<numRows && agrees; r++)
839 for (int c=0; c<numCols && agrees; c++)
840 agrees = doScalarsAgree(out[r][c], ref[startRow+r][startCol+c]);
841
842 REQUIRE( agrees );
843
844 for (int i=0; i<numRows; i++)
845 free(out[i]);
846 free(out);
847 }
848 }
849
850 SECTION( LABEL_VALIDATION ) {
851
852 Qureg qureg = createDensityQureg(5);
853
854 /// @todo fails in MSVC for unknown reason
855 #ifndef _MSC_VER
856 // sanitizer messes with default initialisation
857 #ifndef SANITIZER_IS_ACTIVE
858 SECTION( "not created" ) {
859
860 Qureg bad;
861 REQUIRE_THROWS_WITH( getDensityQuregAmps(nullptr,bad,0,0,0,0), ContainsSubstring("invalid Qureg") );
862 }
863 #endif
864 #endif
865
866 SECTION( "indices" ) {
867
868 int startInd = GENERATE_COPY( -1, qureg.numAmps, qureg.numAmps + 1 );
869
870 REQUIRE_THROWS_WITH( getDensityQuregAmps(nullptr,qureg, startInd,0, 0,0), ContainsSubstring("Either or both of the starting row and column") );
871 REQUIRE_THROWS_WITH( getDensityQuregAmps(nullptr,qureg, 0,startInd, 0,0), ContainsSubstring("Either or both of the starting row and column") );
872 }
873
874 SECTION( "num amps") {
875
876 int numOut = GENERATE_COPY( -1, qureg.numAmps + 1 );
877
878 REQUIRE_THROWS_WITH( getDensityQuregAmps(nullptr,qureg, 0,0, 0,numOut), ContainsSubstring("Either or both of the number of rows and columns") );
879 REQUIRE_THROWS_WITH( getDensityQuregAmps(nullptr,qureg, 0,0, numOut,0), ContainsSubstring("Either or both of the number of rows and columns") );
880 }
881
882 SECTION( "subrange" ) {
883
884 int numOut = 10;
885 int dim = getPow2(qureg.numQubits);
886
887 REQUIRE_THROWS_WITH( getDensityQuregAmps(nullptr,qureg, dim-numOut,0, numOut + 1,1), ContainsSubstring("combination of starting") && ContainsSubstring("number of rows and columns") );
888 REQUIRE_THROWS_WITH( getDensityQuregAmps(nullptr,qureg, 0,dim-numOut, 1,numOut + 1), ContainsSubstring("combination of starting") && ContainsSubstring("number of rows and columns") );
889 }
890
891 destroyQureg(qureg);
892 }
893}
void getDensityQuregAmps(qcomp **outAmps, Qureg qureg, qindex startRow, qindex startCol, qindex numRows, qindex numCols)
Definition qureg.cpp:461

◆ TEST_CASE() [10/11]

TEST_CASE ( "getQuregAmp" ,
TEST_CATEGORY  )

Definition at line 635 of file qureg.cpp.

635 {
636
637 SECTION( LABEL_CORRECTNESS ) {
638
639 for (auto& [label, qureg]: getCachedStatevecs()) {
640
641 qvector ref = getRefStatevec();
642 initDebugState(qureg);
643 setToDebugState(ref);
644
645 int index = GENERATE_COPY( range(0, (int) qureg.numAmps) );
646 CAPTURE( index );
647
648 // not necessarily identical when qureg is GPU-accelerated
649 REQUIRE_AGREE( getQuregAmp(qureg, index), ref[index] );
650 }
651 }
652
653 SECTION( LABEL_VALIDATION ) {
654
655 /// @todo fails in MSVC for unknown reason
656 #ifndef _MSC_VER
657 // sanitizer messes with default initialisation
658 #ifndef SANITIZER_IS_ACTIVE
659 SECTION( "not created" ) {
660
661 Qureg qureg;
662 REQUIRE_THROWS_WITH( getQuregAmp(qureg,0), ContainsSubstring("invalid Qureg") );
663 }
664 #endif
665 #endif
666
667 SECTION( "invalid index" ) {
668
669 int numQubits = GENERATE( range(1,5) );
670 Qureg qureg = createQureg(numQubits);
671 int index = GENERATE_COPY( -1, getPow2(numQubits), getPow2(numQubits) + 1 );
672
673 REQUIRE_THROWS_WITH( getQuregAmp(qureg,index), ContainsSubstring("state index") && ContainsSubstring("is invalid") );
674
675 destroyQureg(qureg);
676 }
677
678 SECTION( "densitymatrix" ) {
679
680 Qureg qureg = createDensityQureg(1);
681
682 REQUIRE_THROWS_WITH( getQuregAmp(qureg,0), ContainsSubstring("received a density matrix") );
683
684 destroyQureg(qureg);
685 }
686 }
687}
qcomp getQuregAmp(Qureg qureg, qindex index)
Definition qureg.cpp:488

◆ TEST_CASE() [11/11]

TEST_CASE ( "getQuregAmps" ,
TEST_CATEGORY  )

Definition at line 750 of file qureg.cpp.

750 {
751
752 SECTION( LABEL_CORRECTNESS ) {
753
754 for (auto& [label, qureg]: getCachedStatevecs()) {
755
756 qvector ref = getRefStatevec();
757 initDebugState(qureg);
758 setToDebugState(ref);
759
760 GENERATE( range(0,100) );
761 int startInd = getRandomInt(0, qureg.numAmps);
762 int numAmps = getRandomInt(0, qureg.numAmps - startInd + 1);
763
764 vector<qcomp> out(numAmps);
765 getQuregAmps(out.data(), qureg, startInd, numAmps);
766
767 // not necessarily identical when qureg is GPU-accelerated
768 REQUIRE_AGREE( out, getSublist(ref, startInd, numAmps) );
769 }
770 }
771
772 SECTION( LABEL_VALIDATION ) {
773
774 Qureg qureg = createQureg(5);
775
776 /// @todo fails in MSVC for unknown reason
777 #ifndef _MSC_VER
778 // sanitizer messes with default initialisation
779 #ifndef SANITIZER_IS_ACTIVE
780 SECTION( "not created" ) {
781
782 Qureg bad;
783 REQUIRE_THROWS_WITH( getQuregAmps(nullptr,bad,0,0), ContainsSubstring("invalid Qureg") );
784 }
785 #endif
786 #endif
787
788 SECTION( "indices" ) {
789
790 int startInd = GENERATE_COPY( -1, qureg.numAmps, qureg.numAmps + 1 );
791
792 REQUIRE_THROWS_WITH( getQuregAmps(nullptr,qureg,startInd,0), ContainsSubstring("starting basis state index") );
793 }
794
795 SECTION( "num amps") {
796
797 int numOut = GENERATE_COPY( -1, qureg.numAmps + 1 );
798
799 REQUIRE_THROWS_WITH( getQuregAmps(nullptr,qureg,0,numOut), ContainsSubstring("number of amplitudes") );
800 }
801
802 SECTION( "subrange" ) {
803
804 int numOut = 10;
805
806 REQUIRE_THROWS_WITH( getQuregAmps(nullptr,qureg, qureg.numAmps - numOut, numOut + 1), ContainsSubstring("implies an end index") );
807 }
808
809 destroyQureg(qureg);
810 }
811}
void getQuregAmps(qcomp *outAmps, Qureg qureg, qindex startInd, qindex numAmps)
Definition qureg.cpp:452