Qrack  10.0
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{ nullptr }
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  using QUnit::Copy;
78  virtual void Copy(QInterfacePtr orig) { Copy(std::dynamic_pointer_cast<QUnitMulti>(orig)); }
79  virtual void Copy(QUnitMultiPtr orig)
80  {
81  QUnit::Copy(std::dynamic_pointer_cast<QUnit>(orig));
82  isRedistributing = orig->isRedistributing;
83  isQEngineOCL = orig->isQEngineOCL;
84  defaultDeviceID = orig->defaultDeviceID;
85  deviceList = orig->deviceList;
86  deviceQbList = orig->deviceQbList;
87  }
88 
89 public:
90  QUnitMulti(std::vector<QInterfaceEngine> eng, bitLenInt qBitCount, const bitCapInt& initState = ZERO_BCI,
91  qrack_rand_gen_ptr rgp = nullptr, const complex& phaseFac = CMPLX_DEFAULT_ARG, bool doNorm = false,
92  bool randomGlobalPhase = true, bool useHostMem = false, int64_t deviceID = -1, bool useHardwareRNG = true,
93  bool useSparseStateVec = false, real1_f norm_thresh = REAL1_EPSILON, std::vector<int64_t> devList = {},
94  bitLenInt qubitThreshold = 0U, real1_f separation_thresh = _qrack_qunit_sep_thresh);
95 
96  QUnitMulti(bitLenInt qBitCount, const bitCapInt& initState = ZERO_BCI, qrack_rand_gen_ptr rgp = nullptr,
97  const complex& phaseFac = CMPLX_DEFAULT_ARG, bool doNorm = false, bool randomGlobalPhase = true,
98  bool useHostMem = false, int64_t deviceID = -1, bool useHardwareRNG = true, bool useSparseStateVec = false,
99  real1_f norm_thresh = REAL1_EPSILON, std::vector<int64_t> devList = {}, bitLenInt qubitThreshold = 0U,
100  real1_f separation_thresh = _qrack_qunit_sep_thresh)
101  : QUnitMulti({ QINTERFACE_STABILIZER_HYBRID }, qBitCount, initState, rgp, phaseFac, doNorm, randomGlobalPhase,
102  useHostMem, deviceID, useHardwareRNG, useSparseStateVec, norm_thresh, devList, qubitThreshold,
103  separation_thresh)
104  {
105  }
106 
108  {
109  QUnitMultiPtr copyPtr = std::make_shared<QUnitMulti>(engines, qubitCount, ZERO_BCI, rand_generator, phaseFactor,
112 
113  return CloneBody(copyPtr, false);
114  }
115 
116  virtual QInterfacePtr Copy()
117  {
118  QUnitMultiPtr copyPtr = std::make_shared<QUnitMulti>(engines, qubitCount, ZERO_BCI, rand_generator, phaseFactor,
121 
122  return CloneBody(copyPtr, true);
123  }
124 
125 protected:
126  virtual std::vector<QEngineInfo> GetQInfos();
127 
128  virtual bool SeparateBit(bool value, bitLenInt qubit)
129  {
130  const bool toRet = QUnit::SeparateBit(value, qubit);
131  if (toRet) {
133  }
134 
135  return toRet;
136  }
137 
138  virtual bool Detach(
139  bitLenInt start, bitLenInt length, QUnitPtr dest, bool isTry = false, real1_f tol = TRYDECOMPOSE_EPSILON)
140  {
141  return Detach(start, length, std::dynamic_pointer_cast<QUnitMulti>(dest), isTry, tol);
142  }
143  virtual bool Detach(
144  bitLenInt start, bitLenInt length, QUnitMultiPtr dest, bool isTry = false, real1_f tol = TRYDECOMPOSE_EPSILON)
145  {
146  if (!length) {
147  return true;
148  }
149 
150  const bool result = QUnit::Detach(start, length, dest, isTry, tol);
151 
152  if (result) {
154  }
155 
156  return result;
157  }
158 
160  std::vector<bitLenInt*>::iterator first, std::vector<bitLenInt*>::iterator last)
161  {
162  QInterfacePtr toRet = QUnit::EntangleInCurrentBasis(first, last);
164 
165  return toRet;
166  }
167 
168  using QUnit::TrySeparate;
169  virtual bool TrySeparate(const std::vector<bitLenInt>& qubits, real1_f error_tol)
170  {
171  for (size_t i = 0U; i < qubits.size(); ++i) {
172  Swap(qubitCount - (i + 1U), qubits[i]);
173  }
174 
175  QUnitPtr dest = std::make_shared<QUnitMulti>(engines, qubits.size(), ZERO_BCI, rand_generator, phaseFactor,
178 
179  const bool result = TryDecompose(qubitCount - qubits.size(), dest);
180  if (result) {
181  Compose(dest);
182  }
183 
184  for (bitLenInt i = qubits.size(); i > 0U; --i) {
185  Swap(qubitCount - i, qubits[i - 1U]);
186  }
187 
188  return result;
189  }
190 
191  virtual void RedistributeQEngines();
192 };
193 } // namespace Qrack
int bi_compare(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:125
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:169
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:96
virtual bool Detach(bitLenInt start, bitLenInt length, QUnitMultiPtr dest, bool isTry=false, real1_f tol=TRYDECOMPOSE_EPSILON)
Definition: qunitmulti.hpp:143
virtual void Copy(QInterfacePtr orig)
Definition: qunitmulti.hpp:78
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:159
virtual bool SeparateBit(bool value, bitLenInt qubit)
Definition: qunitmulti.hpp:128
virtual QInterfacePtr Copy()
Copy this QInterface.
Definition: qunitmulti.hpp:116
virtual QInterfacePtr Clone()
Clone this QInterface.
Definition: qunitmulti.hpp:107
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:138
size_t defaultDeviceID
Definition: qunitmulti.hpp:71
virtual std::vector< QEngineInfo > GetQInfos()
Definition: qunitmulti.cpp:193
virtual void Copy(QUnitMultiPtr orig)
Definition: qunitmulti.hpp:79
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:50
virtual QInterfacePtr EntangleInCurrentBasis(std::vector< bitLenInt * >::iterator first, std::vector< bitLenInt * >::iterator last)
Definition: qunit.cpp:420
real1_f separabilityThreshold
Definition: qunit.hpp:44
virtual bitLenInt Compose(QInterfacePtr toCopy)
Combine another QInterface with this one, after the last bit index of this one.
Definition: qinterface.hpp:371
complex phaseFactor
Definition: qunit.hpp:48
virtual bool SeparateBit(bool value, bitLenInt qubit)
Definition: qunit.cpp:1337
virtual bool TryDecompose(bitLenInt start, QInterfacePtr dest, real1_f error_tol=TRYDECOMPOSE_EPSILON)
Attempt to Decompose() a bit range.
Definition: qunit.hpp:290
virtual bool Detach(bitLenInt start, bitLenInt length, QUnitPtr dest, bool isTry=false, real1_f tol=TRYDECOMPOSE_EPSILON)
Definition: qunit.cpp:289
bitLenInt thresholdQubits
Definition: qunit.hpp:43
std::vector< QInterfaceEngine > engines
Definition: qunit.hpp:51
int64_t devID
Definition: qunit.hpp:47
virtual QInterfacePtr CloneBody(QUnitPtr copyPtr, bool isCopy)
Definition: qunit.cpp:3882
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:2900
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:479
virtual QInterfacePtr Copy()
Copy this QInterface.
Definition: qunit.cpp:3873
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:249
QRACK_CONST real1_f TRYDECOMPOSE_EPSILON
Definition: qrack_types.hpp:270
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::complex< real1 > complex
Definition: qrack_types.hpp:136
std::shared_ptr< QUnitMulti > QUnitMultiPtr
Definition: qunitmulti.hpp:63
QRACK_CONST real1 REAL1_EPSILON
Definition: qrack_types.hpp:208
float real1_f
Definition: qrack_types.hpp:103
QRACK_CONST complex CMPLX_DEFAULT_ARG
Definition: qrack_types.hpp:267
const bitCapInt ZERO_BCI
Definition: qrack_types.hpp:138
#define bitLenInt
Definition: qrack_types.hpp:42
#define qrack_rand_gen_ptr
Definition: qrack_types.hpp:164
#define bitCapInt
Definition: qrack_types.hpp:66
#define bitCapIntOcl
Definition: qrack_types.hpp:54
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