The Quantum Exact Simulation Toolkit v4.0.0
Loading...
Searching...
No Matches
precision.h
1/** @file
2 * User-overridable numerical precision of
3 * both the QuEST API and backends
4 *
5 * @author Tyson Jones
6 * @author Milos Prokop (patched trig overloads in v3)
7 *
8 * @defgroup precision Precision
9 * @ingroup api
10 * @brief Macros for controlling QuEST's numerical precision.
11 * @{
12 */
13
14#ifndef PRECISION_H
15#define PRECISION_H
16
17#include "quest/include/modes.h"
18
19
20
21/*
22 * STATE-INDEXING TYPE
23 */
24
25// can be (for example) int, long, long long, unsigned, long unsigned, long long unsigned.
26// We make sure that the backend never relies upon being able to represent negative
27// indices (e.g. as flags) since that would require a strictly signed type. Note this precision
28// determines qindex which is user-facing so using unsigned types opens the users to the
29// risks of underflowing. Since we never store large collections of this type, there is little
30// benefit in shrinking the type size and facing the associated precision risks. Similarly,
31// there is little benefit in making it larger since a 'long long int' can represent 62 qubits,
32// which is already well beyond simulability, requiring 64 EiB total at double precision.
33// Still, we use a #define, rather than a typedef, so that the value can be compile-time overridden.
34
35/// @neverdoced
36#define INDEX_TYPE long long int
37
38// spoofing above macro as const to doc
39#if 0
40
41 /// @notdoced
42 /// @macrodoc
43 typedef long long int INDEX_TYPE;
44
45#endif
46
47
48
49/*
50 * PAULI STRING INDEXING TYPE
51 */
52
53// should never be changed; it is unsigned due to its use in extensive bitwise processing
54// (no overflow risks since the API does not use this type), and its precision constrains
55// the number of Paulis which can be specified in a PauliStr. Specifically, PauliStr stores
56// two PAULI_MASK_TYPE instances, each of which are interpreted as half the digits of a
57// base-4 numeral encoding the Pauli string. A single 64-bit 'long long unsigned' can ergo
58// specify only 32 qubits, whereas two can specify more qubits (64) than we can simulate.
59// This type is defined purely to avoid littering the source with explicit typing.
60
61/// @neverdoced
62#define PAULI_MASK_TYPE long long unsigned int
63
64// spoofing above macro as typedef to doc
65#if 0
66
67 /// @notdoced
68 /// @macrodoc
69 typedef long long unsigned int PAULI_MASK_TYPE;
70
71#endif
72
73
74
75/*
76 * RE-CONFIGURABLE FLOATING-POINT PRECISION
77 */
78
79// assume double precision as default
80#ifndef FLOAT_PRECISION
81 #define FLOAT_PRECISION 2
82#endif
83
84// validate precision is 1 (float), 2 (double) or 4 (long double)
85#if ! (FLOAT_PRECISION == 1 || FLOAT_PRECISION == 2 || FLOAT_PRECISION == 4)
86 #error "FLOAT_PRECISION must be 1 (float), 2 (double) or 4 (long double)"
87#endif
88
89// infer floating-point type from precision
90#if FLOAT_PRECISION == 1
91 #define FLOAT_TYPE float
92#elif FLOAT_PRECISION == 2
93 #define FLOAT_TYPE double
94#elif FLOAT_PRECISION == 4
95 #define FLOAT_TYPE long double
96#endif
97
98// spoofing above macros as typedefs and consts to doc
99#if 0
100
101 /// @notdoced
102 /// @macrodoc
103 const int FLOAT_PRECISION = 2;
104
105 /// @notdoced
106 /// @macrodoc
107 typedef double int FLOAT_TYPE;
108
109#endif
110
111
112
113/*
114 * CHECK PRECISION TYPES ARE COMPATIBLE WITH DEPLOYMENT
115 */
116
117#if COMPILE_CUDA && (FLOAT_PRECISION == 4)
118 #error "A quad floating-point precision (FLOAT_PRECISION=4, i.e. long double) is not supported by GPU deployment"
119#endif
120
121
122
123/*
124 * RE-CONFIGURABLE DEFAULT VALIDATION PRECISION
125 *
126 * which is compile-time overridable by pre-defining DEFAULT_VALIDATION_EPSILON (e.g.
127 * in user code before importing QuEST, or passed as a preprocessor constant by the
128 * compiler using argument -D), and runtime overridable using setValidationEpsilon()
129 */
130
131#ifndef DEFAULT_VALIDATION_EPSILON
132
133 #if FLOAT_PRECISION == 1
134 #define DEFAULT_VALIDATION_EPSILON 1E-5
135
136 #elif FLOAT_PRECISION == 2
137 #define DEFAULT_VALIDATION_EPSILON 1E-12
138
139 #elif FLOAT_PRECISION == 4
140 #define DEFAULT_VALIDATION_EPSILON 1E-13
141
142 #endif
143
144#endif
145
146// spoofing above macros as typedefs and consts to doc
147#if 0
148
149 /// @notdoced
150 /// @macrodoc
151 const qreal DEFAULT_VALIDATION_EPSILON = 1E-12;
152
153#endif
154
155
156
157/*
158 * PRECISION-AGNOSTIC CONVENIENCE MACROS
159 */
160
161#if FLOAT_PRECISION == 1
162 #define QREAL_FORMAT_SPECIFIER "%.8g"
163
164#elif FLOAT_PRECISION == 2
165 #define QREAL_FORMAT_SPECIFIER "%.14g"
166
167#elif FLOAT_PRECISION == 4
168 #define QREAL_FORMAT_SPECIFIER "%.17Lg"
169
170#endif
171
172// spoofing above macros as typedefs and consts to doc
173#if 0
174
175 /// @notdoced
176 /// @macrodoc
177 const char* QREAL_FORMAT_SPECIFIER = "%.14g";
178
179#endif
180
181
182
183#endif // PRECISION_H
184
185/** @} */ // (end file-wide doxygen defgroup)
long long int INDEX_TYPE
Definition precision.h:43
const char * QREAL_FORMAT_SPECIFIER
Definition precision.h:177
const qreal DEFAULT_VALIDATION_EPSILON
Definition precision.h:151
const int FLOAT_PRECISION
Definition precision.h:103
double int FLOAT_TYPE
Definition precision.h:107
long long unsigned int PAULI_MASK_TYPE
Definition precision.h:69