Qrack  9.13
General classical-emulating-quantum development framework
qfactory.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 "qengine_cpu.hpp"
16 #include "qpager.hpp"
17 #include "qstabilizerhybrid.hpp"
18 #include "qtensornetwork.hpp"
19 
20 #if ENABLE_OPENCL
21 #include "qengine_opencl.hpp"
22 #endif
23 
24 #if ENABLE_CUDA
25 #include "common/cudaengine.cuh"
26 #include "qengine_cuda.hpp"
27 #endif
28 
29 #if ENABLE_OPENCL || ENABLE_CUDA
30 #include "qhybrid.hpp"
31 #include "qunitmulti.hpp"
32 #else
33 #include "qunit.hpp"
34 #endif
35 
36 #if ENABLE_QBDT
37 #include "qbdt.hpp"
38 #include "qbdthybrid.hpp"
39 #endif
40 
41 #include "qinterface_noisy.hpp"
42 
43 namespace Qrack {
44 
46 template <typename... Ts>
48  QInterfaceEngine engine1, QInterfaceEngine engine2, QInterfaceEngine engine3, Ts... args)
49 {
50  QInterfaceEngine engine = engine1;
51  std::vector<QInterfaceEngine> engines{ engine2, engine3 };
52 
53  switch (engine) {
55  return std::make_shared<QStabilizer>(args...);
57  return std::make_shared<QUnitClifford>(args...);
58 #if ENABLE_QBDT
59  case QINTERFACE_BDT:
60  return std::make_shared<QBdt>(engines, args...);
62  return std::make_shared<QBdtHybrid>(engines, args...);
63 #endif
64  case QINTERFACE_QPAGER:
65  return std::make_shared<QPager>(engines, args...);
67  return std::make_shared<QStabilizerHybrid>(engines, args...);
68  case QINTERFACE_QUNIT:
69  return std::make_shared<QUnit>(engines, args...);
71  return std::make_shared<QTensorNetwork>(engines, args...);
72 #if ENABLE_OPENCL
73  case QINTERFACE_OPENCL:
74  return std::make_shared<QEngineOCL>(args...);
75 #endif
76 #if ENABLE_CUDA
77  case QINTERFACE_CUDA:
78  return std::make_shared<QEngineCUDA>(args...);
79 #endif
80 #if ENABLE_OPENCL || ENABLE_CUDA
81  case QINTERFACE_HYBRID:
82  return std::make_shared<QHybrid>(args...);
84  return std::make_shared<QUnitMulti>(engines, args...);
85 #endif
86  case QINTERFACE_CPU:
87  return std::make_shared<QEngineCPU>(args...);
88  case QINTERFACE_NOISY:
89  return std::make_shared<QInterfaceNoisy>(engines, args...);
90  default:
91  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
92  }
93 }
94 
95 template <typename... Ts>
97 {
98  QInterfaceEngine engine = engine1;
99  std::vector<QInterfaceEngine> engines{ engine2 };
100 
101  switch (engine) {
103  return std::make_shared<QStabilizer>(args...);
105  return std::make_shared<QUnitClifford>(args...);
106 #if ENABLE_QBDT
107  case QINTERFACE_BDT:
108  return std::make_shared<QBdt>(engines, args...);
110  return std::make_shared<QBdtHybrid>(engines, args...);
111 #endif
112  case QINTERFACE_QPAGER:
113  return std::make_shared<QPager>(engines, args...);
115  return std::make_shared<QStabilizerHybrid>(engines, args...);
116  case QINTERFACE_QUNIT:
117  return std::make_shared<QUnit>(engines, args...);
119  return std::make_shared<QTensorNetwork>(engines, args...);
120 #if ENABLE_OPENCL
121  case QINTERFACE_OPENCL:
122  return std::make_shared<QEngineOCL>(args...);
123 #endif
124 #if ENABLE_CUDA
125  case QINTERFACE_CUDA:
126  return std::make_shared<QEngineCUDA>(args...);
127 #endif
128 #if ENABLE_OPENCL || ENABLE_CUDA
129  case QINTERFACE_HYBRID:
130  return std::make_shared<QHybrid>(args...);
132  return std::make_shared<QUnitMulti>(engines, args...);
133 #endif
134  case QINTERFACE_CPU:
135  return std::make_shared<QEngineCPU>(args...);
136  case QINTERFACE_NOISY:
137  return std::make_shared<QInterfaceNoisy>(engines, args...);
138  default:
139  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
140  }
141 }
142 
143 template <typename... Ts> QInterfacePtr CreateQuantumInterface(QInterfaceEngine engine, Ts... args)
144 {
145  switch (engine) {
147  return std::make_shared<QStabilizer>(args...);
149  return std::make_shared<QUnitClifford>(args...);
150 #if ENABLE_QBDT
151  case QINTERFACE_BDT:
152  return std::make_shared<QBdt>(args...);
154  return std::make_shared<QBdtHybrid>(args...);
155 #endif
156  case QINTERFACE_QPAGER:
157  return std::make_shared<QPager>(args...);
159  return std::make_shared<QStabilizerHybrid>(args...);
160  case QINTERFACE_QUNIT:
161  return std::make_shared<QUnit>(args...);
163  return std::make_shared<QTensorNetwork>(args...);
164 #if ENABLE_OPENCL
165  case QINTERFACE_OPENCL:
166  return std::make_shared<QEngineOCL>(args...);
167 #endif
168 #if ENABLE_CUDA
169  case QINTERFACE_CUDA:
170  return std::make_shared<QEngineCUDA>(args...);
171 #endif
172 #if ENABLE_OPENCL || ENABLE_CUDA
173  case QINTERFACE_HYBRID:
174  return std::make_shared<QHybrid>(args...);
176  return std::make_shared<QUnitMulti>(args...);
177 #endif
178  case QINTERFACE_CPU:
179  return std::make_shared<QEngineCPU>(args...);
180  case QINTERFACE_NOISY:
181  return std::make_shared<QInterfaceNoisy>(args...);
182  default:
183  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
184  }
185 }
186 
187 template <typename... Ts> QInterfacePtr CreateQuantumInterface(std::vector<QInterfaceEngine> engines, Ts... args)
188 {
189  QInterfaceEngine engine = engines[0];
190  engines.erase(engines.begin());
191 
192  switch (engine) {
194  return std::make_shared<QStabilizer>(args...);
196  return std::make_shared<QUnitClifford>(args...);
197 #if ENABLE_QBDT
198  case QINTERFACE_BDT:
199  if (engines.size()) {
200  return std::make_shared<QBdt>(engines, args...);
201  }
202  return std::make_shared<QBdt>(args...);
204  if (engines.size()) {
205  return std::make_shared<QBdtHybrid>(engines, args...);
206  }
207  return std::make_shared<QBdtHybrid>(args...);
208 #endif
209  case QINTERFACE_QPAGER:
210  if (engines.size()) {
211  return std::make_shared<QPager>(engines, args...);
212  }
213  return std::make_shared<QPager>(args...);
215  if (engines.size()) {
216  return std::make_shared<QStabilizerHybrid>(engines, args...);
217  }
218  return std::make_shared<QStabilizerHybrid>(args...);
219  case QINTERFACE_QUNIT:
220  if (engines.size()) {
221  return std::make_shared<QUnit>(engines, args...);
222  }
223  return std::make_shared<QUnit>(args...);
225  if (engines.size()) {
226  return std::make_shared<QTensorNetwork>(engines, args...);
227  }
228  return std::make_shared<QTensorNetwork>(args...);
229 #if ENABLE_OPENCL
230  case QINTERFACE_OPENCL:
231  return std::make_shared<QEngineOCL>(args...);
232 #endif
233 #if ENABLE_CUDA
234  case QINTERFACE_CUDA:
235  return std::make_shared<QEngineCUDA>(args...);
236 #endif
237 #if ENABLE_OPENCL || ENABLE_CUDA
238  case QINTERFACE_HYBRID:
239  return std::make_shared<QHybrid>(args...);
241  if (engines.size()) {
242  return std::make_shared<QUnitMulti>(engines, args...);
243  }
244  return std::make_shared<QUnitMulti>(args...);
245 #endif
246  case QINTERFACE_CPU:
247  return std::make_shared<QEngineCPU>(args...);
248  case QINTERFACE_NOISY:
249  return std::make_shared<QInterfaceNoisy>(engines, args...);
250  default:
251  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
252  }
253 }
254 
255 #if ENABLE_OPENCL
256 #define DEVICE_COUNT (OCLEngine::Instance().GetDeviceCount())
257 #elif ENABLE_CUDA
258 #define DEVICE_COUNT (CUDAEngine::Instance().GetDeviceCount())
259 #endif
260 template <typename... Ts>
262  bool nw, bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
263 {
264 #if ENABLE_OPENCL || ENABLE_CUDA
265  bool isOcl = oc && (DEVICE_COUNT > 0);
266  bool isOclMulti = oc && md && (DEVICE_COUNT > 1);
267 #else
268  bool isOcl = false;
269  bool isOclMulti = false;
270 #endif
271 
272  // Construct backwards, then reverse:
273  std::vector<QInterfaceEngine> simulatorType;
274 
275  if (isOcl) {
276  simulatorType.push_back(hy ? QINTERFACE_HYBRID : QINTERFACE_OPENCL);
277  } else {
278  simulatorType.push_back(QINTERFACE_CPU);
279  }
280 
281  if (pg && isOcl && !hy) {
282  simulatorType.push_back(QINTERFACE_QPAGER);
283  }
284 
285  if (bdt) {
286  simulatorType.push_back(QINTERFACE_BDT);
287  }
288 
289  if (sh) {
290  simulatorType.push_back(QINTERFACE_STABILIZER_HYBRID);
291  }
292 
293  if (sd) {
294  simulatorType.push_back(isOclMulti ? QINTERFACE_QUNIT_MULTI : QINTERFACE_QUNIT);
295  }
296 
297  if (tn) {
298  simulatorType.push_back(QINTERFACE_TENSOR_NETWORK);
299  }
300 
301  if (nw) {
302  simulatorType.push_back(QINTERFACE_NOISY);
303  }
304 
305  // (...then reverse:)
306  std::reverse(simulatorType.begin(), simulatorType.end());
307 
308  return CreateQuantumInterface(simulatorType, args...);
309 }
310 template <typename... Ts>
311 QInterfacePtr CreateArrangedLayers(bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
312 {
313  return CreateArrangedLayersFull(false, md, sd, sh, bdt, pg, tn, hy, oc, args...);
314 }
315 
316 } // namespace Qrack
GLOSSARY: bitLenInt - "bit-length integer" - unsigned integer ID of qubit position in register bitCap...
Definition: complex16x2simd.hpp:25
QInterfaceEngine
Enumerated list of supported engines.
Definition: qinterface.hpp:37
@ QINTERFACE_QPAGER
Create a QPager, which breaks up the work of a QEngine into equally sized "pages.".
Definition: qinterface.hpp:82
@ QINTERFACE_CUDA
Create a QEngineCUDA, leveraging CUDA hardware to increase the speed of certain calculations.
Definition: qinterface.hpp:52
@ QINTERFACE_STABILIZER_HYBRID
Create a QStabilizerHybrid, switching between a QStabilizer and a QHybrid as efficient.
Definition: qinterface.hpp:77
@ QINTERFACE_HYBRID
Create a QHybrid, switching between QEngineCPU and QEngineOCL as efficient.
Definition: qinterface.hpp:57
@ QINTERFACE_BDT_HYBRID
Create a QBinaryDecisionTree, (CPU-based).
Definition: qinterface.hpp:67
@ QINTERFACE_BDT
Create a QBinaryDecisionTree, (CPU-based).
Definition: qinterface.hpp:62
@ QINTERFACE_TENSOR_NETWORK
Circuit-simplification layer.
Definition: qinterface.hpp:107
@ QINTERFACE_NOISY
Noisy wrapper layer.
Definition: qinterface.hpp:112
@ QINTERFACE_QUNIT_CLIFFORD
Clifford-specialized QUnit.
Definition: qinterface.hpp:102
@ QINTERFACE_OPENCL
Create a QEngineOCL, leveraging OpenCL hardware to increase the speed of certain calculations.
Definition: qinterface.hpp:47
@ QINTERFACE_STABILIZER
Create a QStabilizer, limited to Clifford/Pauli operations, but efficient.
Definition: qinterface.hpp:72
@ QINTERFACE_QUNIT
Create a QUnit, which utilizes other QInterface classes to minimize the amount of work that's needed ...
Definition: qinterface.hpp:91
@ QINTERFACE_QUNIT_MULTI
Create a QUnitMulti, which distributes the explicitly separated "shards" of a QUnit across available ...
Definition: qinterface.hpp:97
@ QINTERFACE_CPU
Create a QEngineCPU leveraging only local CPU and memory resources.
Definition: qinterface.hpp:42
std::shared_ptr< QInterface > QInterfacePtr
Definition: qinterface.hpp:29
QInterfacePtr CreateQuantumInterface(QInterfaceEngine engine1, QInterfaceEngine engine2, QInterfaceEngine engine3, Ts... args)
Factory method to create specific engine implementations.
Definition: qfactory.hpp:47
QInterfacePtr CreateArrangedLayers(bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
Definition: qfactory.hpp:311
QInterfacePtr CreateArrangedLayersFull(bool nw, bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
Definition: qfactory.hpp:261
void reverse(BidirectionalIterator first, BidirectionalIterator last, const bitCapInt &stride)