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 
44 
45 namespace Qrack {
46 
48 template <typename... Ts>
50  QInterfaceEngine engine1, QInterfaceEngine engine2, QInterfaceEngine engine3, Ts... args)
51 {
52  QInterfaceEngine engine = engine1;
53  std::vector<QInterfaceEngine> engines{ engine2, engine3 };
54 
55  switch (engine) {
57  return std::make_shared<QStabilizer>(args...);
59  return std::make_shared<QUnitClifford>(args...);
60 #if ENABLE_QBDT
61  case QINTERFACE_BDT:
62  return std::make_shared<QBdt>(engines, args...);
64  return std::make_shared<QBdtHybrid>(engines, args...);
65 #endif
66  case QINTERFACE_QPAGER:
67  return std::make_shared<QPager>(engines, args...);
69  return std::make_shared<QStabilizerHybrid>(engines, args...);
70  case QINTERFACE_QUNIT:
71  return std::make_shared<QUnit>(engines, args...);
73  return std::make_shared<QTensorNetwork>(engines, args...);
74 #if ENABLE_OPENCL
75  case QINTERFACE_OPENCL:
76  return std::make_shared<QEngineOCL>(args...);
77 #endif
78 #if ENABLE_CUDA
79  case QINTERFACE_CUDA:
80  return std::make_shared<QEngineCUDA>(args...);
81 #endif
82 #if ENABLE_OPENCL || ENABLE_CUDA
83  case QINTERFACE_HYBRID:
84  return std::make_shared<QHybrid>(args...);
86  return std::make_shared<QUnitMulti>(engines, args...);
87 #endif
88  case QINTERFACE_CPU:
89  return std::make_shared<QEngineCPU>(args...);
90  case QINTERFACE_NOISY:
91  return std::make_shared<QInterfaceNoisy>(engines, args...);
92  default:
93  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
94  }
95 }
96 
97 template <typename... Ts>
99 {
100  QInterfaceEngine engine = engine1;
101  std::vector<QInterfaceEngine> engines{ engine2 };
102 
103  switch (engine) {
105  return std::make_shared<QStabilizer>(args...);
107  return std::make_shared<QUnitClifford>(args...);
108 #if ENABLE_QBDT
109  case QINTERFACE_BDT:
110  return std::make_shared<QBdt>(engines, args...);
112  return std::make_shared<QBdtHybrid>(engines, args...);
113 #endif
114  case QINTERFACE_QPAGER:
115  return std::make_shared<QPager>(engines, args...);
117  return std::make_shared<QStabilizerHybrid>(engines, args...);
118  case QINTERFACE_QUNIT:
119  return std::make_shared<QUnit>(engines, args...);
121  return std::make_shared<QTensorNetwork>(engines, args...);
122 #if ENABLE_OPENCL
123  case QINTERFACE_OPENCL:
124  return std::make_shared<QEngineOCL>(args...);
125 #endif
126 #if ENABLE_CUDA
127  case QINTERFACE_CUDA:
128  return std::make_shared<QEngineCUDA>(args...);
129 #endif
130 #if ENABLE_OPENCL || ENABLE_CUDA
131  case QINTERFACE_HYBRID:
132  return std::make_shared<QHybrid>(args...);
134  return std::make_shared<QUnitMulti>(engines, args...);
135 #endif
136  case QINTERFACE_CPU:
137  return std::make_shared<QEngineCPU>(args...);
138  case QINTERFACE_NOISY:
139  return std::make_shared<QInterfaceNoisy>(engines, args...);
140  default:
141  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
142  }
143 }
144 
145 template <typename... Ts> QInterfacePtr CreateQuantumInterface(QInterfaceEngine engine, Ts... args)
146 {
147  switch (engine) {
149  return std::make_shared<QStabilizer>(args...);
151  return std::make_shared<QUnitClifford>(args...);
152 #if ENABLE_QBDT
153  case QINTERFACE_BDT:
154  return std::make_shared<QBdt>(args...);
156  return std::make_shared<QBdtHybrid>(args...);
157 #endif
158  case QINTERFACE_QPAGER:
159  return std::make_shared<QPager>(args...);
161  return std::make_shared<QStabilizerHybrid>(args...);
162  case QINTERFACE_QUNIT:
163  return std::make_shared<QUnit>(args...);
165  return std::make_shared<QTensorNetwork>(args...);
166 #if ENABLE_OPENCL
167  case QINTERFACE_OPENCL:
168  return std::make_shared<QEngineOCL>(args...);
169 #endif
170 #if ENABLE_CUDA
171  case QINTERFACE_CUDA:
172  return std::make_shared<QEngineCUDA>(args...);
173 #endif
174 #if ENABLE_OPENCL || ENABLE_CUDA
175  case QINTERFACE_HYBRID:
176  return std::make_shared<QHybrid>(args...);
178  return std::make_shared<QUnitMulti>(args...);
179 #endif
180  case QINTERFACE_CPU:
181  return std::make_shared<QEngineCPU>(args...);
182  case QINTERFACE_NOISY:
183  return std::make_shared<QInterfaceNoisy>(args...);
184  default:
185  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
186  }
187 }
188 
189 template <typename... Ts> QInterfacePtr CreateQuantumInterface(std::vector<QInterfaceEngine> engines, Ts... args)
190 {
191  QInterfaceEngine engine = engines[0];
192  engines.erase(engines.begin());
193 
194  switch (engine) {
196  return std::make_shared<QStabilizer>(args...);
198  return std::make_shared<QUnitClifford>(args...);
199 #if ENABLE_QBDT
200  case QINTERFACE_BDT:
201  if (engines.size()) {
202  return std::make_shared<QBdt>(engines, args...);
203  }
204  return std::make_shared<QBdt>(args...);
206  if (engines.size()) {
207  return std::make_shared<QBdtHybrid>(engines, args...);
208  }
209  return std::make_shared<QBdtHybrid>(args...);
210 #endif
211  case QINTERFACE_QPAGER:
212  if (engines.size()) {
213  return std::make_shared<QPager>(engines, args...);
214  }
215  return std::make_shared<QPager>(args...);
217  if (engines.size()) {
218  return std::make_shared<QStabilizerHybrid>(engines, args...);
219  }
220  return std::make_shared<QStabilizerHybrid>(args...);
221  case QINTERFACE_QUNIT:
222  if (engines.size()) {
223  return std::make_shared<QUnit>(engines, args...);
224  }
225  return std::make_shared<QUnit>(args...);
227  if (engines.size()) {
228  return std::make_shared<QTensorNetwork>(engines, args...);
229  }
230  return std::make_shared<QTensorNetwork>(args...);
231 #if ENABLE_OPENCL
232  case QINTERFACE_OPENCL:
233  return std::make_shared<QEngineOCL>(args...);
234 #endif
235 #if ENABLE_CUDA
236  case QINTERFACE_CUDA:
237  return std::make_shared<QEngineCUDA>(args...);
238 #endif
239 #if ENABLE_OPENCL || ENABLE_CUDA
240  case QINTERFACE_HYBRID:
241  return std::make_shared<QHybrid>(args...);
243  if (engines.size()) {
244  return std::make_shared<QUnitMulti>(engines, args...);
245  }
246  return std::make_shared<QUnitMulti>(args...);
247 #endif
248  case QINTERFACE_CPU:
249  return std::make_shared<QEngineCPU>(args...);
250  case QINTERFACE_NOISY:
251  if (engines.size()) {
252  return std::make_shared<QInterfaceNoisy>(engines, args...);
253  }
254  return std::make_shared<QInterfaceNoisy>(args...);
255  default:
256  throw std::invalid_argument("CreateQuantumInterface received a request to create a nonexistent type instance!");
257  }
258 }
259 
260 #if ENABLE_OPENCL
261 #define DEVICE_COUNT (OCLEngine::Instance().GetDeviceCount())
262 #elif ENABLE_CUDA
263 #define DEVICE_COUNT (CUDAEngine::Instance().GetDeviceCount())
264 #endif
265 template <typename... Ts>
267  bool nw, bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
268 {
269 #if ENABLE_OPENCL || ENABLE_CUDA
270  bool isOcl = oc && (DEVICE_COUNT > 0);
271  bool isOclMulti = oc && md && (DEVICE_COUNT > 1);
272 #else
273  bool isOcl = false;
274  bool isOclMulti = false;
275 #endif
276 
277  // Construct backwards, then reverse:
278  std::vector<QInterfaceEngine> simulatorType;
279 
280  if (isOcl) {
281  simulatorType.push_back(hy ? QINTERFACE_HYBRID : QINTERFACE_OPENCL);
282  } else {
283  simulatorType.push_back(QINTERFACE_CPU);
284  }
285 
286  if (pg && isOcl && !hy) {
287  simulatorType.push_back(QINTERFACE_QPAGER);
288  }
289 
290  if (bdt) {
291  simulatorType.push_back(QINTERFACE_BDT);
292  }
293 
294  if (sh) {
295  simulatorType.push_back(QINTERFACE_STABILIZER_HYBRID);
296  }
297 
298  if (sd) {
299  simulatorType.push_back(isOclMulti ? QINTERFACE_QUNIT_MULTI : QINTERFACE_QUNIT);
300  }
301 
302  if (tn) {
303  simulatorType.push_back(QINTERFACE_TENSOR_NETWORK);
304  }
305 
306  if (nw) {
307  simulatorType.push_back(QINTERFACE_NOISY);
308  }
309 
310  // (...then reverse:)
311  std::reverse(simulatorType.begin(), simulatorType.end());
312 
313  return CreateQuantumInterface(simulatorType, args...);
314 }
315 template <typename... Ts>
316 QInterfacePtr CreateArrangedLayers(bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
317 {
318  return CreateArrangedLayersFull(false, md, sd, sh, bdt, pg, tn, hy, oc, args...);
319 }
320 
321 } // 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:49
QInterfacePtr CreateArrangedLayers(bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
Definition: qfactory.hpp:316
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:266
void reverse(BidirectionalIterator first, BidirectionalIterator last, const bitCapInt &stride)