Qrack  9.0
General classical-emulating-quantum development framework
statevector.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 header defines buffers for Qrack::QFusion.
6 // QFusion adds an optional "gate fusion" layer on top of a QEngine or QUnit.
7 // Single bit gates are buffered in per-bit 2x2 complex matrices, to reduce the cost
8 // of successive application of single bit gates to the same bit.
9 //
10 // Licensed under the GNU Lesser General Public License V3.
11 // See LICENSE.md in the project root or https://www.gnu.org/licenses/lgpl-3.0.en.html
12 // for details.
13 
14 #pragma once
15 
16 #include "common/parallel_for.hpp"
17 
18 #include <algorithm>
19 #include <mutex>
20 
21 #if ENABLE_PTHREAD
22 #include <future>
23 #endif
24 
25 #if QBCAPPOW > 7
26 #include <boost/functional/hash.hpp>
27 #endif
28 #include <unordered_map>
29 #define SparseStateVecMap std::unordered_map<bitCapIntOcl, complex>
30 
31 #if ENABLE_COMPLEX_X2
32 #if FPPOW == 5
34 #elif FPPOW == 6
36 #endif
37 #endif
38 
39 namespace Qrack {
40 
41 class StateVectorArray;
42 class StateVectorSparse;
43 
44 // This is a buffer struct that's capable of representing controlled single bit gates and arithmetic, when subclassed.
45 class StateVector {
46 protected:
48 
49 public:
51 
53  : capacity(cap)
54  , isReadLocked(true)
55  {
56  }
57  virtual ~StateVector()
58  {
59  // Intentionally left blank.
60  }
61 
62  virtual complex read(const bitCapIntOcl& i) = 0;
63 #if ENABLE_COMPLEX_X2
64  virtual complex2 read2(const bitCapIntOcl& i1, const bitCapIntOcl& i2) = 0;
65 #endif
66  virtual void write(const bitCapIntOcl& i, const complex& c) = 0;
69  virtual void write2(const bitCapIntOcl& i1, const complex& c1, const bitCapIntOcl& i2, const complex& c2) = 0;
70  virtual void clear() = 0;
71  virtual void copy_in(complex const* inArray) = 0;
72  virtual void copy_in(complex const* copyIn, const bitCapIntOcl offset, const bitCapIntOcl length) = 0;
73  virtual void copy_in(StateVectorPtr copyInSv, const bitCapIntOcl srcOffset, const bitCapIntOcl dstOffset,
74  const bitCapIntOcl length) = 0;
75  virtual void copy_out(complex* outArray) = 0;
76  virtual void copy_out(complex* copyIn, const bitCapIntOcl offset, const bitCapIntOcl length) = 0;
77  virtual void copy(StateVectorPtr toCopy) = 0;
78  virtual void shuffle(StateVectorPtr svp) = 0;
79  virtual void get_probs(real1* outArray) = 0;
80  virtual bool is_sparse() = 0;
81 };
82 
83 class StateVectorArray : public StateVector {
84 public:
85  std::unique_ptr<complex[], void (*)(complex*)> amplitudes;
86 
87 protected:
88  static real1_f normHelper(const complex& c) { return (real1_f)norm(c); }
89 
90 #if defined(__APPLE__)
91  complex* _aligned_state_vec_alloc(bitCapIntOcl allocSize)
92  {
93  void* toRet;
94  posix_memalign(&toRet, QRACK_ALIGN_SIZE, allocSize);
95  return (complex*)toRet;
96  }
97 #endif
98 
99  std::unique_ptr<complex[], void (*)(complex*)> Alloc(bitCapIntOcl elemCount)
100  {
101 #if defined(__ANDROID__)
102  return std::unique_ptr<complex[], void (*)(complex*)>(new complex[elemCount], [](complex* c) { delete c; });
103 #else
104  // elemCount is always a power of two, but might be smaller than QRACK_ALIGN_SIZE
105  size_t allocSize = sizeof(complex) * elemCount;
106  if (allocSize < QRACK_ALIGN_SIZE) {
107  allocSize = QRACK_ALIGN_SIZE;
108  }
109 #if defined(__APPLE__)
110  return std::unique_ptr<complex[], void (*)(complex*)>(
111  _aligned_state_vec_alloc(allocSize), [](complex* c) { free(c); });
112 #elif defined(_WIN32) && !defined(__CYGWIN__)
113  return std::unique_ptr<complex[], void (*)(complex*)>(
114  (complex*)_aligned_malloc(allocSize, QRACK_ALIGN_SIZE), [](complex* c) { _aligned_free(c); });
115 #else
116  return std::unique_ptr<complex[], void (*)(complex*)>(
117  (complex*)aligned_alloc(QRACK_ALIGN_SIZE, allocSize), [](complex* c) { free(c); });
118 #endif
119 #endif
120  }
121 
122  virtual void Free() { amplitudes = NULL; }
123 
124 public:
126  : StateVector(cap)
128  {
129  // Intentionally left blank.
130  }
131 
132  virtual ~StateVectorArray() { Free(); }
133 
134  complex read(const bitCapIntOcl& i) { return amplitudes.get()[i]; };
135 
136 #if ENABLE_COMPLEX_X2
137  complex2 read2(const bitCapIntOcl& i1, const bitCapIntOcl& i2)
138  {
139  return complex2(amplitudes.get()[i1], amplitudes.get()[i2]);
140  }
141 #endif
142 
143  void write(const bitCapIntOcl& i, const complex& c) { amplitudes.get()[i] = c; };
144 
145  void write2(const bitCapIntOcl& i1, const complex& c1, const bitCapIntOcl& i2, const complex& c2)
146  {
147  amplitudes.get()[i1] = c1;
148  amplitudes.get()[i2] = c2;
149  };
150 
151  void clear() { std::fill(amplitudes.get(), amplitudes.get() + (bitCapIntOcl)capacity, ZERO_CMPLX); }
152 
153  void copy_in(complex const* copyIn)
154  {
155  if (copyIn) {
156  std::copy(copyIn, copyIn + (bitCapIntOcl)capacity, amplitudes.get());
157  } else {
158  std::fill(amplitudes.get(), amplitudes.get() + (bitCapIntOcl)capacity, ZERO_CMPLX);
159  }
160  }
161 
162  void copy_in(complex const* copyIn, const bitCapIntOcl offset, const bitCapIntOcl length)
163  {
164  if (copyIn) {
165  std::copy(copyIn, copyIn + length, amplitudes.get() + offset);
166  } else {
167  std::fill(amplitudes.get(), amplitudes.get() + length, ZERO_CMPLX);
168  }
169  }
170 
171  void copy_in(
172  StateVectorPtr copyInSv, const bitCapIntOcl srcOffset, const bitCapIntOcl dstOffset, const bitCapIntOcl length)
173  {
174  if (copyInSv) {
175  complex const* copyIn = std::dynamic_pointer_cast<StateVectorArray>(copyInSv)->amplitudes.get() + srcOffset;
176  std::copy(copyIn, copyIn + length, amplitudes.get() + dstOffset);
177  } else {
178  std::fill(amplitudes.get() + dstOffset, amplitudes.get() + dstOffset + length, ZERO_CMPLX);
179  }
180  }
181 
182  void copy_out(complex* copyOut) { std::copy(amplitudes.get(), amplitudes.get() + capacity, copyOut); }
183 
184  void copy_out(complex* copyOut, const bitCapIntOcl offset, const bitCapIntOcl length)
185  {
186  std::copy(amplitudes.get() + offset, amplitudes.get() + offset + capacity, copyOut);
187  }
188 
189  void copy(StateVectorPtr toCopy) { copy(std::dynamic_pointer_cast<StateVectorArray>(toCopy)); }
190 
192  {
193  std::copy(toCopy->amplitudes.get(), toCopy->amplitudes.get() + capacity, amplitudes.get());
194  }
195 
196  void shuffle(StateVectorPtr svp) { shuffle(std::dynamic_pointer_cast<StateVectorArray>(svp)); }
197 
199  {
200  std::swap_ranges(amplitudes.get() + (capacity >> ONE_BCI), amplitudes.get() + capacity, svp->amplitudes.get());
201  }
202 
203  void get_probs(real1* outArray)
204  {
205  std::transform(amplitudes.get(), amplitudes.get() + capacity, outArray, normHelper);
206  }
207 
208  bool is_sparse() { return false; }
209 };
210 
211 class StateVectorSparse : public StateVector, public ParallelFor {
212 protected:
214  std::mutex mtx;
215 
217  {
218  auto it = amplitudes.find(i);
219  return (it == amplitudes.end()) ? ZERO_CMPLX : it->second;
220  }
221 
223  {
224  std::lock_guard<std::mutex> lock(mtx);
225  return readUnlocked(i);
226  }
227 
228 public:
230  : StateVector(cap)
231  , amplitudes()
232  {
233  }
234 
236 
237 #if ENABLE_COMPLEX_X2
238  complex2 read2(const bitCapIntOcl& i1, const bitCapIntOcl& i2)
239  {
240  if (isReadLocked) {
241  return complex2(readLocked(i1), readLocked(i2));
242  }
243  return complex2(readUnlocked(i1), readUnlocked(i2));
244  }
245 #endif
246 
247  void write(const bitCapIntOcl& i, const complex& c)
248  {
249  const bool isCSet = abs(c) > REAL1_EPSILON;
250  ;
251  bool isFound;
252  SparseStateVecMap::iterator it;
253 
254  // For lock_guard scope
255  if (true) {
256  std::lock_guard<std::mutex> lock(mtx);
257 
258  it = amplitudes.find(i);
259  isFound = (it != amplitudes.end());
260  if (isCSet != isFound) {
261  if (isCSet) {
262  amplitudes[i] = c;
263  } else {
264  amplitudes.erase(it);
265  }
266  }
267  }
268 
269  if (isCSet == isFound) {
270  if (isCSet) {
271  it->second = c;
272  }
273  }
274  }
275 
276  void write2(const bitCapIntOcl& i1, const complex& c1, const bitCapIntOcl& i2, const complex& c2)
277  {
278  const bool isC1Set = abs(c1) > REAL1_EPSILON;
279  const bool isC2Set = abs(c2) > REAL1_EPSILON;
280  if (!isC1Set && !isC2Set) {
281  std::lock_guard<std::mutex> lock(mtx);
282  amplitudes.erase(i1);
283  amplitudes.erase(i2);
284  } else if (isC1Set && isC2Set) {
285  std::lock_guard<std::mutex> lock(mtx);
286  amplitudes[i1] = c1;
287  amplitudes[i2] = c2;
288  } else if (isC1Set) {
289  std::lock_guard<std::mutex> lock(mtx);
290  amplitudes.erase(i2);
291  amplitudes[i1] = c1;
292  } else {
293  std::lock_guard<std::mutex> lock(mtx);
294  amplitudes.erase(i1);
295  amplitudes[i2] = c2;
296  }
297  }
298 
299  void clear()
300  {
301  std::lock_guard<std::mutex> lock(mtx);
302  amplitudes.clear();
303  }
304 
305  void copy_in(complex const* copyIn)
306  {
307  if (!copyIn) {
308  clear();
309  return;
310  }
311 
312  std::lock_guard<std::mutex> lock(mtx);
313  for (bitCapIntOcl i = 0U; i < capacity; ++i) {
314  if (abs(copyIn[i]) <= REAL1_EPSILON) {
315  amplitudes.erase(i);
316  } else {
317  amplitudes[i] = copyIn[i];
318  }
319  }
320  }
321 
322  void copy_in(complex const* copyIn, const bitCapIntOcl offset, const bitCapIntOcl length)
323  {
324  if (!copyIn) {
325  std::lock_guard<std::mutex> lock(mtx);
326  for (bitCapIntOcl i = 0U; i < length; ++i) {
327  amplitudes.erase(i);
328  }
329 
330  return;
331  }
332 
333  std::lock_guard<std::mutex> lock(mtx);
334  for (bitCapIntOcl i = 0U; i < length; ++i) {
335  if (abs(copyIn[i]) <= REAL1_EPSILON) {
336  amplitudes.erase(i);
337  } else {
338  amplitudes[i + offset] = copyIn[i];
339  }
340  }
341  }
342 
343  void copy_in(
344  StateVectorPtr copyInSv, const bitCapIntOcl srcOffset, const bitCapIntOcl dstOffset, const bitCapIntOcl length)
345  {
346  StateVectorSparsePtr copyIn = std::dynamic_pointer_cast<StateVectorSparse>(copyInSv);
347 
348  if (!copyIn) {
349  std::lock_guard<std::mutex> lock(mtx);
350  for (bitCapIntOcl i = 0U; i < length; ++i) {
351  amplitudes.erase(i + srcOffset);
352  }
353 
354  return;
355  }
356 
357  std::lock_guard<std::mutex> lock(mtx);
358  for (bitCapIntOcl i = 0U; i < length; ++i) {
359  complex amp = copyIn->read(i + srcOffset);
360  if (abs(amp) <= REAL1_EPSILON) {
361  amplitudes.erase(i + srcOffset);
362  } else {
363  amplitudes[i + dstOffset] = amp;
364  }
365  }
366  }
367 
368  void copy_out(complex* copyOut)
369  {
370  for (bitCapIntOcl i = 0U; i < capacity; ++i) {
371  copyOut[i] = read(i);
372  }
373  }
374 
375  void copy_out(complex* copyOut, const bitCapIntOcl offset, const bitCapIntOcl length)
376  {
377  for (bitCapIntOcl i = 0U; i < length; ++i) {
378  copyOut[i] = read(i + offset);
379  }
380  }
381 
382  void copy(const StateVectorPtr toCopy) { copy(std::dynamic_pointer_cast<StateVectorSparse>(toCopy)); }
383 
385  {
386  std::lock_guard<std::mutex> lock(mtx);
387  amplitudes = toCopy->amplitudes;
388  }
389 
390  void shuffle(StateVectorPtr svp) { shuffle(std::dynamic_pointer_cast<StateVectorSparse>(svp)); }
391 
393  {
394  const size_t halfCap = (size_t)(capacity >> ONE_BCI);
395  std::lock_guard<std::mutex> lock(mtx);
396  for (bitCapIntOcl i = 0U; i < halfCap; ++i) {
397  complex amp = svp->read(i);
398  svp->write(i, read(i + halfCap));
399  write(i + halfCap, amp);
400  }
401  }
402 
403  void get_probs(real1* outArray)
404  {
405  for (bitCapIntOcl i = 0U; i < capacity; ++i) {
406  outArray[i] = norm(read(i));
407  }
408  }
409 
410  bool is_sparse() { return (amplitudes.size() < (size_t)(capacity >> ONE_BCI)); }
411 
412  std::vector<bitCapIntOcl> iterable()
413  {
414  std::vector<std::vector<bitCapIntOcl>> toRet(GetConcurrencyLevel());
415  std::vector<std::vector<bitCapIntOcl>>::iterator toRetIt;
416 
417  // For lock_guard scope
418  if (true) {
419  std::lock_guard<std::mutex> lock(mtx);
420 
421  par_for(0U, amplitudes.size(), [&](const bitCapIntOcl& lcv, const unsigned& cpu) {
422  auto it = amplitudes.begin();
423  std::advance(it, lcv);
424  toRet[cpu].push_back(it->first);
425  });
426  }
427 
428  for (int64_t i = (int64_t)(toRet.size() - 1U); i >= 0; i--) {
429  if (!toRet[i].size()) {
430  toRetIt = toRet.begin();
431  std::advance(toRetIt, i);
432  toRet.erase(toRetIt);
433  }
434  }
435 
436  if (!toRet.size()) {
437  return {};
438  }
439 
440  while (toRet.size() > 1U) {
441  // Work odd unit into collapse sequence:
442  if (toRet.size() & 1U) {
443  toRet[toRet.size() - 2U].insert(
444  toRet[toRet.size() - 2U].end(), toRet[toRet.size() - 1U].begin(), toRet[toRet.size() - 1U].end());
445  toRet.pop_back();
446  }
447 
448  const int64_t combineCount = (int64_t)(toRet.size() >> 1U);
449 #if ENABLE_PTHREAD
450  std::vector<std::future<void>> futures(combineCount);
451  for (int64_t i = (combineCount - 1); i >= 0; i--) {
452  futures[i] = std::async(std::launch::async, [i, combineCount, &toRet]() {
453  toRet[i].insert(toRet[i].end(), toRet[i + combineCount].begin(), toRet[i + combineCount].end());
454  toRet[i + combineCount].clear();
455  });
456  }
457  for (int64_t i = (combineCount - 1); i >= 0; i--) {
458  futures[i].get();
459  toRet.pop_back();
460  }
461 #else
462  for (int64_t i = (combineCount - 1); i >= 0; i--) {
463  toRet[i].insert(toRet[i].end(), toRet[i + combineCount].begin(), toRet[i + combineCount].end());
464  toRet.pop_back();
465  }
466 #endif
467  }
468 
469  return toRet[0U];
470  }
471 
473  std::set<bitCapIntOcl> iterable(
474  const bitCapIntOcl& setMask, const bitCapIntOcl& filterMask = 0, const bitCapIntOcl& filterValues = 0)
475  {
476  if (!filterMask && filterValues) {
477  return {};
478  }
479 
480  const bitCapIntOcl unsetMask = ~setMask;
481 
482  std::vector<std::set<bitCapIntOcl>> toRet(GetConcurrencyLevel());
483  std::vector<std::set<bitCapIntOcl>>::iterator toRetIt;
484 
485  // For lock_guard scope
486  if (true) {
487  std::lock_guard<std::mutex> lock(mtx);
488 
489  if (!filterMask && !filterValues) {
490  par_for(0U, amplitudes.size(), [&](const bitCapIntOcl& lcv, const unsigned& cpu) {
491  auto it = amplitudes.begin();
492  std::advance(it, lcv);
493  toRet[cpu].insert(it->first & unsetMask);
494  });
495  } else {
496  const bitCapIntOcl unfilterMask = ~filterMask;
497  par_for(0U, amplitudes.size(), [&](const bitCapIntOcl lcv, const unsigned& cpu) {
498  auto it = amplitudes.begin();
499  std::advance(it, lcv);
500  if ((it->first & filterMask) == filterValues) {
501  toRet[cpu].insert(it->first & unsetMask & unfilterMask);
502  }
503  });
504  }
505  }
506 
507  for (int64_t i = (int64_t)(toRet.size() - 1U); i >= 0; i--) {
508  if (!toRet[i].size()) {
509  toRetIt = toRet.begin();
510  std::advance(toRetIt, i);
511  toRet.erase(toRetIt);
512  }
513  }
514 
515  if (!toRet.size()) {
516  return {};
517  }
518 
519  while (toRet.size() > 1U) {
520  // Work odd unit into collapse sequence:
521  if (toRet.size() & 1U) {
522  toRet[toRet.size() - 2U].insert(toRet[toRet.size() - 1U].begin(), toRet[toRet.size() - 1U].end());
523  toRet.pop_back();
524  }
525 
526  const int64_t combineCount = (int64_t)(toRet.size() >> 1U);
527 #if ENABLE_PTHREAD
528  std::vector<std::future<void>> futures(combineCount);
529  for (int64_t i = (combineCount - 1); i >= 0; i--) {
530  futures[i] = std::async(std::launch::async, [i, combineCount, &toRet]() {
531  toRet[i].insert(toRet[i + combineCount].begin(), toRet[i + combineCount].end());
532  toRet[i + combineCount].clear();
533  });
534  }
535 
536  for (int64_t i = (combineCount - 1); i >= 0; i--) {
537  futures[i].get();
538  toRet.pop_back();
539  }
540 #else
541  for (int64_t i = (combineCount - 1); i >= 0; i--) {
542  toRet[i].insert(toRet[i + combineCount].begin(), toRet[i + combineCount].end());
543  toRet.pop_back();
544  }
545 #endif
546  }
547 
548  return toRet[0U];
549  }
550 };
551 
552 } // namespace Qrack
Definition: parallel_for.hpp:19
unsigned GetConcurrencyLevel()
Definition: parallel_for.hpp:38
void par_for(const bitCapIntOcl begin, const bitCapIntOcl end, ParallelFunc fn)
Call fn once for every numerical value between begin and end.
Definition: parallel_for.cpp:51
Definition: statevector.hpp:83
std::unique_ptr< complex[], void(*)(complex *)> Alloc(bitCapIntOcl elemCount)
Definition: statevector.hpp:99
void copy(StateVectorArrayPtr toCopy)
Definition: statevector.hpp:191
virtual ~StateVectorArray()
Definition: statevector.hpp:132
std::unique_ptr< complex[], void(*)(complex *)> amplitudes
Definition: statevector.hpp:85
complex read(const bitCapIntOcl &i)
Definition: statevector.hpp:134
void write(const bitCapIntOcl &i, const complex &c)
Definition: statevector.hpp:143
void copy_out(complex *copyOut, const bitCapIntOcl offset, const bitCapIntOcl length)
Definition: statevector.hpp:184
static real1_f normHelper(const complex &c)
Definition: statevector.hpp:88
void clear()
Definition: statevector.hpp:151
virtual void Free()
Definition: statevector.hpp:122
void copy_in(StateVectorPtr copyInSv, const bitCapIntOcl srcOffset, const bitCapIntOcl dstOffset, const bitCapIntOcl length)
Definition: statevector.hpp:171
void get_probs(real1 *outArray)
Definition: statevector.hpp:203
void write2(const bitCapIntOcl &i1, const complex &c1, const bitCapIntOcl &i2, const complex &c2)
Optimized "write" that is only guaranteed to write if either amplitude is nonzero.
Definition: statevector.hpp:145
void copy_out(complex *copyOut)
Definition: statevector.hpp:182
void shuffle(StateVectorArrayPtr svp)
Definition: statevector.hpp:198
void shuffle(StateVectorPtr svp)
Definition: statevector.hpp:196
bool is_sparse()
Definition: statevector.hpp:208
void copy(StateVectorPtr toCopy)
Definition: statevector.hpp:189
void copy_in(complex const *copyIn)
Definition: statevector.hpp:153
void copy_in(complex const *copyIn, const bitCapIntOcl offset, const bitCapIntOcl length)
Definition: statevector.hpp:162
StateVectorArray(bitCapIntOcl cap)
Definition: statevector.hpp:125
Definition: statevector.hpp:211
void get_probs(real1 *outArray)
Definition: statevector.hpp:403
void shuffle(StateVectorPtr svp)
Definition: statevector.hpp:390
complex readLocked(const bitCapIntOcl &i)
Definition: statevector.hpp:222
std::set< bitCapIntOcl > iterable(const bitCapIntOcl &setMask, const bitCapIntOcl &filterMask=0, const bitCapIntOcl &filterValues=0)
Returns empty if iteration should be over full set, otherwise just the iterable elements:
Definition: statevector.hpp:473
std::vector< bitCapIntOcl > iterable()
Definition: statevector.hpp:412
void copy_out(complex *copyOut)
Definition: statevector.hpp:368
void write2(const bitCapIntOcl &i1, const complex &c1, const bitCapIntOcl &i2, const complex &c2)
Optimized "write" that is only guaranteed to write if either amplitude is nonzero.
Definition: statevector.hpp:276
void copy_out(complex *copyOut, const bitCapIntOcl offset, const bitCapIntOcl length)
Definition: statevector.hpp:375
void write(const bitCapIntOcl &i, const complex &c)
Definition: statevector.hpp:247
std::mutex mtx
Definition: statevector.hpp:214
void copy_in(complex const *copyIn)
Definition: statevector.hpp:305
SparseStateVecMap amplitudes
Definition: statevector.hpp:213
StateVectorSparse(bitCapIntOcl cap)
Definition: statevector.hpp:229
complex read(const bitCapIntOcl &i)
Definition: statevector.hpp:235
complex readUnlocked(const bitCapIntOcl &i)
Definition: statevector.hpp:216
void copy_in(StateVectorPtr copyInSv, const bitCapIntOcl srcOffset, const bitCapIntOcl dstOffset, const bitCapIntOcl length)
Definition: statevector.hpp:343
void copy_in(complex const *copyIn, const bitCapIntOcl offset, const bitCapIntOcl length)
Definition: statevector.hpp:322
void copy(StateVectorSparsePtr toCopy)
Definition: statevector.hpp:384
void clear()
Definition: statevector.hpp:299
bool is_sparse()
Definition: statevector.hpp:410
void shuffle(StateVectorSparsePtr svp)
Definition: statevector.hpp:392
void copy(const StateVectorPtr toCopy)
Definition: statevector.hpp:382
Definition: statevector.hpp:45
bitCapIntOcl capacity
Definition: statevector.hpp:47
virtual void get_probs(real1 *outArray)=0
virtual void shuffle(StateVectorPtr svp)=0
virtual complex read(const bitCapIntOcl &i)=0
virtual void write(const bitCapIntOcl &i, const complex &c)=0
virtual void copy_out(complex *outArray)=0
virtual void copy_in(complex const *copyIn, const bitCapIntOcl offset, const bitCapIntOcl length)=0
virtual void copy_in(complex const *inArray)=0
virtual void copy_out(complex *copyIn, const bitCapIntOcl offset, const bitCapIntOcl length)=0
virtual void write2(const bitCapIntOcl &i1, const complex &c1, const bitCapIntOcl &i2, const complex &c2)=0
Optimized "write" that is only guaranteed to write if either amplitude is nonzero.
virtual void copy(StateVectorPtr toCopy)=0
virtual void clear()=0
StateVector(bitCapIntOcl cap)
Definition: statevector.hpp:52
bool isReadLocked
Definition: statevector.hpp:50
virtual void copy_in(StateVectorPtr copyInSv, const bitCapIntOcl srcOffset, const bitCapIntOcl dstOffset, const bitCapIntOcl length)=0
virtual ~StateVector()
Definition: statevector.hpp:57
virtual bool is_sparse()=0
Half-precision floating-point type.
Definition: half.hpp:2222
Definition: complex16x2simd.hpp:25
constexpr uint8_t ONE_BCI
Definition: qrack_types.hpp:90
std::complex< half_float::half > complex
Definition: qrack_types.hpp:62
std::shared_ptr< StateVectorSparse > StateVectorSparsePtr
Definition: qrack_types.hpp:137
double norm(const complex2 &c)
Definition: complex16x2simd.hpp:101
float real1_f
Definition: qrack_types.hpp:64
std::shared_ptr< StateVectorArray > StateVectorArrayPtr
Definition: qrack_types.hpp:136
std::shared_ptr< StateVector > StateVectorPtr
Definition: qrack_types.hpp:133
const real1 REAL1_EPSILON
Definition: qrack_types.hpp:157
QRACK_CONST complex ZERO_CMPLX
Definition: qrack_types.hpp:240
HALF_CONSTEXPR half abs(half arg)
Absolute value.
Definition: half.hpp:2975
MICROSOFT_QUANTUM_DECL void U(_In_ uintq sid, _In_ uintq q, _In_ double theta, _In_ double phi, _In_ double lambda)
(External API) 3-parameter unitary gate
Definition: pinvoke_api.cpp:1362
#define bitCapIntOcl
Definition: qrack_types.hpp:91
#define QRACK_ALIGN_SIZE
Definition: qrack_types.hpp:147
#define SparseStateVecMap
Definition: statevector.hpp:29
SIMD implementation of the double precision complex vector type of 2 complex numbers,...
Definition: complex16x2simd.hpp:30