Qrack  10.0
General classical-emulating-quantum development framework
qrack_functions.hpp
Go to the documentation of this file.
1 //
3 // (C) Daniel Strano and the Qrack contributors 2017-2023. All rights reserved.
4 //
5 // This is a multithreaded, universal quantum register simulation, allowing
6 // (nonphysical) register cloning and direct measurement of probability and
7 // phase, to leverage what advantages classical emulation of qubits can have.
8 //
9 // Licensed under the GNU Lesser General Public License V3.
10 // See LICENSE.md in the project root or https://www.gnu.org/licenses/lgpl-3.0.en.html
11 // for details.
12 
13 #pragma once
14 
15 #include "qrack_types.hpp"
16 
17 #ifdef __APPLE__
18 #include "TargetConditionals.h"
19 #elif ENABLE_INTRINSICS
20 #include "immintrin.h"
21 #endif
22 
23 #include <set>
24 #include <vector>
25 #if CPP_STD >= 20
26 #include <bit>
27 #endif
28 
29 #define _bi_compare(left, right) \
30  if (left > right) { \
31  return 1; \
32  } \
33  if (left < right) { \
34  return -1; \
35  } \
36  \
37  return 0;
38 
39 #if (QBCAPPOW < 7) || ((QBCAPPOW < 8) && defined(__SIZEOF_INT128__)) || ((QBCAPPOW > 7) && defined(BOOST_AVAILABLE))
40 inline void bi_not_ip(bitCapInt* left) { *left = ~(*left); }
41 inline void bi_and_ip(bitCapInt* left, const bitCapInt& right) { *left &= right; }
42 inline void bi_or_ip(bitCapInt* left, const bitCapInt& right) { *left |= right; }
43 inline void bi_xor_ip(bitCapInt* left, const bitCapInt& right) { *left ^= right; }
44 inline double bi_to_double(const bitCapInt& in) { return (double)in; }
45 
46 inline void bi_increment(bitCapInt* pBigInt, const bitCapInt& value) { *pBigInt += value; }
47 inline void bi_decrement(bitCapInt* pBigInt, const bitCapInt& value) { *pBigInt -= value; }
48 
49 inline void bi_lshift_ip(bitCapInt* left, const size_t& right) { *left <<= right; }
50 inline void bi_rshift_ip(bitCapInt* left, const size_t& right) { *left >>= right; }
51 
52 inline int bi_and_1(const bitCapInt& left) { return (bool)(left & 1); }
53 
54 inline int bi_compare(const bitCapInt& left, const bitCapInt& right) { _bi_compare(left, right) }
55 inline int bi_compare_0(const bitCapInt& left) { return (int)(bool)left; }
56 inline int bi_compare_1(const bitCapInt& left) { _bi_compare(left, 1U); }
57 
58 inline void bi_add_ip(bitCapInt* left, const bitCapInt& right) { *left += right; }
59 inline void bi_sub_ip(bitCapInt* left, const bitCapInt& right) { *left -= right; }
60 
61 inline void bi_div_mod(const bitCapInt& left, const bitCapInt& right, bitCapInt* quotient, bitCapInt* rmndr)
62 {
63  if (quotient) {
64  *quotient = left / right;
65  }
66  if (rmndr) {
67  *rmndr = left % right;
68  }
69 }
70 #ifdef __SIZEOF_INT128__
71 inline void bi_div_mod_small(const bitCapInt& left, uint64_t right, bitCapInt* quotient, uint64_t* rmndr)
72 {
73  if (quotient) {
74  *quotient = left / right;
75  }
76  if (rmndr) {
77  *rmndr = (uint64_t)(left % right);
78  }
79 }
80 #else
81 inline void bi_div_mod_small(const bitCapInt& left, uint32_t right, bitCapInt* quotient, uint32_t* rmndr)
82 {
83  if (quotient) {
84  *quotient = left / right;
85  }
86  if (rmndr) {
87  *rmndr = (uint32_t)(left % right);
88  }
89 }
90 #endif
91 #endif
92 
93 namespace Qrack {
94 
96 {
97 // Source: https://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers#answer-11376759
98 #if CPP_STD >= 20
99  return std::bit_width(n) - 1U;
100 #elif ENABLE_INTRINSICS && defined(_WIN32) && !defined(__CYGWIN__)
101 #if UINTPOW < 6
102  return (bitLenInt)(bitsInByte * sizeof(unsigned int) - _lzcnt_u32((unsigned int)n) - 1U);
103 #else
104  return (bitLenInt)(bitsInByte * sizeof(unsigned long long) - _lzcnt_u64((unsigned long long)n) - 1U);
105 #endif
106 #elif ENABLE_INTRINSICS && !defined(__APPLE__)
107 #if UINTPOW < 6
108  return (bitLenInt)(bitsInByte * sizeof(unsigned int) - __builtin_clz((unsigned int)n) - 1U);
109 #else
110  return (bitLenInt)(bitsInByte * sizeof(unsigned long long) - __builtin_clzll((unsigned long long)n) - 1U);
111 #endif
112 #else
113  bitLenInt pow = 0U;
114  bitCapIntOcl p = n >> 1U;
115  while (p) {
116  p >>= 1U;
117  ++pow;
118  }
119  return pow;
120 #endif
121 }
122 
124 {
125 #if CPP_STD >= 20
126  return (bitLenInt)std::popcount(n);
127 #elif (defined(__GNUC__) || defined(__clang__)) && !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
128  return __builtin_popcount(n);
129 #else
130  bitLenInt popCount;
131  for (popCount = 0U; n; ++popCount) {
132  n &= n - 1U;
133  }
134  return popCount;
135 #endif
136 }
137 
138 #if (QBCAPPOW < 7) || ((QBCAPPOW < 8) && defined(__SIZEOF_INT128__)) || ((QBCAPPOW > 7) && defined(BOOST_AVAILABLE))
139 inline int bi_log2(const bitCapInt& n) { return log2Ocl((bitCapIntOcl)n); }
140 #endif
141 inline bitLenInt log2(bitCapInt n) { return (bitLenInt)bi_log2(n); }
142 
143 inline bitCapInt pow2(const bitLenInt& p) { return ONE_BCI << p; }
144 inline bitCapIntOcl pow2Ocl(const bitLenInt& p) { return (bitCapIntOcl)1U << p; }
145 inline bitCapInt pow2Mask(const bitLenInt& p)
146 {
147  bitCapInt toRet = ONE_BCI << p;
148  bi_decrement(&toRet, 1U);
149  return toRet;
150 }
151 inline bitCapIntOcl pow2MaskOcl(const bitLenInt& p) { return ((bitCapIntOcl)1U << p) - 1U; }
152 inline bitCapInt bitSlice(const bitLenInt& bit, const bitCapInt& source) { return (ONE_BCI << bit) & source; }
153 inline bitCapIntOcl bitSliceOcl(const bitLenInt& bit, const bitCapIntOcl& source)
154 {
155  return ((bitCapIntOcl)1U << bit) & source;
156 }
157 inline bitCapInt bitRegMask(const bitLenInt& start, const bitLenInt& length)
158 {
159  bitCapInt toRet = ONE_BCI << length;
160  bi_decrement(&toRet, 1U);
161  bi_lshift_ip(&toRet, start);
162  return toRet;
163 }
164 inline bitCapIntOcl bitRegMaskOcl(const bitLenInt& start, const bitLenInt& length)
165 {
166  return (((bitCapIntOcl)1U << length) - 1U) << start;
167 }
168 // Source: https://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/
169 inline bool isPowerOfTwo(const bitCapInt& x)
170 {
171  bitCapInt y = x;
172  bi_decrement(&y, 1U);
173  bi_and_ip(&y, x);
174  return (bi_compare_0(x) != 0) && (bi_compare_0(y) == 0);
175 }
176 inline bool isPowerOfTwoOcl(const bitCapIntOcl& x) { return x && !(x & (x - 1U)); }
177 inline bool isBadBitRange(const bitLenInt& start, const bitLenInt& length, const bitLenInt& qubitCount)
178 {
179  return ((start + length) > qubitCount) || ((bitLenInt)(start + length) < start);
180 }
181 inline bool isBadPermRange(const bitCapIntOcl& start, const bitCapIntOcl& length, const bitCapIntOcl& maxQPowerOcl)
182 {
183  return ((start + length) > maxQPowerOcl) || ((bitCapIntOcl)(start + length) < start);
184 }
186  const std::vector<bitLenInt>& controls, const bitLenInt& qubitCount, std::string message)
187 {
188  std::set<bitLenInt> dupes;
189  for (const bitLenInt& control : controls) {
190  if (control >= qubitCount) {
191  throw std::invalid_argument(message);
192  }
193 
194  if (dupes.find(control) == dupes.end()) {
195  dupes.insert(control);
196  } else {
197  throw std::invalid_argument(message + " (Found duplicate qubit indices!)");
198  }
199  }
200 }
201 
202 // These are utility functions defined in qinterface/protected.cpp:
203 unsigned char* cl_alloc(size_t ucharCount);
204 void cl_free(void* toFree);
205 void mul2x2(const complex* left, const complex* right, complex* out);
206 void exp2x2(const complex* matrix2x2, complex* outMatrix2x2);
207 void log2x2(const complex* matrix2x2, complex* outMatrix2x2);
208 void inv2x2(const complex* matrix2x2, complex* outMatrix2x2);
209 bool isOverflowAdd(
210  bitCapIntOcl inOutInt, bitCapIntOcl inInt, const bitCapIntOcl& signMask, const bitCapIntOcl& lengthPower);
211 bool isOverflowSub(
212  bitCapIntOcl inOutInt, bitCapIntOcl inInt, const bitCapIntOcl& signMask, const bitCapIntOcl& lengthPower);
213 bitCapInt pushApartBits(const bitCapInt& perm, const std::vector<bitCapInt>& skipPowers);
214 bitCapInt intPow(const bitCapInt& base, const bitCapInt& power);
216 
217 #if QBCAPPOW > 6
218 std::ostream& operator<<(std::ostream& os, const bitCapInt& b);
219 std::istream& operator>>(std::istream& is, bitCapInt& b);
220 #endif
221 
222 #if ENABLE_ENV_VARS
223 const real1_f _qrack_qunit_sep_thresh = getenv("QRACK_QUNIT_SEPARABILITY_THRESHOLD")
224  ? (real1_f)std::stof(std::string(getenv("QRACK_QUNIT_SEPARABILITY_THRESHOLD")))
225  : FP_NORM_EPSILON;
226 const real1_f _qrack_qbdt_sep_thresh = getenv("QRACK_QBDT_SEPARABILITY_THRESHOLD")
227  ? (real1_f)std::stof(std::string(getenv("QRACK_QBDT_SEPARABILITY_THRESHOLD")))
228  : FP_NORM_EPSILON;
230  getenv("QRACK_MAX_CPU_QB") ? (bitLenInt)std::stoi(std::string(getenv("QRACK_MAX_CPU_QB"))) : -1;
231 const bitLenInt QRACK_MAX_PAGE_QB_DEFAULT = getenv("QRACK_MAX_PAGE_QB")
232  ? (bitLenInt)std::stoi(std::string(getenv("QRACK_MAX_PAGE_QB")))
234 const bitLenInt QRACK_MAX_PAGING_QB_DEFAULT = getenv("QRACK_MAX_PAGING_QB")
235  ? (bitLenInt)std::stoi(std::string(getenv("QRACK_MAX_PAGING_QB")))
238  getenv("QRACK_MAX_CPU_QB") ? QRACK_MAX_CPU_QB_DEFAULT : 32U;
240  (bitLenInt)(getenv("QRACK_PSTRIDEPOW") ? std::stoi(std::string(getenv("QRACK_PSTRIDEPOW"))) : PSTRIDEPOW);
241 const size_t QRACK_QBDT_MAX_ALLOC_MB_DEFAULT =
242  (size_t)(getenv("QRACK_QBDT_MAX_ALLOC_MB") ? std::stoi(std::string(getenv("QRACK_QBDT_MAX_ALLOC_MB"))) : -1);
244  (size_t)(getenv("QRACK_SPARSE_MAX_ALLOC_MB") ? std::stoi(std::string(getenv("QRACK_SPARSE_MAX_ALLOC_MB"))) : -1);
245 const real1_f _qrack_sparse_thresh = getenv("QRACK_SPARSE_TRUNCATION_THRESHOLD")
246  ? (real1_f)std::stof(std::string(getenv("QRACK_SPARSE_TRUNCATION_THRESHOLD")))
247  : REAL1_EPSILON;
248 #else
255 const bitLenInt PSTRIDEPOW_DEFAULT = PSTRIDEPOW;
259 #endif
263 } // namespace Qrack
GLOSSARY: bitLenInt - "bit-length integer" - unsigned integer ID of qubit position in register bitCap...
Definition: complex16x2simd.hpp:25
void ThrowIfQbIdArrayIsBad(const std::vector< bitLenInt > &controls, const bitLenInt &qubitCount, std::string message)
Definition: qrack_functions.hpp:185
bitCapInt bitRegMask(const bitLenInt &start, const bitLenInt &length)
Definition: qrack_functions.hpp:157
void cl_free(void *toFree)
Definition: functions.cpp:49
void exp2x2(const complex *matrix2x2, complex *outMatrix2x2)
Definition: functions.cpp:200
bool isPowerOfTwo(const bitCapInt &x)
Definition: qrack_functions.hpp:169
const real1_f _qrack_qunit_sep_thresh
Definition: qrack_functions.hpp:249
const bitLenInt QRACK_MAX_PAGING_QB_DEFAULT
Definition: qrack_functions.hpp:253
int bi_log2(const bitCapInt &n)
Definition: qrack_functions.hpp:139
void mul2x2(const complex *left, const complex *right, complex *out)
Definition: functions.cpp:113
unsigned char * cl_alloc(size_t ucharCount)
Definition: functions.cpp:27
bitLenInt log2Ocl(bitCapIntOcl n)
Definition: qrack_functions.hpp:95
const size_t QRACK_SPARSE_MAX_KEYS
Definition: qrack_functions.hpp:262
const size_t QRACK_QBDT_MAX_ALLOC_BYTES_DEFAULT
Definition: qrack_functions.hpp:260
void U(quid sid, bitLenInt q, real1_f theta, real1_f phi, real1_f lambda)
(External API) 3-parameter unitary gate
Definition: wasm_api.cpp:1199
std::istream & operator>>(std::istream &os, QCircuitGatePtr &g)
Definition: qcircuit.cpp:38
std::complex< real1 > complex
Definition: qrack_types.hpp:136
const real1_f _qrack_qbdt_sep_thresh
Definition: qrack_functions.hpp:250
const bitLenInt PSTRIDEPOW_DEFAULT
Definition: qrack_functions.hpp:255
void log2x2(const complex *matrix2x2, complex *outMatrix2x2)
Definition: functions.cpp:202
const real1_f _qrack_sparse_thresh
Definition: qrack_functions.hpp:258
const bitLenInt QRACK_MAX_PAGE_QB_DEFAULT
Definition: qrack_functions.hpp:252
QRACK_CONST real1 FP_NORM_EPSILON
Definition: qrack_types.hpp:268
const bitLenInt QRACK_MAX_CPU_QB_DEFAULT
Definition: qrack_functions.hpp:251
bitCapInt pushApartBits(const bitCapInt &perm, const std::vector< bitCapInt > &skipPowers)
Definition: functions.cpp:260
bitCapInt pow2(const bitLenInt &p)
Definition: qrack_functions.hpp:143
constexpr size_t SPARSE_KEY_BYTES
Definition: qrack_types.hpp:260
bitCapIntOcl bitRegMaskOcl(const bitLenInt &start, const bitLenInt &length)
Definition: qrack_functions.hpp:164
QRACK_CONST real1 REAL1_EPSILON
Definition: qrack_types.hpp:208
bitCapInt bitSlice(const bitLenInt &bit, const bitCapInt &source)
Definition: qrack_functions.hpp:152
void inv2x2(const complex *matrix2x2, complex *outMatrix2x2)
Definition: functions.cpp:204
bitLenInt popCountOcl(bitCapIntOcl n)
Definition: qrack_functions.hpp:123
bitCapInt pow2Mask(const bitLenInt &p)
Definition: qrack_functions.hpp:145
float real1_f
Definition: qrack_types.hpp:103
const bitLenInt QRACK_QRACK_QTENSORNETWORK_THRESHOLD_CPU_QB
Definition: qrack_functions.hpp:254
bitCapIntOcl intPowOcl(bitCapIntOcl base, bitCapIntOcl power)
Definition: functions.cpp:77
bool isPowerOfTwoOcl(const bitCapIntOcl &x)
Definition: qrack_functions.hpp:176
const size_t QRACK_SPARSE_MAX_ALLOC_MB_DEFAULT
Definition: qrack_functions.hpp:257
bool isOverflowSub(bitCapIntOcl inOutInt, bitCapIntOcl inInt, const bitCapIntOcl &signMask, const bitCapIntOcl &lengthPower)
Check if a subtraction with overflow sets the flag.
Definition: functions.cpp:237
const size_t QRACK_SPARSE_MAX_ALLOC_BYTES_DEFAULT
Definition: qrack_functions.hpp:261
bitCapInt intPow(const bitCapInt &base, const bitCapInt &power)
Definition: functions.cpp:59
std::ostream & operator<<(std::ostream &os, const QCircuitGatePtr g)
Definition: qcircuit.cpp:17
const size_t QRACK_QBDT_MAX_ALLOC_MB_DEFAULT
Definition: qrack_functions.hpp:256
bitCapIntOcl pow2MaskOcl(const bitLenInt &p)
Definition: qrack_functions.hpp:151
bool isBadPermRange(const bitCapIntOcl &start, const bitCapIntOcl &length, const bitCapIntOcl &maxQPowerOcl)
Definition: qrack_functions.hpp:181
const bitCapInt ONE_BCI
Definition: qrack_types.hpp:137
bool isBadBitRange(const bitLenInt &start, const bitLenInt &length, const bitLenInt &qubitCount)
Definition: qrack_functions.hpp:177
bitCapIntOcl pow2Ocl(const bitLenInt &p)
Definition: qrack_functions.hpp:144
bitCapIntOcl bitSliceOcl(const bitLenInt &bit, const bitCapIntOcl &source)
Definition: qrack_functions.hpp:153
bitLenInt log2(bitCapInt n)
Definition: qrack_functions.hpp:141
bool isOverflowAdd(bitCapIntOcl inOutInt, bitCapIntOcl inInt, const bitCapIntOcl &signMask, const bitCapIntOcl &lengthPower)
Check if an addition with overflow sets the flag.
Definition: functions.cpp:214
half pow(half x, half y)
Power function.
Definition: half.hpp:3738
void bi_and_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:41
int bi_compare_1(const bitCapInt &left)
Definition: qrack_functions.hpp:56
int bi_and_1(const bitCapInt &left)
Definition: qrack_functions.hpp:52
void bi_xor_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:43
void bi_not_ip(bitCapInt *left)
Definition: qrack_functions.hpp:40
int bi_compare_0(const bitCapInt &left)
Definition: qrack_functions.hpp:55
int bi_compare(const bitCapInt &left, const bitCapInt &right)
Definition: qrack_functions.hpp:54
void bi_increment(bitCapInt *pBigInt, const bitCapInt &value)
Definition: qrack_functions.hpp:46
void bi_div_mod_small(const bitCapInt &left, uint32_t right, bitCapInt *quotient, uint32_t *rmndr)
Definition: qrack_functions.hpp:81
double bi_to_double(const bitCapInt &in)
Definition: qrack_functions.hpp:44
void bi_div_mod(const bitCapInt &left, const bitCapInt &right, bitCapInt *quotient, bitCapInt *rmndr)
Definition: qrack_functions.hpp:61
void bi_rshift_ip(bitCapInt *left, const size_t &right)
Definition: qrack_functions.hpp:50
void bi_decrement(bitCapInt *pBigInt, const bitCapInt &value)
Definition: qrack_functions.hpp:47
void bi_add_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:58
void bi_or_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:42
#define _bi_compare(left, right)
Definition: qrack_functions.hpp:29
void bi_sub_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:59
void bi_lshift_ip(bitCapInt *left, const size_t &right)
Definition: qrack_functions.hpp:49
#define bitsInByte
Definition: qrack_types.hpp:162
#define bitLenInt
Definition: qrack_types.hpp:42
#define bitCapInt
Definition: qrack_types.hpp:66
#define bitCapIntOcl
Definition: qrack_types.hpp:54