Qrack  10.0
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  if (engines.size()) {
250  return std::make_shared<QInterfaceNoisy>(engines, args...);
251  }
252  return std::make_shared<QInterfaceNoisy>(args...);
253  default:
254  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
255  }
256 }
257 
258 #if ENABLE_OPENCL
259 #define DEVICE_COUNT (OCLEngine::Instance().GetDeviceCount())
260 #elif ENABLE_CUDA
261 #define DEVICE_COUNT (CUDAEngine::Instance().GetDeviceCount())
262 #endif
263 template <typename... Ts>
265  bool nw, bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
266 {
267 #if ENABLE_OPENCL || ENABLE_CUDA
268  bool isOcl = oc && (DEVICE_COUNT > 0);
269  bool isOclMulti = oc && md && (DEVICE_COUNT > 1);
270 #else
271  bool isOcl = false;
272  bool isOclMulti = false;
273 #endif
274 
275  // Construct backwards, then reverse:
276  std::vector<QInterfaceEngine> simulatorType;
277 
278  if (isOcl) {
279  simulatorType.push_back(hy ? QINTERFACE_HYBRID : QINTERFACE_OPENCL);
280  } else {
281  simulatorType.push_back(QINTERFACE_CPU);
282  }
283 
284  if (pg && isOcl && !hy) {
285  simulatorType.push_back(QINTERFACE_QPAGER);
286  }
287 
288  if (bdt) {
289  simulatorType.push_back(QINTERFACE_BDT);
290  }
291 
292  if (sh) {
293  simulatorType.push_back(QINTERFACE_STABILIZER_HYBRID);
294  }
295 
296  if (sd) {
297  simulatorType.push_back(isOclMulti ? QINTERFACE_QUNIT_MULTI : QINTERFACE_QUNIT);
298  }
299 
300  if (tn) {
301  simulatorType.push_back(QINTERFACE_TENSOR_NETWORK);
302  }
303 
304  if (nw) {
305  simulatorType.push_back(QINTERFACE_NOISY);
306  }
307 
308  // (...then reverse:)
309  std::reverse(simulatorType.begin(), simulatorType.end());
310 
311  return CreateQuantumInterface(simulatorType, args...);
312 }
313 template <typename... Ts>
314 QInterfacePtr CreateArrangedLayers(bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
315 {
316  return CreateArrangedLayersFull(false, md, sd, sh, bdt, pg, tn, hy, oc, args...);
317 }
318 
319 } // 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:314
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:264
void reverse(BidirectionalIterator first, BidirectionalIterator last, const bitCapInt &stride)