Qrack  9.13
General classical-emulating-quantum development framework
qunitmulti.hpp
Go to the documentation of this file.
1 //
3 // (C) Daniel Strano and the Qrack contributors 2017-2023. All rights reserved.
4 //
5 // QUnit maintains explicit separability of qubits as an optimization on a QEngine.
6 // See https://arxiv.org/abs/1710.05867
7 // (The makers of Qrack have no affiliation with the authors of that paper.)
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 #if ENABLE_OPENCL
16 #include "common/oclengine.hpp"
17 #include "qengine_opencl.hpp"
18 #elif ENABLE_CUDA
19 #include "common/cudaengine.cuh"
20 #include "qengine_cuda.hpp"
21 #endif
22 #include "qunit.hpp"
23 
24 namespace Qrack {
25 
26 struct QEngineInfo {
28  size_t deviceIndex;
29 
31  : unit(NULL)
32  , deviceIndex(0U)
33  {
34  }
35 
36  QEngineInfo(QInterfacePtr u, size_t devIndex)
37  : unit(u)
38  , deviceIndex(devIndex)
39  {
40  }
41 
42  bool operator<(const QEngineInfo& other) const
43  {
44  const int v = bi_compare(unit->GetMaxQPower(), other.unit->GetMaxQPower());
45  if (v == 0) {
46  // "Larger" QEngineInfo instances get first scheduling priority, and low device indices have greater
47  // capacity, so larger deviceIndices get are "<"
48  return other.deviceIndex < deviceIndex;
49  } else {
50  return v < 0;
51  }
52  }
53 };
54 
55 struct DeviceInfo {
56  size_t id;
58 
59  bool operator<(const DeviceInfo& other) const { return maxSize < other.maxSize; }
60  bool operator>(const DeviceInfo& other) const { return maxSize > other.maxSize; }
61 };
62 
63 class QUnitMulti;
64 typedef std::shared_ptr<QUnitMulti> QUnitMultiPtr;
65 
66 class QUnitMulti : public QUnit {
67 
68 protected:
72  std::vector<DeviceInfo> deviceList;
73  std::vector<bitLenInt> deviceQbList;
74 
75  QInterfacePtr MakeEngine(bitLenInt length, const bitCapInt& perm);
76 
77  virtual void Copy(QInterfacePtr orig) { Copy(std::dynamic_pointer_cast<QUnitMulti>(orig)); }
78  virtual void Copy(QUnitMultiPtr orig)
79  {
80  QUnit::Copy(std::dynamic_pointer_cast<QUnit>(orig));
81  isRedistributing = orig->isRedistributing;
82  isQEngineOCL = orig->isQEngineOCL;
83  defaultDeviceID = orig->defaultDeviceID;
84  deviceList = orig->deviceList;
85  deviceQbList = orig->deviceQbList;
86  }
87 
88 public:
89  QUnitMulti(std::vector<QInterfaceEngine> eng, bitLenInt qBitCount, const bitCapInt& initState = ZERO_BCI,
90  qrack_rand_gen_ptr rgp = nullptr, const complex& phaseFac = CMPLX_DEFAULT_ARG, bool doNorm = false,
91  bool randomGlobalPhase = true, bool useHostMem = false, int64_t deviceID = -1, bool useHardwareRNG = true,
92  bool useSparseStateVec = false, real1_f norm_thresh = REAL1_EPSILON, std::vector<int64_t> devList = {},
93  bitLenInt qubitThreshold = 0U, real1_f separation_thresh = _qrack_qunit_sep_thresh);
94 
95  QUnitMulti(bitLenInt qBitCount, const bitCapInt& initState = ZERO_BCI, qrack_rand_gen_ptr rgp = nullptr,
96  const complex& phaseFac = CMPLX_DEFAULT_ARG, bool doNorm = false, bool randomGlobalPhase = true,
97  bool useHostMem = false, int64_t deviceID = -1, bool useHardwareRNG = true, bool useSparseStateVec = false,
98  real1_f norm_thresh = REAL1_EPSILON, std::vector<int64_t> devList = {}, bitLenInt qubitThreshold = 0U,
99  real1_f separation_thresh = _qrack_qunit_sep_thresh)
100  : QUnitMulti({ QINTERFACE_STABILIZER_HYBRID }, qBitCount, initState, rgp, phaseFac, doNorm, randomGlobalPhase,
101  useHostMem, deviceID, useHardwareRNG, useSparseStateVec, norm_thresh, devList, qubitThreshold,
102  separation_thresh)
103  {
104  }
105 
107  {
108  QUnitMultiPtr copyPtr = std::make_shared<QUnitMulti>(engines, qubitCount, ZERO_BCI, rand_generator, phaseFactor,
111 
112  return CloneBody(copyPtr, false);
113  }
114 
115  virtual QInterfacePtr Copy()
116  {
117  QUnitMultiPtr copyPtr = std::make_shared<QUnitMulti>(engines, qubitCount, ZERO_BCI, rand_generator, phaseFactor,
120 
121  return CloneBody(copyPtr, true);
122  }
123 
124 protected:
125  virtual std::vector<QEngineInfo> GetQInfos();
126 
127  virtual bool SeparateBit(bool value, bitLenInt qubit)
128  {
129  const bool toRet = QUnit::SeparateBit(value, qubit);
130  if (toRet) {
132  }
133 
134  return toRet;
135  }
136 
137  virtual bool Detach(
138  bitLenInt start, bitLenInt length, QUnitPtr dest, bool isTry = false, real1_f tol = TRYDECOMPOSE_EPSILON)
139  {
140  return Detach(start, length, std::dynamic_pointer_cast<QUnitMulti>(dest), isTry, tol);
141  }
142  virtual bool Detach(
143  bitLenInt start, bitLenInt length, QUnitMultiPtr dest, bool isTry = false, real1_f tol = TRYDECOMPOSE_EPSILON)
144  {
145  if (!length) {
146  return true;
147  }
148 
149  const bool result = QUnit::Detach(start, length, dest, isTry, tol);
150 
151  if (result) {
153  }
154 
155  return result;
156  }
157 
159  std::vector<bitLenInt*>::iterator first, std::vector<bitLenInt*>::iterator last)
160  {
161  QInterfacePtr toRet = QUnit::EntangleInCurrentBasis(first, last);
163 
164  return toRet;
165  }
166 
167  using QUnit::TrySeparate;
168  virtual bool TrySeparate(const std::vector<bitLenInt>& qubits, real1_f error_tol)
169  {
170  for (size_t i = 0U; i < qubits.size(); ++i) {
171  Swap(qubitCount - (i + 1U), qubits[i]);
172  }
173 
174  QUnitPtr dest = std::make_shared<QUnitMulti>(engines, qubits.size(), ZERO_BCI, rand_generator, phaseFactor,
177 
178  const bool result = TryDecompose(qubitCount - qubits.size(), dest);
179  if (result) {
180  Compose(dest);
181  }
182 
183  for (bitLenInt i = qubits.size(); i > 0U; --i) {
184  Swap(qubitCount - i, qubits[i - 1U]);
185  }
186 
187  return result;
188  }
189 
190  virtual void RedistributeQEngines();
191 };
192 } // namespace Qrack
int bi_compare(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:120
real1 amplitudeFloor
Definition: qinterface.hpp:148
bool useRDRAND
Definition: qinterface.hpp:145
qrack_rand_gen_ptr rand_generator
Definition: qinterface.hpp:150
bool randGlobalPhase
Definition: qinterface.hpp:144
bitLenInt qubitCount
Definition: qinterface.hpp:146
bool doNormalize
Definition: qinterface.hpp:143
Definition: qunitmulti.hpp:66
bool isQEngineOCL
Definition: qunitmulti.hpp:70
virtual bool TrySeparate(const std::vector< bitLenInt > &qubits, real1_f error_tol)
Qrack::QUnit types maintain explicit separation of representations of qubits, which reduces memory us...
Definition: qunitmulti.hpp:168
QUnitMulti(bitLenInt qBitCount, const bitCapInt &initState=ZERO_BCI, qrack_rand_gen_ptr rgp=nullptr, const complex &phaseFac=CMPLX_DEFAULT_ARG, bool doNorm=false, bool randomGlobalPhase=true, bool useHostMem=false, int64_t deviceID=-1, bool useHardwareRNG=true, bool useSparseStateVec=false, real1_f norm_thresh=REAL1_EPSILON, std::vector< int64_t > devList={}, bitLenInt qubitThreshold=0U, real1_f separation_thresh=_qrack_qunit_sep_thresh)
Definition: qunitmulti.hpp:95
virtual bool Detach(bitLenInt start, bitLenInt length, QUnitMultiPtr dest, bool isTry=false, real1_f tol=TRYDECOMPOSE_EPSILON)
Definition: qunitmulti.hpp:142
virtual void Copy(QInterfacePtr orig)
Definition: qunitmulti.hpp:77
QInterfacePtr MakeEngine(bitLenInt length, const bitCapInt &perm)
Definition: qunitmulti.cpp:172
virtual QInterfacePtr EntangleInCurrentBasis(std::vector< bitLenInt * >::iterator first, std::vector< bitLenInt * >::iterator last)
Definition: qunitmulti.hpp:158
virtual bool SeparateBit(bool value, bitLenInt qubit)
Definition: qunitmulti.hpp:127
virtual QInterfacePtr Copy()
Copy this QInterface.
Definition: qunitmulti.hpp:115
virtual QInterfacePtr Clone()
Clone this QInterface.
Definition: qunitmulti.hpp:106
std::vector< DeviceInfo > deviceList
Definition: qunitmulti.hpp:72
virtual void RedistributeQEngines()
Definition: qunitmulti.cpp:217
virtual bool Detach(bitLenInt start, bitLenInt length, QUnitPtr dest, bool isTry=false, real1_f tol=TRYDECOMPOSE_EPSILON)
Definition: qunitmulti.hpp:137
size_t defaultDeviceID
Definition: qunitmulti.hpp:71
virtual std::vector< QEngineInfo > GetQInfos()
Definition: qunitmulti.cpp:193
virtual void Copy(QUnitMultiPtr orig)
Definition: qunitmulti.hpp:78
QUnitMulti(std::vector< QInterfaceEngine > eng, bitLenInt qBitCount, const bitCapInt &initState=ZERO_BCI, qrack_rand_gen_ptr rgp=nullptr, const complex &phaseFac=CMPLX_DEFAULT_ARG, bool doNorm=false, bool randomGlobalPhase=true, bool useHostMem=false, int64_t deviceID=-1, bool useHardwareRNG=true, bool useSparseStateVec=false, real1_f norm_thresh=REAL1_EPSILON, std::vector< int64_t > devList={}, bitLenInt qubitThreshold=0U, real1_f separation_thresh=_qrack_qunit_sep_thresh)
Definition: qunitmulti.cpp:31
bool isRedistributing
Definition: qunitmulti.hpp:69
std::vector< bitLenInt > deviceQbList
Definition: qunitmulti.hpp:73
Definition: qunit.hpp:28
std::vector< int64_t > deviceIDs
Definition: qunit.hpp:47
virtual QInterfacePtr EntangleInCurrentBasis(std::vector< bitLenInt * >::iterator first, std::vector< bitLenInt * >::iterator last)
Definition: qunit.cpp:414
real1_f separabilityThreshold
Definition: qunit.hpp:41
virtual bitLenInt Compose(QInterfacePtr toCopy)
Combine another QInterface with this one, after the last bit index of this one.
Definition: qinterface.hpp:364
complex phaseFactor
Definition: qunit.hpp:45
virtual bool SeparateBit(bool value, bitLenInt qubit)
Definition: qunit.cpp:1331
virtual bool TryDecompose(bitLenInt start, QInterfacePtr dest, real1_f error_tol=TRYDECOMPOSE_EPSILON)
Attempt to Decompose() a bit range.
Definition: qunit.hpp:229
virtual bool Detach(bitLenInt start, bitLenInt length, QUnitPtr dest, bool isTry=false, real1_f tol=TRYDECOMPOSE_EPSILON)
Definition: qunit.cpp:282
bitLenInt thresholdQubits
Definition: qunit.hpp:40
std::vector< QInterfaceEngine > engines
Definition: qunit.hpp:48
int64_t devID
Definition: qunit.hpp:44
virtual QInterfacePtr CloneBody(QUnitPtr copyPtr, bool isCopy)
Definition: qunit.cpp:3949
virtual bool TrySeparate(const std::vector< bitLenInt > &qubits, real1_f error_tol)
Qrack::QUnit types maintain explicit separation of representations of qubits, which reduces memory us...
Definition: qinterface.hpp:2881
bool useHostRam
Definition: qunit.hpp:34
virtual void U(bitLenInt target, real1_f theta, real1_f phi, real1_f lambda)
General unitary gate.
Definition: rotational.cpp:18
virtual void Swap(bitLenInt qubit1, bitLenInt qubit2)
Swap values of two bits in register.
Definition: qunit.hpp:414
virtual QInterfacePtr Copy()
Copy this QInterface.
Definition: qunit.cpp:3940
GLOSSARY: bitLenInt - "bit-length integer" - unsigned integer ID of qubit position in register bitCap...
Definition: complex16x2simd.hpp:25
@ QINTERFACE_STABILIZER_HYBRID
Create a QStabilizerHybrid, switching between a QStabilizer and a QHybrid as efficient.
Definition: qinterface.hpp:77
std::shared_ptr< QUnit > QUnitPtr
Definition: qunit.hpp:24
std::shared_ptr< QInterface > QInterfacePtr
Definition: qinterface.hpp:29
const real1_f _qrack_qunit_sep_thresh
Definition: qrack_functions.hpp:235
QRACK_CONST real1_f TRYDECOMPOSE_EPSILON
Definition: qrack_types.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:1143
std::complex< real1 > complex
Definition: qrack_types.hpp:128
std::shared_ptr< QUnitMulti > QUnitMultiPtr
Definition: qunitmulti.hpp:63
QRACK_CONST real1 REAL1_EPSILON
Definition: qrack_types.hpp:200
float real1_f
Definition: qrack_types.hpp:95
QRACK_CONST complex CMPLX_DEFAULT_ARG
Definition: qrack_types.hpp:257
const bitCapInt ZERO_BCI
Definition: qrack_types.hpp:130
#define bitLenInt
Definition: qrack_types.hpp:38
#define qrack_rand_gen_ptr
Definition: qrack_types.hpp:156
#define bitCapInt
Definition: qrack_types.hpp:62
#define bitCapIntOcl
Definition: qrack_types.hpp:50
Definition: qunitmulti.hpp:55
bitCapIntOcl maxSize
Definition: qunitmulti.hpp:57
bool operator<(const DeviceInfo &other) const
Definition: qunitmulti.hpp:59
bool operator>(const DeviceInfo &other) const
Definition: qunitmulti.hpp:60
size_t id
Definition: qunitmulti.hpp:56
Definition: qunitmulti.hpp:26
bool operator<(const QEngineInfo &other) const
Definition: qunitmulti.hpp:42
QInterfacePtr unit
Definition: qunitmulti.hpp:27
size_t deviceIndex
Definition: qunitmulti.hpp:28
QEngineInfo()
Definition: qunitmulti.hpp:30
QEngineInfo(QInterfacePtr u, size_t devIndex)
Definition: qunitmulti.hpp:36