The Quantum Exact Simulation Toolkit v4.3.0
Loading...
Searching...
No Matches
debug.h
1/** @file
2 * API signatures for debugging QuEST behaviour,
3 * controlling input validation, changing reporter
4 * parameters or seeding random generation.
5 *
6 * @author Tyson Jones
7 *
8 * @defgroup debug Debug
9 * @ingroup api
10 * @brief Utilities for controlling QuEST behaviour such as seeding, input validation and printing.
11 * @{
12 */
13
14#ifndef DEBUG_H
15#define DEBUG_H
16
17#include "quest/include/types.h"
18
19
20
21/*
22 * C AND C++ AGNOSTIC FUNCTIONS
23 */
24
25// enable invocation by both C and C++ binaries
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30
31
32/**
33 * @defgroup debug_seed Seeding
34 * @brief Functions for seeding QuEST's random generators.
35 * @details Re-seeding with identical seeds will determine all of QuEST's subsequent
36 * random outputs (such as measurement and random state preparation), and can
37 * be done at any stage of execution. When seeding is not explicitly performed,
38 * QuEST will attempt to use a cryptographically secure pseudorandom number generator
39 * (CSPRNG) if locally available, else fall back to a standard PRNG, via using
40 * the standard C++ `random_device` class.
41 * @{
42 */
43
44
45/** Sets the seeds used by QuEST's random number generation.
46 *
47 * This affects and determines all pseudorandom decisions made the QuEST library,
48 * such as qubit measurement outcomes and random state preparation. The seeds are
49 * passed without modification to QuEST's 19,937-bit
50 * [Mersenne Twister](https://cplusplus.com/reference/random/mt19937_64/) generator.
51 * As such, fully specifying the generator's initial state requires 19,937 seed bits,
52 * or 623 unsigned integers, although this is rarely necessary.
53 *
54 * Seeding can be performed at any time before a random decision (such as measurement);
55 * no random outcomes/state is stored on any object beforehand.
56 *
57 * > [!NOTE]
58 * > In distributed simulation, only the root node's seeds are consulted (and broadcast
59 * > to all nodes) while those passed on all other nodes are ignored.
60 *
61 * @myexample
62 * ```
63 // make report() print only one trailing newline
64 setQuESTNumReportedNewlines(1);
65
66 // seed
67 unsigned seeds[] = {123456789u, 987654321u, 546372819u};
68 setQuESTSeeds(seeds, 3);
69
70 // randomly collapse the plus state
71 initPlusState(qureg);
72 reportScalar("outcome 0", applyQubitMeasurement(qureg, 0));
73 reportScalar("outcome 1", applyQubitMeasurement(qureg, 1));
74 reportScalar("outcome 2", applyQubitMeasurement(qureg, 2));
75
76 // restore RNG to state prior to collapse
77 setQuESTSeeds(seeds, 3);
78
79 // randomly collapse the plus state again, obtaining same outcomes
80 reportStr("");
81 initPlusState(qureg);
82 reportScalar("outcome 0", applyQubitMeasurement(qureg, 0));
83 reportScalar("outcome 1", applyQubitMeasurement(qureg, 1));
84 reportScalar("outcome 2", applyQubitMeasurement(qureg, 2));
85 * ```
86 * Example output:
87 * ```
88 outcome 0: 0
89 outcome 1: 1
90 outcome 2: 1
91
92 outcome 0: 0
93 outcome 1: 1
94 outcome 2: 1
95 * ```
96 *
97 * @param[in] seeds a list of seeds.
98 * @param[in] numSeeds the length of @p seeds.
99 * @throws @validationerror
100 * - if @p seeds is a null pointer.
101 * - if @p numSeeds is less than one.
102 * @see
103 * - getQuESTSeeds()
104 * - getQuESTNumSeeds()
105 * - setQuESTSeedsToDefault()
106 * @author Tyson Jones
107 */
108void setQuESTSeeds(unsigned* seeds, int numSeeds);
109
110
111/** Re-randomizes QuEST, seeding its random number generator with new seeds as pseudorandomly
112 * produced by the @c C++ [@c std::random_device](https://en.cppreference.com/cpp/numeric/random/random_device)
113 * function, potentially using a hardware RNG.
114 *
115 * Similar to setQuESTSeeds(), this affects all pseudorandom decisions made the QuEST library,
116 * such as qubit measurement outcomes and random state preparation. Unlike setQuESTSeeds()
117 * however, repeated calls will not guarantee identical random generation; the internally
118 * processed seeds may differ at each invocation. This is, in fact, the function first
119 * internally called during QuEST environment initialisation.
120 *
121 * Seeding can be performed at any time after QuEST library initialisation, before a
122 * random decision (such as measurement); no random outcomes/state is stored on any object beforehand.
123 *
124 * This function consults @c std::random_device to produce @c DEFAULT_NUM_RNG_SEEDS=4
125 * seeds, which is infact insufficient to fully specify an initial state of QuEST's
126 * [19,937-bit Mersenne Twister](https://cplusplus.com/reference/random/mt19937_64/)
127 * generator. Presently, @c DEFAULT_NUM_RNG_SEEDS cannot be changed except through
128 * manual modification and recompilation.
129 *
130 * > [!NOTE]
131 * > In distributed simulation, only the root node's seeds are consulted (and broadcast
132 * > to all nodes) while those passed on all other nodes are ignored.
133 *
134 * Note that many data structures (e.g. CompMatr, DiagMatr, KrausMap) will assess epsilon-dependent
135 * validation properties such as unitarity _once_, recording the result in a persistent heap field
136 * (like KrausMap.isApproxCPTP) to avoid superfluous re-calculation.
137 * Updating the global validation epsilon via this function will update all persistent heap fields,
138 * marking epsilon-dependent properties as "unknown", which will be lazily re-evaluated when validation
139 * is next performed. Ergo, calling this function can cause later additional function overheads.
140 *
141 * @myexample
142 * ```
143 // make report() print only one trailing newline
144 setQuESTNumReportedNewlines(1);
145
146 // randomise the RNG state
147 setQuESTSeedsToDefault();
148
149 // randomly collapse the plus state
150 initPlusState(qureg);
151 reportScalar("outcome 0", applyQubitMeasurement(qureg, 0));
152 reportScalar("outcome 1", applyQubitMeasurement(qureg, 1));
153 reportScalar("outcome 2", applyQubitMeasurement(qureg, 2));
154
155 // re-randomise the RNG state
156 setQuESTSeedsToDefault();
157
158 // randomly collapse the plus state again, obtaining new outcomes
159 reportStr("");
160 initPlusState(qureg);
161 reportScalar("outcome 0", applyQubitMeasurement(qureg, 0));
162 reportScalar("outcome 1", applyQubitMeasurement(qureg, 1));
163 reportScalar("outcome 2", applyQubitMeasurement(qureg, 2));
164 * ```
165 * Example output:
166 * ```
167 outcome 0: 0
168 outcome 1: 1
169 outcome 2: 0
170
171 outcome 0: 1
172 outcome 1: 1
173 outcome 2: 1
174 * ```
175 * We can view the random seeds chosen by QuEST using getQuESTSeeds():
176 * ```
177 int numSeeds = getQuESTNumSeeds(); // fixed=4
178 unsigned seeds[1000]; // lazily/dangerously assume num<=1000
179
180 setQuESTSeedsToDefault();
181 getQuESTSeeds(seeds);
182
183 for (int i=0; i<numSeeds; i++)
184 printf("%u ", seeds[i]);
185 printf("\n\n");
186
187 setQuESTSeedsToDefault();
188 getQuESTSeeds(seeds);
189
190 for (int i=0; i<numSeeds; i++)
191 printf("%u ", seeds[i]);
192 printf("\n");
193 * ```
194 * Example output:
195 * ```
196 766738893 3449946700 2005286535 3261547242
197
198 3996404805 474611433 1261615115 3403708295
199 * ```
200 *
201 * @throws @validationerror
202 * - if the QuEST environment has not been initialised via initQuESTEnv().
203 * @see
204 * - setQuESTSeeds()
205 * - getQuESTSeeds()
206 * - getQuESTNumSeeds()
207 * @author Tyson Jones
208 */
210
211
212/** Populates @p seeds with those which last seeded QuEST's random number generation.
213 *
214 * This will return the last seeds passed to setQuESTSeeds(), or those internally
215 * chosen within setQuESTSeedsToDefault() (and equivalently, those initially chosen
216 * during the QuEST environment initialisation). The number of seeds, which informs
217 * the necessary capacity of @p seeds, is obtained by getQuESTNumSeeds().
218 *
219 * @myexample
220 *
221 * ```
222 int numSeeds = getQuESTNumSeeds();
223 unsigned *seeds = malloc(numSeeds * sizeof *seeds);
224
225 getQuESTSeeds(seeds);
226 printf("seeds[%d] = { ", numSeeds);
227
228 for (int i=0; i<numSeeds; i++)
229 printf("%u ", seeds[i]);
230 printf("} \n");
231
232 free(seeds);
233 * ```
234 * may output
235 * ```
236 seeds[4] = { 3674477761 2499034318 2614242128 475980445 }
237 * ```
238 *
239 * See setQuESTSeedsToDefault() for an example of how getQuESTSeeds() interacts with
240 * other seeding calls.
241 *
242 * @param[out] seeds the list of seeds
243 * @throws @validationerror
244 * - if the QuEST environment has not been initialised via initQuESTEnv().
245 * - if @p seeds is a nullptr.
246 * @throws seg-fault
247 * - if @p seeds does not have capacity to write as many @c unsigned as getQuESTNumSeeds() returns.
248 * @see
249 * - getQuESTNumSeeds()
250 * - setQuESTSeeds()
251 * @author Tyson Jones
252 */
253void getQuESTSeeds(unsigned* seeds);
254
255
256/** Returns the number of seeds used by QuEST in its latest round of random number generator seeding.
257 *
258 * This is the length of the list output by getQuESTSeeds().
259 *
260 * @returns the number of seeds.
261 * @throws @validationerror
262 * - if the QuEST environment has not been initialised via initQuESTEnv().
263 * @see
264 * - getQuESTSeeds()
265 * - setQuESTSeeds()
266 * @author Tyson Jones
267 */
268int getQuESTNumSeeds();
269
270
271/** @} */
272
273
274
275/**
276 * @defgroup debug_validation Validation
277 * @brief Functions to control QuEST's user-input validation.
278 * @details These can be used to adjust the precision with which properties like unitarity
279 * are checked/enforced, or otherwise disable all input validation (e.g. is the
280 * given qubit index valid?). Note passing erroneous input while validation is
281 * disabled can result in runtime errors like segmentation faults.
282 * @{
283 */
284
285
286/** Sets the function which QuEST will call when encountering an invalid input.
287 *
288 * By default, when a user passes an invalid input to QuEST (such as a negative qubit index),
289 * an internal function @c default_inputErrorHandler() is called which prints a message to
290 * @c stdout, attempts to gracefully clean up communication in distributed settings, then
291 * exits execution with @c exit(EXIT_FAILURE). If this is undesired, setQuESTInputErrorHandler()
292 * allows the user to substitute @p callback for the default handler, which will receive the
293 * throwing API function name @p func, and the error message string @p msg.
294 *
295 * QuEST endeavours to perform input validation upfront before proceeding to any mutation
296 * of passed objects (like a Qureg). This permits gracefully catching validation errors through
297 * custom handling without corrupting QuEST's state. For example, @c C++ users may wish
298 * to throw an exception within @p callback, or MPI superusers may wish to perform custom
299 * communicator cleanup before exiting.
300 *
301 * > [!IMPORTANT]
302 * > It is crucial that @p callback does not return execution back to the throwing
303 * > QuEST function, which is likely to cause a segmentation fault or other internal
304 * > error. Instead, @p callback should exit or throw an exception, caught by the
305 * > user's control flow.
306 *
307 * Note validation can be changed or disabled with setQuESTValidationEpsilon() and
308 * setQuESTValidationOff(), which affects when @p callback will be called. This function
309 * can be called at any time to update the error handler.
310 *
311 * @myexample
312 *
313 * ```
314 void myErrorHandler(const char* errFunc, const char* errMsg) {
315 printf("Ruh-roh, Raggy! Function '%s' has reported '%s'.\n", errFunc, errMsg);
316 printf("We will now be very good children and exit immediately!\n");
317 exit(0);
318 }
319
320 int main() {
321 initQuESTEnv();
322 setQuESTInputErrorHandler(myErrorHandler);
323 createQureg(9999); // invokes myErrorHandler
324 ...
325 }
326 * ```
327 *
328 * @param[in] callback a pointer to a function which accepts two `const char*` arguments.
329 * @throws @validationerror
330 * - if the QuEST environment has not been initialised via initQuESTEnv().
331 * @throws seg-fault
332 * - if @p callback is a null-ptr and an invalid input is later encountered.
333 * @see
334 * - [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/setting_errorhandler.c) and
335 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/setting_errorhandler.cpp) examples
336 * - setQuESTValidationOff()
337 * @author Tyson Jones
338 */
339void setQuESTInputErrorHandler(void (*callback)(const char* func, const char* msg));
340
341
342/** Restores QuEST's input validation.
343 *
344 * This means that invalid inputs to other QuEST API functions will call the error handler
345 * (the default, or one passed to setQuESTInputErrorHandler()), rather than be silently ignored.
346 *
347 * This function only has an affect if setQuESTValidationOff() was prior called. This function
348 * does not affect the validation epsilon controlled with setQuESTValidationEpsilon(), which when
349 * zero, will still see the skipping of numerically-approximated validations (such as unitarity checks).
350 *
351 * @see
352 * - setQuESTValidationOff()
353 * @author Tyson Jones
354 */
356
357
358/** Disables all of QuEST's input validation.
359 *
360 * When a QuEST API function encounters an invalid input, the error will be ignored and execution of the
361 * function will proceed. This is useful in order to call a QuEST function in a manner which is ordinarily
362 * forbidden to avoid user mistakes.
363 *
364 * > [!IMPORTANT]
365 * > This function disables all of QuEST's runtime input validation, meaning invalid inputs such as
366 * > negative qubit indices will be accepted and trusted, likely causing internal errors and segmentation faults.
367 *
368 * Users wishing only to adjust numerical validation tolerances, or disable numerical validations such as
369 * matrix unitarity checks, should instead use the safer setQuESTValidationEpsilon(). If it is essential to
370 * disable all validation, it should be later restored with setQuESTValidationOn().
371 *
372 * @myexample
373 *
374 * ```
375 Qureg qureg = createDensityQureg(3); // ~ 6-qubit statevector
376 CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4}});
377
378 int target = 4; // 0-2 valid, 3-5 hacky, 6+ seg-fault
379
380 setQuESTValidationOff();
381 leftapplyCompMatr1(qureg, target, matr);
382 setQuESTValidationOn();
383 * ```
384 *
385 * @see
386 * - setQuESTValidationOn()
387 * - setQuESTValidationEpsilon()
388 * - setQuESTInputErrorHandler()
389 * @author Tyson Jones
390 */
392
393
394/** Restores QuEST's validation threshold for testing numerical or approximate quantities, to its default value.
395 *
396 * The default value is informed by the environment variable `QUEST_DEFAULT_VALIDATION_EPSILON`. If the
397 * environment variable was not specified during the launch of the QuEST executable, then the default
398 * validation epsilon is specific to the precision of `qreal`, as controlled by `QUEST_FLOAT_PRECISION`.
399 * These are:
400 * | @c QUEST_FLOAT_PRECISION | @c qreal | default epsilon |
401 * |--------------------------|-----------|-----------------|
402 * | 1 | @c float | @c 1E-5 |
403 * | 2 | @c double | @c 1E-12 |
404 * | 4 | @c long @c double | @c 1E-15 |
405 *
406 * @see
407 * - setQuESTValidationEpsilon()
408 * @author Tyson Jones
409 */
411
412
413/** Modifies QuEST's validation threshold for testing numerical or approximate quantities, to @p eps.
414 *
415 * Many of QuEST's API functions validate that expected numerical properties of the input are satisfied.
416 * For example, that the matrix passed to applyCompMatr1() is unitary, and ergo that the
417 * product of the matrix with its own adjoint produces the identity matrix. Due to floating-point error,
418 * such properties cannot be evaluated exactly, and small disagreement between the expected and given
419 * property is tolerated. This difference is the validation epsilon, as overridden by this function.
420 * Precisely how the validation epsilon is used by numerical validation is function specific, and
421 * individually documented.
422 *
423 * > [!TIP]
424 * > Passing @p eps=0 effectively encodes @p eps=infinity, and *disables* all numerical validation.
425 *
426 * The validation epsilon has no effect on non-numerical validation, such as whether qubit incices
427 * are valid. In general, it is therefore safe to modify and disable numerical validation via this
428 * function.
429 *
430 * The default validation epsilon, which can itself be controlled by the `QUEST_DEFAULT_VALIDATION_EPSILON`
431 * environment variable, is restored via setQuESTValidationEpsilonToDefault().
432 *
433 * Note that many data structures (e.g. CompMatr, DiagMatr, KrausMap) will assess epsilon-dependent
434 * validation properties such as unitarity _once_, recording the result in a persistent heap field
435 * (like KrausMap.isApproxCPTP) to avoid superfluous re-calculation.
436 * Updating the global validation epsilon via this function will update all persistent heap fields,
437 * marking epsilon-dependent properties as "unknown", which will be lazily re-evaluated when validation
438 * is next performed. Ergo, calling this function can cause later additional function overheads.
439 *
440 * @myexample
441 *
442 * ```
443 // | max [matr . adj(matr) - identity] |^2 = 576
444 CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4}}); // non-unitary
445 setQuESTValidationEpsilon(576.0);
446 applyCompMatr1(qureg, 0, matr); // no error
447
448 matr.elems[0][0] = 999;
449 setQuESTValidationEpsilon(0); // disable all numerical validation
450 applyCompMatr1(qureg, 0, matr); // no error
451
452 // target=-1 would still trigger an error
453 // applyCompMatr1(qureg, -1, matr);
454 * ```
455 *
456 * @param[in] eps the new validation epsilon.
457 * @throws @validationerror
458 * - if the QuEST environment has not been initialised via initQuESTEnv().
459 * - if @p eps is negative.
460 * @see
461 * - setQuESTValidationEpsilonToDefault()
462 * - getQuESTValidationEpsilon()
463 * - setQuESTValidationOff()
464 * @author Tyson Jones
465 */
466void setQuESTValidationEpsilon(qreal eps);
467
468
469/** Returns the threshold used by QuEST's numerical validation.
470 *
471 * This is the value last passed to setQuESTValidationEpsilon(), unless overridden by
472 * setQuESTValidationEpsilonToDefault(), or similarly if never called. It indicates the
473 * precision and correctness demanded of input numerical quantities to the QuEST API. A larger
474 * epsilon corresponds to more permissive validation, while a smaller epsilon means validation
475 * is harder to pass and input quantities must be more carefully prepared.
476 *
477 * > [!NOTE]
478 * > A validation epsilon of @c 0 indicates numerical validation is disabled.
479 *
480 * The exact usage of the validation epsilon is function specific. For an example, see applyCompMatr1().
481 * The validation has no effect when validation has been disabled entirely via setQuESTValidationOff().
482 *
483 * @returns The validation epsilon.
484 * @see
485 * - setQuESTValidationEpsilon()
486 * - setQuESTValidationEpsilonToDefault()
487 * - setQuESTValidationOff()
488 * @author Tyson Jones
489 */
491
492
493/** @} */
494
495
496
497/**
498 * @defgroup debug_reporting Reporting
499 * @brief Functions to control how QuEST's reporters display and truncate information.
500 * @{
501 */
502
503
504/** Sets the maximum number of rows and columns of data structures subsequently printed by
505 * QuEST's report functions, with remaining elements ellipted.
506 *
507 * This function is useful for keeping @c stdout concise and readable when reporting
508 * large data structures, such as matrices and Qureg. The ellipted elements are in
509 * the _center_ of the reported data structure. The specified maximums persist until
510 * changed again with this function.
511 *
512 * > [!TIP]
513 * > Specifying @p numRows=0 or @p numCols=0 respectively disables ellipsis across
514 * > rows and columns respectively. Beware this means that functions like reportQureg()
515 * > will display the entirety of their data, which can be very large.
516 *
517 * This function presently affects the output of functions:
518 * - reportQureg()
519 * - reportPauliStrSum()
520 * - reportCompMatr1()
521 * - reportCompMatr2()
522 * - reportCompMatr()
523 * - reportDiagMatr1()
524 * - reportDiagMatr2()
525 * - reportDiagMatr()
526 * - reportFullStateDiagMatr()
527 * - reportKrausMap()
528 * - reportSuperOp()
529 *
530 * In contrast, it has no effect on the output of functions:
531 * - reportPauliStr()
532 * - reportScalar()
533 * - reportStr()
534 *
535 * > When this function is not called, the QuEST defaults are adopted, which are presently:
536 * > - @c numRows=32
537 * > - @c numCols=4
538 *
539 * @myexample
540 *
541 * ```cpp
542 Qureg qureg = createDensityQureg(6);
543 initRandomPureState(qureg);
544 setQuESTMaxNumReportedItems(7,4);
545 reportQureg(qureg);
546 * ```
547 * will report 7 rows and 4 columns of @c qureg.
548 * ```text
549 Qureg (6 qubit density matrix, 64x64 qcomps, 64.1 KiB):
550 0.012273+(3.2329e-19)i -0.0056906+0.0072884i … -0.0052104-0.0070839i 0.00092891-0.0086299i
551 -0.0056906-0.0072884i 0.0069669-(1.363e-20)i … -0.0017909+0.0063788i -0.0055556+0.0034498i
552 0.014757-0.0083751i -0.0018689+0.012647i … -0.011099-0.0049622i -0.0047721-0.011011i
553 0.00078401+0.0014319i -0.0012139-0.00019834i … 0.00049365-0.0010604i 0.0010662-0.00044291i
554 ⋮
555 -0.010456+0.012047i -0.0023056-0.011795i … 0.011393+0.00092115i 0.0076794+0.0082644i
556 -0.0052104+0.0070839i -0.0017909-0.0063788i … 0.0063009-(3.3799e-20)i 0.0045868+0.0041999i
557 0.00092891+0.0086299i -0.0055556-0.0034498i … 0.0045868-0.0041999i 0.0061386-(1.4941e-19)i
558 * ```
559 *
560 * @param[in] numRows the max number of rows to report (all if @c =0).
561 * @param[in] numCols the max number of columns to report (all if @c =0).
562 * @throws @validationerror
563 * - if the QuEST environment has not been initialised via initQuESTEnv().
564 * - if either @p numRows or @p numCols is negative.
565 * @see
566 * - [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/reporting_matrices.c) and
567 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/reporting_matrices.cpp) examples
568 * - setQuESTMaxNumReportedSigFigs()
569 * - setQuESTNumReportedNewlines()
570 */
571void setQuESTMaxNumReportedItems(qindex numRows, qindex numCols);
572
573
574/** Sets the maximum number of significant figures in floating-point numbers printed by
575 * QuEST's reporter functions.
576 *
577 * This function is useful for keeping @c stdout concise and readable when reporting
578 * numerical quantites, such as matrices and Qureg amplitudes. The specified number of
579 * significant figures persists until changed again with this function.
580 *
581 * > [!TIP]
582 * > Numbers with _fewer_ non-zero significant figures will _not_ be padded with zeros,
583 * > and so will print fewer digits than @p numSigFigs, keeping the output concise.
584 *
585 * > [!NOTE]
586 * > Complex quantities will have their real and imaginary components separately printed,
587 * > each with the specified number of significant figures.
588 *
589 * > [!IMPORTANT]
590 * > This function does not affect the significant figures in printed memory sizes
591 * > (e.g. `5.32 KiB`) which is always shown with three significant figures
592 * > (or four when in bytes, e.g. `1023 bytes`).
593 *
594 * @myexample
595 *
596 * ```cpp
597 Qureg qureg = createQureg(3);
598 initRandomPureState(qureg);
599
600 setQuESTMaxNumReportedSigFigs(2);
601 reportQureg(qureg);
602
603 setQuESTMaxNumReportedSigFigs(10);
604 reportQureg(qureg);
605 * ```
606 * may output
607 * ```text
608 Qureg (3 qubit statevector, 8 qcomps, 232 bytes):
609 0.49+0.35i |0⟩
610 -0.085+0.17i |1⟩
611 0.37+0.099i |2⟩
612 -0.14+0.088i |3⟩
613 -0.29+0.078i |4⟩
614 0.19+0.019i |5⟩
615 0.02-0.5i |6⟩
616 -0.032+0.22i |7⟩
617
618 Qureg (3 qubit statevector, 8 qcomps, 232 bytes):
619 0.4915502074+0.3471270204i |0⟩
620 -0.08473589829+0.1685819182i |1⟩
621 0.3702183582+0.0991921232i |2⟩
622 -0.142193399+0.08829704821i |3⟩
623 -0.2881909331+0.07795511511i |4⟩
624 0.1868915394+0.01946703883i |5⟩
625 0.01956017542-0.5029788111i |6⟩
626 -0.03171267079+0.220342331i |7⟩
627 * ```
628 * Meanwhile,
629 * ```cpp
630 CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4.123456789}});
631 setQuESTMaxNumReportedSigFigs(3);
632 reportCompMatr1(matr);
633 * ```
634 * will output
635 * ```text
636 CompMatr1 (1 qubit, 2x2 qcomps, 80 bytes):
637 1 2
638 3 4.12
639 * ```
640 *
641 * @param[in] numSigFigs the max number of significant figures to print in subsequent report functions.
642 * @throws @validationerror
643 * - if the QuEST environment has not been initialised via initQuESTEnv().
644 * - if @p numSigFigs is negative.
645 * @see
646 * - setQuESTMaxNumReportedItems()
647 * - setQuESTNumReportedNewlines()
648 * @author Tyson Jones
649 */
650void setQuESTMaxNumReportedSigFigs(int numSigFigs);
651
652
653/** Sets the number of trailing newlines printed at the end of QuEST's report functions.
654 *
655 * These newlines are merely a convenience so that users do not have to manually intersperse
656 * newlines in @c stdout between functions like reportScalar() and reportPauliStr(),
657 * which becomes a greater pain in distributed settings when avoiding duplicated output
658 * across processes. The specified number of newlines persists until changed again with
659 * this function.
660 *
661 * @myexample
662 *
663 * By default, the sequence
664 * ```cpp
665 reportCompMatr1(getInlineCompMatr1({{1,2},{3,4}}));
666 reportPauliStr(getInlinePauliStr("XYZ", {0,2,4}));
667 reportScalar("x", 5);
668 reportStr("hello world!");
669 * ```
670 * will print with the internal default of @p numNewLines=2
671 * ```text
672 CompMatr1 (1 qubit, 2x2 qcomps, 80 bytes):
673 1 2
674 3 4
675
676 ZIYIX
677
678 x: 5
679
680 hello world!
681 * ```
682 * but if called after @c setQuESTNumReportedNewlines(1), will output
683 * ```text
684 CompMatr1 (1 qubit, 2x2 qcomps, 80 bytes):
685 1 2
686 3 4
687 ZIYIX
688 x: 5
689 hello world!
690 * ```
691 * It is possible to forego all trailing newlines, and also to write to @c stdout between
692 * report functions.
693 * ```cpp
694 setQuESTNumReportedNewlines(0);
695 reportPauliStr(getInlinePauliStr("XYZ", {0,2,4}));
696 printf(" * ");
697 reportPauliStr(getInlinePauliStr("ZZZ", {0,1,2}));
698 printf(" = ");
699 reportPauliStr(getInlinePauliStr("YZXZ", {0,1,2,4}));
700 printf("\n");
701 * ```
702 * ```text
703 ZIYIX * ZZZ = ZIXZY
704 * ```
705 *
706 * @param[in] numNewlines the new number of trailing newlines.
707 * @throws @validationerror
708 * - if the QuEST environment has not been initialised via initQuESTEnv().
709 * - if @p numNewlines is negative.
710 * @author Tyson Jones
711 */
712void setQuESTNumReportedNewlines(int numNewlines);
713
714
715/** Sets the characters used by reportPauliStr() and reportPauliStrSum() to indicate the
716 * @c I, @c X, @c Y and @c Z Pauli operators.
717 *
718 * @myexample
719 * ```cpp
720 PauliStr str = getInlinePauliStr("XYZZ", {0,10,13,20});
721 reportPauliStr(str);
722
723 setQuESTReportedPauliChars(".xyz");
724 reportPauliStr(str);
725
726 setQuESTReportedPauliChars(" !!!");
727 reportPauliStr(str);
728 * ```
729 * ```text
730 ZIIIIIIZIIYIIIIIIIIIX
731
732 z......z..y.........x
733
734 ! ! ! !
735 * ```
736 * These symbols are used across all styles accepted by setQuESTReportedPauliStrStyle().
737 * ```cpp
738 setQuESTReportedPauliStrStyle(1); // style=1
739 setQuESTReportedPauliChars(".XyS");
740 reportPauliStr(str);
741 * ```
742 * ```text
743 X0 y10 S13 S20
744 * ```
745 *
746 * @param[in] paulis four characters to indicate @c I, @c X, @c Y and @c Z respectively.
747 * @throws @validationerror
748 * - if the QuEST environment has not been initialised via initQuESTEnv().
749 * - if @p paulis is not length @c 4.
750 * @throws seg-fault
751 * - if @p paulis is a null pointer.
752 * - if @p paulis does not contain a terminal character and is smaller than 4 bytes in size.
753 * @see
754 * - setQuESTReportedPauliStrStyle()
755 * @author Tyson Jones
756 */
757void setQuESTReportedPauliChars(const char* paulis);
758
759
760/** Sets the visual style of Pauli strings printed by reportPauliStr() and reportPauliStrSum().
761 *
762 * - When @p style=0 (default), every Pauli operator in the string is printed, _until_ the
763 * largest-index non-identity operator. The rightmost printed operator is the least
764 * significant (i.e. of qubit index @c 0).
765 *
766 * For example:
767 * ```cpp
768 setQuESTReportedPauliStrStyle(0); // default
769 reportPauliStr(getInlinePauliStr("XYZZ", {0,10,13,20}));
770 * ```
771 * ```text
772 ZIIIIIIZIIYIIIIIIIIIX
773 * ```
774 *
775 * - When @p style=1, only non-identity Pauli operators are printed, followed by their indices.
776 *
777 * For example:
778 * ```cpp
779 setQuESTReportedPauliStrStyle(1);
780 reportPauliStr(getInlinePauliStr("XYZZ", {0,10,13,20}));
781 * ```
782 * ```text
783 X0 Y10 Z13 Z20
784 * ```
785 *
786 * The symbols for @c I, @c X, @c Y and @c Z can be overridden with setQuESTReportedPauliChars().
787 *
788 * @param[in] style either @c 0 or @c 1 to respectively indicate the above styles.
789 * @throws @validationerror
790 * - if the QuEST environment has not been initialised via initQuESTEnv().
791 * - if @p style is not @c 0 or @c 1.
792 * @see
793 * - setQuESTReportedPauliChars()
794 * @author Tyson Jones
795 */
796void setQuESTReportedPauliStrStyle(int style);
797
798
799/** @} */
800
801
802
803/**
804 * @defgroup debug_cache Caching
805 * @brief Functions to control temporary memory used by the QuEST process.
806 * @{
807 */
808
809
810/** Returns the current size (in bytes) of the persistent GPU cache used to accelerate
811 * QuEST.
812 *
813 * Some QuEST functions involve allocating non-trivial device data, which persists between
814 * invocations for effiency. For example, applyCompMatr() when given a matrix of more than
815 * five qubits, will allocate data proportional in size to the matrix dimension and the
816 * simulated Qureg size. This allocation happens on-the-fly.
817 *
818 * This function returns the size of that cache. It does not include device memory consumed
819 * by persistent QuEST objects, such as Qureg and CompMatr.
820 * When QuEST is not running in GPU-accelerated mode, this function always returns @c 0.
821 *
822 * @returns The current GPU cache size in bytes.
823 * @see
824 * - clearQuESTGpuCache()
825 * @author Tyson Jones
826 */
827qindex getQuESTGpuCacheSize();
828
829
830/** Clears QuEST's GPU cache.
831 *
832 * Some QuEST functions involve allocating non-trivial device data, which persists between
833 * invocations for effiency. For example, applyCompMatr() when given a matrix of more than
834 * five qubits, will allocate data proportional in size to the matrix dimension and the
835 * simulated Qureg size. This allocation happens on-the-fly.
836 *
837 * This function clears this cache, freeing memory at the cost of increased runtime when
838 * calling functions like applyCompMatr(), due to the overhead of reallocation therein.
839 * This function has no effect on the persistent device memory owned by QuEST objects like
840 * Qureg and CompMatr, nor does it have any effect when QuEST is not using GPU acceleration.
841 *
842 * @see
843 * - getQuESTGpuCacheSize()
844 * @author Tyson Jones
845 */
846void clearQuESTGpuCache();
847
848
849/** @} */
850
851
852
853/**
854 * @defgroup debug_info Info
855 * @brief Functions for getting debugging information.
856 * @{
857 */
858
859
860/** Writes a compact description of the active QuEST environment into @p str.
861 *
862 * The caller must provide a character buffer of length at least @c 200. The
863 * resulting string is null-terminated and summarises the current deployment.
864 *
865 * @param[out] str a character buffer of length @c 200 to overwrite.
866 * @throws @validationerror
867 * - if the QuEST environment is not initialised.
868 * @notyettested
869 * @author Tyson Jones
870 */
871void getQuESTEnvironmentString(char str[200]);
872
873
874/** @} */
875
876
877
878// end de-mangler
879#ifdef __cplusplus
880}
881#endif
882
883
884
885/*
886 * C++ OVERLOADS
887 *
888 * which are only accessible to C++ binaries, and accept
889 * arguments more natural to C++ (e.g. std::vector). We
890 * manually add these to their respective Doxygen doc groups.
891 */
892
893#ifdef __cplusplus
894
895#include <vector>
896
897
898/// @ingroup debug_seed
899/// @notyettested
900/// @notyetdoced
901/// @cppvectoroverload
902/// @see setQuESTSeeds()
903void setQuESTSeeds(std::vector<unsigned> seeds);
904
905
906/// @ingroup debug_seed
907/// @notyettested
908/// @notyetdoced
909/// @cpponly
910/// @see getQuESTSeeds()
911std::vector<unsigned> getQuESTSeeds();
912
913
914#endif // __cplusplus
915
916
917
918#endif // DEBUG_H
919
920/** @} */ // (end file-wide doxygen defgroup)
qindex getQuESTGpuCacheSize()
Definition debug.cpp:180
void clearQuESTGpuCache()
Definition debug.cpp:191
void getQuESTEnvironmentString(char str[200])
void setQuESTReportedPauliChars(const char *paulis)
Definition debug.cpp:158
void setQuESTMaxNumReportedItems(qindex numRows, qindex numCols)
Definition debug.cpp:128
void setQuESTMaxNumReportedSigFigs(int numSigFigs)
Definition debug.cpp:142
void setQuESTReportedPauliStrStyle(int style)
Definition debug.cpp:166
void setQuESTNumReportedNewlines(int numNewlines)
Definition debug.cpp:150
int getQuESTNumSeeds()
Definition debug.cpp:52
void setQuESTSeeds(unsigned *seeds, int numSeeds)
Definition debug.cpp:37
void setQuESTSeedsToDefault()
Definition debug.cpp:45
void getQuESTSeeds(unsigned *seeds)
Definition debug.cpp:58
void setQuESTValidationOff()
Definition debug.cpp:86
void setQuESTValidationEpsilonToDefault()
Definition debug.cpp:108
qreal getQuESTValidationEpsilon()
Definition debug.cpp:115
void setQuESTValidationEpsilon(qreal eps)
Definition debug.cpp:100
void setQuESTValidationOn()
Definition debug.cpp:80
void setQuESTInputErrorHandler(void(*callback)(const char *func, const char *msg))
Definition debug.cpp:74