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