Qrack  9.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 namespace Qrack {
42 
44 template <typename... Ts>
46  QInterfaceEngine engine1, QInterfaceEngine engine2, QInterfaceEngine engine3, Ts... args)
47 {
48  QInterfaceEngine engine = engine1;
49  std::vector<QInterfaceEngine> engines{ engine2, engine3 };
50 
51  switch (engine) {
52  case QINTERFACE_CPU:
53  return std::make_shared<QEngineCPU>(args...);
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  default:
87  return NULL;
88  }
89 }
90 
91 template <typename... Ts>
93 {
94  QInterfaceEngine engine = engine1;
95  std::vector<QInterfaceEngine> engines{ engine2 };
96 
97  switch (engine) {
98  case QINTERFACE_CPU:
99  return std::make_shared<QEngineCPU>(args...);
101  return std::make_shared<QStabilizer>(args...);
103  return std::make_shared<QUnitClifford>(args...);
104 #if ENABLE_QBDT
105  case QINTERFACE_BDT:
106  return std::make_shared<QBdt>(engines, args...);
108  return std::make_shared<QBdtHybrid>(engines, args...);
109 #endif
110  case QINTERFACE_QPAGER:
111  return std::make_shared<QPager>(engines, args...);
113  return std::make_shared<QStabilizerHybrid>(engines, args...);
114  case QINTERFACE_QUNIT:
115  return std::make_shared<QUnit>(engines, args...);
117  return std::make_shared<QTensorNetwork>(engines, args...);
118 #if ENABLE_OPENCL
119  case QINTERFACE_OPENCL:
120  return std::make_shared<QEngineOCL>(args...);
121 #endif
122 #if ENABLE_CUDA
123  case QINTERFACE_CUDA:
124  return std::make_shared<QEngineCUDA>(args...);
125 #endif
126 #if ENABLE_OPENCL || ENABLE_CUDA
127  case QINTERFACE_HYBRID:
128  return std::make_shared<QHybrid>(args...);
130  return std::make_shared<QUnitMulti>(engines, args...);
131 #endif
132  default:
133  return NULL;
134  }
135 }
136 
137 template <typename... Ts> QInterfacePtr CreateQuantumInterface(QInterfaceEngine engine, Ts... args)
138 {
139  switch (engine) {
140  case QINTERFACE_CPU:
141  return std::make_shared<QEngineCPU>(args...);
143  return std::make_shared<QStabilizer>(args...);
145  return std::make_shared<QUnitClifford>(args...);
146 #if ENABLE_QBDT
147  case QINTERFACE_BDT:
148  return std::make_shared<QBdt>(args...);
150  return std::make_shared<QBdtHybrid>(args...);
151 #endif
152  case QINTERFACE_QPAGER:
153  return std::make_shared<QPager>(args...);
155  return std::make_shared<QStabilizerHybrid>(args...);
156  case QINTERFACE_QUNIT:
157  return std::make_shared<QUnit>(args...);
159  return std::make_shared<QTensorNetwork>(args...);
160 #if ENABLE_OPENCL
161  case QINTERFACE_OPENCL:
162  return std::make_shared<QEngineOCL>(args...);
163 #endif
164 #if ENABLE_CUDA
165  case QINTERFACE_CUDA:
166  return std::make_shared<QEngineCUDA>(args...);
167 #endif
168 #if ENABLE_OPENCL || ENABLE_CUDA
169  case QINTERFACE_HYBRID:
170  return std::make_shared<QHybrid>(args...);
172  return std::make_shared<QUnitMulti>(args...);
173 #endif
174  default:
175  return NULL;
176  }
177 }
178 
179 template <typename... Ts> QInterfacePtr CreateQuantumInterface(std::vector<QInterfaceEngine> engines, Ts... args)
180 {
181  QInterfaceEngine engine = engines[0];
182  engines.erase(engines.begin());
183 
184  switch (engine) {
185  case QINTERFACE_CPU:
186  return std::make_shared<QEngineCPU>(args...);
188  return std::make_shared<QStabilizer>(args...);
190  return std::make_shared<QUnitClifford>(args...);
191 #if ENABLE_QBDT
192  case QINTERFACE_BDT:
193  if (engines.size()) {
194  return std::make_shared<QBdt>(engines, args...);
195  }
196  return std::make_shared<QBdt>(args...);
198  if (engines.size()) {
199  return std::make_shared<QBdtHybrid>(engines, args...);
200  }
201  return std::make_shared<QBdtHybrid>(args...);
202 #endif
203  case QINTERFACE_QPAGER:
204  if (engines.size()) {
205  return std::make_shared<QPager>(engines, args...);
206  }
207  return std::make_shared<QPager>(args...);
209  if (engines.size()) {
210  return std::make_shared<QStabilizerHybrid>(engines, args...);
211  }
212  return std::make_shared<QStabilizerHybrid>(args...);
213  case QINTERFACE_QUNIT:
214  if (engines.size()) {
215  return std::make_shared<QUnit>(engines, args...);
216  }
217  return std::make_shared<QUnit>(args...);
219  if (engines.size()) {
220  return std::make_shared<QTensorNetwork>(engines, args...);
221  }
222  return std::make_shared<QTensorNetwork>(args...);
223 #if ENABLE_OPENCL
224  case QINTERFACE_OPENCL:
225  return std::make_shared<QEngineOCL>(args...);
226 #endif
227 #if ENABLE_CUDA
228  case QINTERFACE_CUDA:
229  return std::make_shared<QEngineCUDA>(args...);
230 #endif
231 #if ENABLE_OPENCL || ENABLE_CUDA
232  case QINTERFACE_HYBRID:
233  return std::make_shared<QHybrid>(args...);
235  if (engines.size()) {
236  return std::make_shared<QUnitMulti>(engines, args...);
237  }
238  return std::make_shared<QUnitMulti>(args...);
239 #endif
240  default:
241  return NULL;
242  }
243 }
244 
245 #if ENABLE_OPENCL
246 #define DEVICE_COUNT (OCLEngine::Instance().GetDeviceCount())
247 #elif ENABLE_CUDA
248 #define DEVICE_COUNT (CUDAEngine::Instance().GetDeviceCount())
249 #endif
250 template <typename... Ts>
251 QInterfacePtr CreateArrangedLayers(bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
252 {
253 #if ENABLE_OPENCL || ENABLE_CUDA
254  bool isOcl = oc && (DEVICE_COUNT > 0);
255  bool isOclMulti = oc && md && (DEVICE_COUNT > 1);
256 #else
257  bool isOclMulti = false;
258 #endif
259 
260  // Construct backwards, then reverse:
261  std::vector<QInterfaceEngine> simulatorType;
262 
263 #if ENABLE_OPENCL
264  if (!hy) {
265  simulatorType.push_back(isOcl ? QINTERFACE_OPENCL : QINTERFACE_CPU);
266  }
267 #elif ENABLE_CUDA
268  if (!hy) {
269  simulatorType.push_back(isOcl ? QINTERFACE_CUDA : QINTERFACE_CPU);
270  }
271 #endif
272 
273  if (pg && simulatorType.size()) {
274  simulatorType.push_back(QINTERFACE_QPAGER);
275  }
276 
277 #if ENABLE_QBDT
278  if (bdt) {
279  simulatorType.push_back(QINTERFACE_BDT_HYBRID);
280  }
281 #endif
282 
283  if (sh && (!sd || simulatorType.size())) {
284  simulatorType.push_back(QINTERFACE_STABILIZER_HYBRID);
285  }
286 
287  if (sd) {
288  simulatorType.push_back(isOclMulti ? QINTERFACE_QUNIT_MULTI : QINTERFACE_QUNIT);
289  }
290 
291  if (tn) {
292  simulatorType.push_back(QINTERFACE_TENSOR_NETWORK);
293  }
294 
295  // (...then reverse:)
296  std::reverse(simulatorType.begin(), simulatorType.end());
297 
298  if (!simulatorType.size()) {
299 #if ENABLE_OPENCL || ENABLE_CUDA
300  if (hy && isOcl) {
301  simulatorType.push_back(QINTERFACE_HYBRID);
302  } else {
303 #if ENABLE_OPENCL
304  simulatorType.push_back(isOcl ? QINTERFACE_OPENCL : QINTERFACE_CPU);
305 #else
306  simulatorType.push_back(isOcl ? QINTERFACE_CUDA : QINTERFACE_CPU);
307 #endif
308  }
309 #else
310  simulatorType.push_back(QINTERFACE_CPU);
311 #endif
312  }
313 
314  return CreateQuantumInterface(simulatorType, args...);
315 }
316 
317 } // namespace Qrack
Definition: complex16x2simd.hpp:25
QInterfaceEngine
Enumerated list of supported engines.
Definition: qinterface.hpp:50
@ QINTERFACE_QPAGER
Create a QPager, which breaks up the work of a QEngine into equally sized "pages.".
Definition: qinterface.hpp:95
@ QINTERFACE_CUDA
Create a QEngineCUDA, leveraging CUDA hardware to increase the speed of certain calculations.
Definition: qinterface.hpp:65
@ QINTERFACE_STABILIZER_HYBRID
Create a QStabilizerHybrid, switching between a QStabilizer and a QHybrid as efficient.
Definition: qinterface.hpp:90
@ QINTERFACE_HYBRID
Create a QHybrid, switching between QEngineCPU and QEngineOCL as efficient.
Definition: qinterface.hpp:70
@ QINTERFACE_BDT_HYBRID
Create a QBinaryDecisionTree, (CPU-based).
Definition: qinterface.hpp:80
@ QINTERFACE_BDT
Create a QBinaryDecisionTree, (CPU-based).
Definition: qinterface.hpp:75
@ QINTERFACE_TENSOR_NETWORK
Circuit-simplification layer, with (optional) recourse to cuTensorNetwork.
Definition: qinterface.hpp:120
@ QINTERFACE_QUNIT_CLIFFORD
Clifford-specialized QUnit.
Definition: qinterface.hpp:115
@ QINTERFACE_OPENCL
Create a QEngineOCL, leveraging OpenCL hardware to increase the speed of certain calculations.
Definition: qinterface.hpp:60
@ QINTERFACE_STABILIZER
Create a QStabilizer, limited to Clifford/Pauli operations, but efficient.
Definition: qinterface.hpp:85
@ QINTERFACE_QUNIT
Create a QUnit, which utilizes other QInterface classes to minimize the amount of work that's needed ...
Definition: qinterface.hpp:104
@ QINTERFACE_QUNIT_MULTI
Create a QUnitMulti, which distributes the explicitly separated "shards" of a QUnit across available ...
Definition: qinterface.hpp:110
@ QINTERFACE_CPU
Create a QEngineCPU leveraging only local CPU and memory resources.
Definition: qinterface.hpp:55
std::shared_ptr< QInterface > QInterfacePtr
Definition: qinterface.hpp:28
QInterfacePtr CreateQuantumInterface(QInterfaceEngine engine1, QInterfaceEngine engine2, QInterfaceEngine engine3, Ts... args)
Factory method to create specific engine implementations.
Definition: qfactory.hpp:45
QInterfacePtr CreateArrangedLayers(bool md, bool sd, bool sh, bool bdt, bool pg, bool tn, bool hy, bool oc, Ts... args)
Definition: qfactory.hpp:251
void reverse(BidirectionalIterator first, BidirectionalIterator last, bitCapInt stride)