Qrack  9.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(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  if (unit->GetMaxQPower() == other.unit->GetMaxQPower()) {
45  // "Larger" QEngineInfo instances get first scheduling priority, and low device indices have greater
46  // capacity, so larger deviceIndices get are "<"
47  return other.deviceIndex < deviceIndex;
48  } else {
49  return unit->GetMaxQPower() < other.unit->GetMaxQPower();
50  }
51  }
52 };
53 
54 struct DeviceInfo {
55  size_t id;
57 
58  bool operator<(const DeviceInfo& other) const { return maxSize < other.maxSize; }
59  bool operator>(const DeviceInfo& other) const { return maxSize > other.maxSize; }
60 };
61 
62 class QUnitMulti;
63 typedef std::shared_ptr<QUnitMulti> QUnitMultiPtr;
64 
65 class QUnitMulti : public QUnit {
66 
67 protected:
71  std::vector<DeviceInfo> deviceList;
72  std::vector<bitLenInt> deviceQbList;
73 
75 
76 public:
77  QUnitMulti(std::vector<QInterfaceEngine> eng, bitLenInt qBitCount, bitCapInt initState = 0U,
78  qrack_rand_gen_ptr rgp = nullptr, complex phaseFac = CMPLX_DEFAULT_ARG, bool doNorm = false,
79  bool randomGlobalPhase = true, bool useHostMem = false, int64_t deviceID = -1, bool useHardwareRNG = true,
80  bool useSparseStateVec = false, real1_f norm_thresh = REAL1_EPSILON, std::vector<int64_t> devList = {},
81  bitLenInt qubitThreshold = 0U, real1_f separation_thresh = FP_NORM_EPSILON_F);
82 
83  QUnitMulti(bitLenInt qBitCount, bitCapInt initState = 0U, qrack_rand_gen_ptr rgp = nullptr,
84  complex phaseFac = CMPLX_DEFAULT_ARG, bool doNorm = false, bool randomGlobalPhase = true,
85  bool useHostMem = false, int64_t deviceID = -1, bool useHardwareRNG = true, bool useSparseStateVec = false,
86  real1_f norm_thresh = REAL1_EPSILON, std::vector<int64_t> devList = {}, bitLenInt qubitThreshold = 0U,
87  real1_f separation_thresh = FP_NORM_EPSILON_F)
88  : QUnitMulti({ QINTERFACE_STABILIZER_HYBRID }, qBitCount, initState, rgp, phaseFac, doNorm, randomGlobalPhase,
89  useHostMem, deviceID, useHardwareRNG, useSparseStateVec, norm_thresh, devList, qubitThreshold,
90  separation_thresh)
91  {
92  }
93 
94  virtual QInterfacePtr Clone()
95  {
96  // TODO: Copy buffers instead of flushing?
97  for (bitLenInt i = 0U; i < qubitCount; ++i) {
98  RevertBasis2Qb(i);
99  }
100 
101  QUnitMultiPtr copyPtr = std::make_shared<QUnitMulti>(engines, qubitCount, 0U, rand_generator, phaseFactor,
104 
105  copyPtr->SetReactiveSeparate(isReactiveSeparate);
106 
107  return CloneBody(copyPtr);
108  }
109 
110 protected:
111  virtual std::vector<QEngineInfo> GetQInfos();
112 
113  virtual bool SeparateBit(bool value, bitLenInt qubit)
114  {
115  const bool toRet = QUnit::SeparateBit(value, qubit);
117 
118  return toRet;
119  }
120 
121  virtual void Detach(bitLenInt start, bitLenInt length, QUnitPtr dest)
122  {
123  Detach(start, length, std::dynamic_pointer_cast<QUnitMulti>(dest));
124  }
125  virtual void Detach(bitLenInt start, bitLenInt length, QUnitMultiPtr dest)
126  {
127  if (!length) {
128  return;
129  }
130 
131  QUnit::Detach(start, length, dest);
133  }
134 
136  std::vector<bitLenInt*>::iterator first, std::vector<bitLenInt*>::iterator last)
137  {
138  QInterfacePtr toRet = QUnit::EntangleInCurrentBasis(first, last);
140 
141  return toRet;
142  }
143 
144  virtual void RedistributeQEngines();
145 };
146 } // namespace Qrack
real1 amplitudeFloor
Definition: qinterface.hpp:153
bool useRDRAND
Definition: qinterface.hpp:150
qrack_rand_gen_ptr rand_generator
Definition: qinterface.hpp:155
bool randGlobalPhase
Definition: qinterface.hpp:149
bitLenInt qubitCount
Definition: qinterface.hpp:151
bool doNormalize
Definition: qinterface.hpp:148
Definition: qunitmulti.hpp:65
bool isQEngineOCL
Definition: qunitmulti.hpp:69
virtual QInterfacePtr EntangleInCurrentBasis(std::vector< bitLenInt * >::iterator first, std::vector< bitLenInt * >::iterator last)
Definition: qunitmulti.hpp:135
virtual bool SeparateBit(bool value, bitLenInt qubit)
Definition: qunitmulti.hpp:113
QUnitMulti(bitLenInt qBitCount, bitCapInt initState=0U, qrack_rand_gen_ptr rgp=nullptr, 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=FP_NORM_EPSILON_F)
Definition: qunitmulti.hpp:83
virtual QInterfacePtr Clone()
Clone this QInterface.
Definition: qunitmulti.hpp:94
virtual void Detach(bitLenInt start, bitLenInt length, QUnitPtr dest)
Definition: qunitmulti.hpp:121
std::vector< DeviceInfo > deviceList
Definition: qunitmulti.hpp:71
virtual void RedistributeQEngines()
Definition: qunitmulti.cpp:217
QUnitMulti(std::vector< QInterfaceEngine > eng, bitLenInt qBitCount, bitCapInt initState=0U, qrack_rand_gen_ptr rgp=nullptr, 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=FP_NORM_EPSILON_F)
Definition: qunitmulti.cpp:31
size_t defaultDeviceID
Definition: qunitmulti.hpp:70
QInterfacePtr MakeEngine(bitLenInt length, bitCapInt perm)
Definition: qunitmulti.cpp:172
virtual void Detach(bitLenInt start, bitLenInt length, QUnitMultiPtr dest)
Definition: qunitmulti.hpp:125
virtual std::vector< QEngineInfo > GetQInfos()
Definition: qunitmulti.cpp:193
bool isRedistributing
Definition: qunitmulti.hpp:68
std::vector< bitLenInt > deviceQbList
Definition: qunitmulti.hpp:72
Definition: qunit.hpp:28
std::vector< int64_t > deviceIDs
Definition: qunit.hpp:44
virtual QInterfacePtr EntangleInCurrentBasis(std::vector< bitLenInt * >::iterator first, std::vector< bitLenInt * >::iterator last)
Definition: qunit.cpp:384
real1_f separabilityThreshold
Definition: qunit.hpp:39
complex phaseFactor
Definition: qunit.hpp:42
virtual bool SeparateBit(bool value, bitLenInt qubit)
Definition: qunit.cpp:1347
bool isReactiveSeparate
Definition: qunit.hpp:36
bitLenInt thresholdQubits
Definition: qunit.hpp:38
std::vector< QInterfaceEngine > engines
Definition: qunit.hpp:45
virtual void Detach(bitLenInt start, bitLenInt length, QUnitPtr dest)
Definition: qunit.cpp:268
void RevertBasis2Qb(bitLenInt i, RevertExclusivity exclusivity=INVERT_AND_PHASE, RevertControl controlExclusivity=CONTROLS_AND_TARGETS, RevertAnti antiExclusivity=CTRL_AND_ANTI, const std::set< bitLenInt > &exceptControlling={}, const std::set< bitLenInt > &exceptTargetedBy={}, bool dumpSkipped=false, bool skipOptimized=false)
Definition: qunit.cpp:4167
virtual QInterfacePtr CloneBody(QUnitPtr copyPtr)
Definition: qunit.cpp:4060
bool isSparse
Definition: qunit.hpp:35
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
Definition: complex16x2simd.hpp:25
std::complex< half_float::half > complex
Definition: qrack_types.hpp:62
@ QINTERFACE_STABILIZER_HYBRID
Create a QStabilizerHybrid, switching between a QStabilizer and a QHybrid as efficient.
Definition: qinterface.hpp:90
std::shared_ptr< QUnit > QUnitPtr
Definition: qunit.hpp:24
std::shared_ptr< QInterface > QInterfacePtr
Definition: qinterface.hpp:28
constexpr real1_f FP_NORM_EPSILON_F
Definition: qrack_types.hpp:245
std::shared_ptr< QUnitMulti > QUnitMultiPtr
Definition: qunitmulti.hpp:62
float real1_f
Definition: qrack_types.hpp:64
QRACK_CONST complex CMPLX_DEFAULT_ARG
Definition: qrack_types.hpp:242
const real1 REAL1_EPSILON
Definition: qrack_types.hpp:157
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 bitLenInt
Definition: qrack_types.hpp:44
#define qrack_rand_gen_ptr
Definition: qrack_types.hpp:146
#define bitCapInt
Definition: qrack_types.hpp:105
Definition: qunitmulti.hpp:54
bitCapInt maxSize
Definition: qunitmulti.hpp:56
bool operator<(const DeviceInfo &other) const
Definition: qunitmulti.hpp:58
bool operator>(const DeviceInfo &other) const
Definition: qunitmulti.hpp:59
size_t id
Definition: qunitmulti.hpp:55
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