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) || \
40  (defined(ENABLE_CPP_INT) && \
41  (((QBCAPPOW < 8) && defined(__SIZEOF_INT128__)) || ((QBCAPPOW > 7) && defined(BOOST_AVAILABLE))))
42 inline void bi_not_ip(bitCapInt* left) { *left = ~(*left); }
43 inline void bi_and_ip(bitCapInt* left, const bitCapInt& right) { *left &= right; }
44 inline void bi_or_ip(bitCapInt* left, const bitCapInt& right) { *left |= right; }
45 inline void bi_xor_ip(bitCapInt* left, const bitCapInt& right) { *left ^= right; }
46 inline double bi_to_double(const bitCapInt& in) { return (double)in; }
47 
48 inline void bi_increment(bitCapInt* pBigInt, const bitCapInt& value) { *pBigInt += value; }
49 inline void bi_decrement(bitCapInt* pBigInt, const bitCapInt& value) { *pBigInt -= value; }
50 
51 inline void bi_lshift_ip(bitCapInt* left, const size_t& right) { *left <<= right; }
52 inline void bi_rshift_ip(bitCapInt* left, const size_t& right) { *left >>= right; }
53 
54 inline int bi_and_1(const bitCapInt& left) { return (bool)(left & 1); }
55 
56 inline int bi_compare(const bitCapInt& left, const bitCapInt& right) { _bi_compare(left, right) }
57 inline int bi_compare_0(const bitCapInt& left) { return (int)(bool)left; }
58 inline int bi_compare_1(const bitCapInt& left) { _bi_compare(left, 1U); }
59 
60 inline void bi_add_ip(bitCapInt* left, const bitCapInt& right) { *left += right; }
61 inline void bi_sub_ip(bitCapInt* left, const bitCapInt& right) { *left -= right; }
62 
63 inline void bi_div_mod(const bitCapInt& left, const bitCapInt& right, bitCapInt* quotient, bitCapInt* rmndr)
64 {
65  if (quotient) {
66  *quotient = left / right;
67  }
68  if (rmndr) {
69  *rmndr = left % right;
70  }
71 }
72 #ifdef __SIZEOF_INT128__
73 inline void bi_div_mod_small(const bitCapInt& left, uint64_t right, bitCapInt* quotient, uint64_t* rmndr)
74 {
75  if (quotient) {
76  *quotient = left / right;
77  }
78  if (rmndr) {
79  *rmndr = (uint64_t)(left % right);
80  }
81 }
82 #else
83 inline void bi_div_mod_small(const bitCapInt& left, uint32_t right, bitCapInt* quotient, uint32_t* rmndr)
84 {
85  if (quotient) {
86  *quotient = left / right;
87  }
88  if (rmndr) {
89  *rmndr = (uint32_t)(left % right);
90  }
91 }
92 #endif
93 #endif
94 
95 namespace Qrack {
96 
98 {
99 // Source: https://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers#answer-11376759
100 #if CPP_STD >= 20
101  return std::bit_width(n) - 1U;
102 #elif ENABLE_INTRINSICS && defined(_WIN32) && !defined(__CYGWIN__)
103 #if UINTPOW < 6
104  return (bitLenInt)(bitsInByte * sizeof(unsigned int) - _lzcnt_u32((unsigned int)n) - 1U);
105 #else
106  return (bitLenInt)(bitsInByte * sizeof(unsigned long long) - _lzcnt_u64((unsigned long long)n) - 1U);
107 #endif
108 #elif ENABLE_INTRINSICS && !defined(__APPLE__)
109 #if UINTPOW < 6
110  return (bitLenInt)(bitsInByte * sizeof(unsigned int) - __builtin_clz((unsigned int)n) - 1U);
111 #else
112  return (bitLenInt)(bitsInByte * sizeof(unsigned long long) - __builtin_clzll((unsigned long long)n) - 1U);
113 #endif
114 #else
115  bitLenInt pow = 0U;
116  bitCapIntOcl p = n >> 1U;
117  while (p) {
118  p >>= 1U;
119  ++pow;
120  }
121  return pow;
122 #endif
123 }
124 
126 {
128  for (popCount = 0U; n != ZERO_BCI; ++popCount) {
129  n = n & (n - 1U);
130  }
131  return popCount;
132 }
133 
135 {
136 #if CPP_STD >= 20
137  return (bitLenInt)std::popcount(n);
138 #elif (defined(__GNUC__) || defined(__clang__)) && !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
139  return __builtin_popcount(n);
140 #else
142  for (popCount = 0U; n; ++popCount) {
143  n &= n - 1U;
144  }
145  return popCount;
146 #endif
147 }
148 
149 #if (QBCAPPOW < 7) || ((QBCAPPOW < 8) && defined(__SIZEOF_INT128__)) && defined(ENABLE_CPP_INT)
150 inline int bi_log2(const bitCapInt& n) { return log2Ocl((bitCapIntOcl)n); }
151 #elif (QBCAPPOW > 7) && defined(BOOST_AVAILABLE) && defined(ENABLE_CPP_INT)
152 inline int bi_log2(const bitCapInt& n) { return boost::multiprecision::msb(n); }
153 #endif
154 inline bitLenInt log2(bitCapInt n) { return (bitLenInt)bi_log2(n); }
155 
156 inline bitCapInt pow2(const bitLenInt& p) { return ONE_BCI << p; }
157 inline bitCapIntOcl pow2Ocl(const bitLenInt& p) { return (bitCapIntOcl)1U << p; }
158 inline bitCapInt pow2Mask(const bitLenInt& p)
159 {
160  bitCapInt toRet = ONE_BCI << p;
161  bi_decrement(&toRet, 1U);
162  return toRet;
163 }
164 inline bitCapIntOcl pow2MaskOcl(const bitLenInt& p) { return ((bitCapIntOcl)1U << p) - 1U; }
165 inline bitCapInt bitSlice(const bitLenInt& bit, const bitCapInt& source) { return (ONE_BCI << bit) & source; }
166 inline bitCapIntOcl bitSliceOcl(const bitLenInt& bit, const bitCapIntOcl& source)
167 {
168  return ((bitCapIntOcl)1U << bit) & source;
169 }
170 inline bitCapInt bitRegMask(const bitLenInt& start, const bitLenInt& length)
171 {
172  bitCapInt toRet = ONE_BCI << length;
173  bi_decrement(&toRet, 1U);
174  bi_lshift_ip(&toRet, start);
175  return toRet;
176 }
177 inline bitCapIntOcl bitRegMaskOcl(const bitLenInt& start, const bitLenInt& length)
178 {
179  return (((bitCapIntOcl)1U << length) - 1U) << start;
180 }
181 // Source: https://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/
182 inline bool isPowerOfTwo(const bitCapInt& x)
183 {
184  bitCapInt y = x;
185  bi_decrement(&y, 1U);
186  bi_and_ip(&y, x);
187  return (bi_compare_0(x) != 0) && (bi_compare_0(y) == 0);
188 }
189 inline bool isPowerOfTwoOcl(const bitCapIntOcl& x) { return x && !(x & (x - 1U)); }
190 inline bool isBadBitRange(const bitLenInt& start, const bitLenInt& length, const bitLenInt& qubitCount)
191 {
192  return ((start + length) > qubitCount) || ((bitLenInt)(start + length) < start);
193 }
194 inline bool isBadPermRange(const bitCapIntOcl& start, const bitCapIntOcl& length, const bitCapIntOcl& maxQPowerOcl)
195 {
196  return ((start + length) > maxQPowerOcl) || ((bitCapIntOcl)(start + length) < start);
197 }
199  const std::vector<bitLenInt>& controls, const bitLenInt& qubitCount, std::string message)
200 {
201  std::set<bitLenInt> dupes;
202  for (const bitLenInt& control : controls) {
203  if (control >= qubitCount) {
204  throw std::invalid_argument(message);
205  }
206 
207  if (dupes.find(control) == dupes.end()) {
208  dupes.insert(control);
209  } else {
210  throw std::invalid_argument(message + " (Found duplicate qubit indices!)");
211  }
212  }
213 }
214 
215 // These are utility functions defined in qinterface/protected.cpp:
216 unsigned char* cl_alloc(size_t ucharCount);
217 void cl_free(void* toFree);
218 void mul2x2(const complex left[4U], const complex right[4U], complex out[4U]);
219 void exp2x2(const complex m[4U], complex o[4U]);
220 void log2x2(const complex m[4U], complex o[4U]);
221 void inv2x2(const complex m[4U], complex o[4U]);
222 bool isOverflowAdd(bitCapInt inOutInt, bitCapInt inInt, const bitCapInt& signMask, const bitCapInt& lengthPower);
223 bool isOverflowSub(bitCapInt inOutInt, bitCapInt inInt, const bitCapInt& signMask, const bitCapInt& lengthPower);
224 bitCapInt pushApartBits(const bitCapInt& perm, const std::vector<bitCapInt>& skipPowers);
225 bitCapInt intPow(const bitCapInt& base, const bitCapInt& power);
227 
228 #if QBCAPPOW > 6
229 std::ostream& operator<<(std::ostream& os, const bitCapInt& b);
230 std::istream& operator>>(std::istream& is, bitCapInt& b);
231 #endif
232 
233 #if ENABLE_ENV_VARS
234 const real1_f _qrack_qunit_sep_thresh = getenv("QRACK_QUNIT_SEPARABILITY_THRESHOLD")
235  ? (real1_f)std::stof(std::string(getenv("QRACK_QUNIT_SEPARABILITY_THRESHOLD")))
236  : FP_NORM_EPSILON;
237 const real1_f _qrack_qbdt_sep_thresh = getenv("QRACK_QBDT_SEPARABILITY_THRESHOLD")
238  ? (real1_f)std::stof(std::string(getenv("QRACK_QBDT_SEPARABILITY_THRESHOLD")))
239  : FP_NORM_EPSILON;
241  getenv("QRACK_MAX_CPU_QB") ? (bitLenInt)std::stoi(std::string(getenv("QRACK_MAX_CPU_QB"))) : -1;
242 const bitLenInt QRACK_MAX_PAGE_QB_DEFAULT = getenv("QRACK_MAX_PAGE_QB")
243  ? (bitLenInt)std::stoi(std::string(getenv("QRACK_MAX_PAGE_QB")))
245 const bitLenInt QRACK_MAX_PAGING_QB_DEFAULT = getenv("QRACK_MAX_PAGING_QB")
246  ? (bitLenInt)std::stoi(std::string(getenv("QRACK_MAX_PAGING_QB")))
249  (bitLenInt)(getenv("QRACK_PSTRIDEPOW") ? std::stoi(std::string(getenv("QRACK_PSTRIDEPOW"))) : PSTRIDEPOW);
250 const size_t QRACK_QBDT_MAX_ALLOC_MB_DEFAULT =
251  (size_t)(getenv("QRACK_QBDT_MAX_ALLOC_MB") ? std::stoi(std::string(getenv("QRACK_QBDT_MAX_ALLOC_MB"))) : -1);
253  (size_t)(getenv("QRACK_SPARSE_MAX_ALLOC_MB") ? std::stoi(std::string(getenv("QRACK_SPARSE_MAX_ALLOC_MB"))) : -1);
254 const real1_f _qrack_sparse_thresh = getenv("QRACK_SPARSE_TRUNCATION_THRESHOLD")
255  ? (real1_f)std::stof(std::string(getenv("QRACK_SPARSE_TRUNCATION_THRESHOLD")))
256  : REAL1_EPSILON;
257 #else
263 const bitLenInt PSTRIDEPOW_DEFAULT = PSTRIDEPOW;
267 #endif
271 } // 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:198
bitCapInt bitRegMask(const bitLenInt &start, const bitLenInt &length)
Definition: qrack_functions.hpp:170
bool isOverflowSub(bitCapInt inOutInt, bitCapInt inInt, const bitCapInt &signMask, const bitCapInt &lengthPower)
Check if a subtraction with overflow sets the flag.
Definition: functions.cpp:236
void cl_free(void *toFree)
Definition: functions.cpp:49
bool isPowerOfTwo(const bitCapInt &x)
Definition: qrack_functions.hpp:182
const real1_f _qrack_qunit_sep_thresh
Definition: qrack_functions.hpp:258
const bitLenInt QRACK_MAX_PAGING_QB_DEFAULT
Definition: qrack_functions.hpp:262
int bi_log2(const bitCapInt &n)
Definition: qrack_functions.hpp:150
unsigned char * cl_alloc(size_t ucharCount)
Definition: functions.cpp:27
void inv2x2(const complex m[4U], complex o[4U])
bitLenInt log2Ocl(bitCapIntOcl n)
Definition: qrack_functions.hpp:97
const size_t QRACK_SPARSE_MAX_KEYS
Definition: qrack_functions.hpp:270
const size_t QRACK_QBDT_MAX_ALLOC_BYTES_DEFAULT
Definition: qrack_functions.hpp:268
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:140
const real1_f _qrack_qbdt_sep_thresh
Definition: qrack_functions.hpp:259
const bitLenInt PSTRIDEPOW_DEFAULT
Definition: qrack_functions.hpp:263
void mul2x2(const complex left[4U], const complex right[4U], complex out[4U])
const real1_f _qrack_sparse_thresh
Definition: qrack_functions.hpp:266
const bitLenInt QRACK_MAX_PAGE_QB_DEFAULT
Definition: qrack_functions.hpp:261
QRACK_CONST real1 FP_NORM_EPSILON
Definition: qrack_types.hpp:263
const bitLenInt QRACK_MAX_CPU_QB_DEFAULT
Definition: qrack_functions.hpp:260
void exp2x2(const complex m[4U], complex o[4U])
bitCapInt pushApartBits(const bitCapInt &perm, const std::vector< bitCapInt > &skipPowers)
Definition: functions.cpp:258
bitCapInt pow2(const bitLenInt &p)
Definition: qrack_functions.hpp:156
constexpr size_t SPARSE_KEY_BYTES
Definition: qrack_types.hpp:255
bitCapIntOcl bitRegMaskOcl(const bitLenInt &start, const bitLenInt &length)
Definition: qrack_functions.hpp:177
QRACK_CONST real1 REAL1_EPSILON
Definition: qrack_types.hpp:203
bitCapInt bitSlice(const bitLenInt &bit, const bitCapInt &source)
Definition: qrack_functions.hpp:165
bitLenInt popCountOcl(bitCapIntOcl n)
Definition: qrack_functions.hpp:134
bitCapInt pow2Mask(const bitLenInt &p)
Definition: qrack_functions.hpp:158
float real1_f
Definition: qrack_types.hpp:107
bool isOverflowAdd(bitCapInt inOutInt, bitCapInt inInt, const bitCapInt &signMask, const bitCapInt &lengthPower)
Check if an addition with overflow sets the flag.
Definition: functions.cpp:214
bitCapIntOcl intPowOcl(bitCapIntOcl base, bitCapIntOcl power)
Definition: functions.cpp:77
bool isPowerOfTwoOcl(const bitCapIntOcl &x)
Definition: qrack_functions.hpp:189
bitLenInt popCount(bitCapInt n)
Definition: qrack_functions.hpp:125
const size_t QRACK_SPARSE_MAX_ALLOC_MB_DEFAULT
Definition: qrack_functions.hpp:265
void log2x2(const complex m[4U], complex o[4U])
const size_t QRACK_SPARSE_MAX_ALLOC_BYTES_DEFAULT
Definition: qrack_functions.hpp:269
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:264
bitCapIntOcl pow2MaskOcl(const bitLenInt &p)
Definition: qrack_functions.hpp:164
bool isBadPermRange(const bitCapIntOcl &start, const bitCapIntOcl &length, const bitCapIntOcl &maxQPowerOcl)
Definition: qrack_functions.hpp:194
const bitCapInt ONE_BCI
Definition: qrack_types.hpp:141
const bitCapInt ZERO_BCI
Definition: qrack_types.hpp:142
bool isBadBitRange(const bitLenInt &start, const bitLenInt &length, const bitLenInt &qubitCount)
Definition: qrack_functions.hpp:190
bitCapIntOcl pow2Ocl(const bitLenInt &p)
Definition: qrack_functions.hpp:157
bitCapIntOcl bitSliceOcl(const bitLenInt &bit, const bitCapIntOcl &source)
Definition: qrack_functions.hpp:166
bitLenInt log2(bitCapInt n)
Definition: qrack_functions.hpp:154
half pow(half x, half y)
Power function.
Definition: half.hpp:3721
void bi_and_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:43
int bi_compare_1(const bitCapInt &left)
Definition: qrack_functions.hpp:58
int bi_and_1(const bitCapInt &left)
Definition: qrack_functions.hpp:54
void bi_xor_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:45
void bi_not_ip(bitCapInt *left)
Definition: qrack_functions.hpp:42
int bi_compare_0(const bitCapInt &left)
Definition: qrack_functions.hpp:57
int bi_compare(const bitCapInt &left, const bitCapInt &right)
Definition: qrack_functions.hpp:56
void bi_increment(bitCapInt *pBigInt, const bitCapInt &value)
Definition: qrack_functions.hpp:48
void bi_div_mod_small(const bitCapInt &left, uint32_t right, bitCapInt *quotient, uint32_t *rmndr)
Definition: qrack_functions.hpp:83
double bi_to_double(const bitCapInt &in)
Definition: qrack_functions.hpp:46
void bi_div_mod(const bitCapInt &left, const bitCapInt &right, bitCapInt *quotient, bitCapInt *rmndr)
Definition: qrack_functions.hpp:63
void bi_rshift_ip(bitCapInt *left, const size_t &right)
Definition: qrack_functions.hpp:52
void bi_decrement(bitCapInt *pBigInt, const bitCapInt &value)
Definition: qrack_functions.hpp:49
void bi_add_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:60
void bi_or_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:44
#define _bi_compare(left, right)
Definition: qrack_functions.hpp:29
void bi_sub_ip(bitCapInt *left, const bitCapInt &right)
Definition: qrack_functions.hpp:61
void bi_lshift_ip(bitCapInt *left, const size_t &right)
Definition: qrack_functions.hpp:51
#define bitsInByte
Definition: qrack_types.hpp:156
#define bitLenInt
Definition: qrack_types.hpp:41
#define bitCapInt
Definition: qrack_types.hpp:65
#define bitCapIntOcl
Definition: qrack_types.hpp:53