8#include "quest/include/qureg.h"
9#include "quest/include/modes.h"
10#include "quest/include/environment.h"
11#include "quest/include/initialisations.h"
13#include "quest/src/core/validation.hpp"
14#include "quest/src/core/autodeployer.hpp"
15#include "quest/src/core/printer.hpp"
16#include "quest/src/core/bitwise.hpp"
17#include "quest/src/core/memory.hpp"
18#include "quest/src/core/utilities.hpp"
19#include "quest/src/core/localiser.hpp"
20#include "quest/src/comm/comm_config.hpp"
21#include "quest/src/comm/comm_routines.hpp"
22#include "quest/src/cpu/cpu_config.hpp"
23#include "quest/src/gpu/gpu_config.hpp"
38Qureg qureg_populateNonHeapFields(
int numQubits,
int isDensMatr,
int useDistrib,
int useGpuAccel,
int useMultithread) {
43 int logNumNodes = (useDistrib)?
44 logBase2(env.numNodes) : 0;
45 qindex logNumAmpsPerNode = (isDensMatr)?
46 (2*numQubits - logNumNodes) :
47 ( numQubits - logNumNodes);
53 out.isMultithreaded = useMultithread;
54 out.isGpuAccelerated = useGpuAccel;
55 out.isDistributed = useDistrib;
62 out.rank = (useDistrib)? env.rank : 0;
63 out.numNodes = (useDistrib)? env.numNodes : 1;
64 out.logNumNodes = (useDistrib)? logBase2(env.numNodes) : 0;
67 out.isDensityMatrix = isDensMatr;
68 out.numQubits = numQubits;
69 out.numAmps = (isDensMatr)? powerOf2(2*numQubits) : powerOf2(numQubits);
70 out.logNumAmps = (isDensMatr)? 2*numQubits : numQubits;
73 out.numAmpsPerNode = powerOf2(logNumAmpsPerNode);
74 out.logNumAmpsPerNode = logNumAmpsPerNode;
75 out.logNumColsPerNode = (isDensMatr)? numQubits - logNumNodes : 0;
78 out.cpuAmps =
nullptr;
79 out.gpuAmps =
nullptr;
80 out.cpuCommBuffer =
nullptr;
81 out.gpuCommBuffer =
nullptr;
93bool didAnyLocalAllocsFail(
Qureg qureg) {
96 if (! mem_isAllocated(qureg.cpuAmps))
100 if (qureg.isDistributed && ! mem_isAllocated(qureg.cpuCommBuffer))
104 if (qureg.isGpuAccelerated && ! mem_isAllocated(qureg.gpuAmps))
108 if (qureg.isDistributed && qureg.isGpuAccelerated && ! mem_isAllocated(qureg.gpuCommBuffer))
116bool didAnyAllocsFailOnAnyNode(
Qureg qureg) {
118 bool anyFail = didAnyLocalAllocsFail(qureg);
120 anyFail = comm_isTrueOnAllNodes(anyFail);
126void freeAllMemoryIfAnyAllocsFailed(
Qureg qureg) {
129 if (!didAnyAllocsFailOnAnyNode(qureg))
133 cpu_deallocArray(qureg.cpuAmps);
134 cpu_deallocArray(qureg.cpuCommBuffer);
137 if (qureg.isGpuAccelerated) {
138 gpu_deallocArray(qureg.gpuAmps);
139 gpu_deallocArray(qureg.gpuCommBuffer);
144Qureg validateAndCreateCustomQureg(
int numQubits,
int isDensMatr,
int useDistrib,
int useGpuAccel,
int useMultithread,
const char* caller) {
146 validate_envIsInit(caller);
150 validate_newQuregParams(numQubits, isDensMatr, useDistrib, useGpuAccel, useMultithread, env, caller);
153 autodep_chooseQuregDeployment(numQubits, isDensMatr, useDistrib, useGpuAccel, useMultithread, env);
155 Qureg qureg = qureg_populateNonHeapFields(numQubits, isDensMatr, useDistrib, useGpuAccel, useMultithread);
158 qureg.cpuAmps = cpu_allocNumaArray(qureg.numAmpsPerNode);
163 qureg.gpuAmps = (useGpuAccel)? gpu_allocArray(qureg.numAmpsPerNode) :
nullptr;
164 qureg.cpuCommBuffer = (useDistrib)? cpu_allocArray(qureg.numAmpsPerNode) :
nullptr;
165 qureg.gpuCommBuffer = (useGpuAccel && useDistrib)? gpu_allocArray(qureg.numAmpsPerNode) :
nullptr;
168 freeAllMemoryIfAnyAllocsFailed(qureg);
169 validate_newQuregAllocs(qureg, __func__);
174 if (useGpuAccel && gpu_isHipCompiled() && qureg.numAmpsPerNode >= (1LL << 32))
175 error_quregTooLargeForHipGpuAccel();
190void printDeploymentInfo(
Qureg qureg) {
194 {
"isMpiEnabled", qureg.isDistributed},
195 {
"isGpuEnabled", qureg.isGpuAccelerated},
196 {
"isOmpEnabled", qureg.isMultithreaded},
200void printDimensionInfo(
Qureg qureg) {
202 using namespace printer_substrings;
206 ampsStr = bt + printer_toStr(qureg.numQubits * (qureg.isDensityMatrix? 2 : 1));
207 ampsStr += eq + printer_toStr(qureg.numAmps);
210 if (qureg.isDensityMatrix)
212 bt + printer_toStr(qureg.numQubits) +
213 eq + printer_toStr(powerOf2(qureg.numQubits)));
217 {
"isDensMatr", printer_toStr(qureg.isDensityMatrix)},
218 {
"numQubits", printer_toStr(qureg.numQubits)},
219 {
"numCols", colsStr},
220 {
"numAmps", ampsStr},
225void printDistributionInfo(
Qureg qureg) {
227 using namespace printer_substrings;
230 string nodesStr = na;
235 if (qureg.isDistributed) {
236 nodesStr = bt + printer_toStr(qureg.logNumNodes) + eq + printer_toStr(qureg.numNodes);
237 ampsStr = bt + printer_toStr(qureg.logNumAmpsPerNode) + eq + printer_toStr(qureg.numAmpsPerNode) + pn;
238 if (qureg.isDensityMatrix)
239 colsStr = bt + printer_toStr(qureg.logNumColsPerNode) + eq + printer_toStr(powerOf2(qureg.logNumColsPerNode)) + pn;
244 {
"numNodes", nodesStr},
245 {
"numCols", colsStr},
246 {
"numAmps", ampsStr},
251void printMemoryInfo(
Qureg qureg) {
253 using namespace printer_substrings;
255 size_t localArrayMem = mem_getLocalQuregMemoryRequired(qureg.numAmpsPerNode);
256 string localMemStr = printer_getMemoryWithUnitStr(localArrayMem) + (qureg.isDistributed? pn :
"");
260 qindex globalTotalMem = mem_getTotalGlobalMemoryUsed(qureg);
261 string globalMemStr = (globalTotalMem == 0)?
"overflowed" : printer_getMemoryWithUnitStr(globalTotalMem);
265 {
"cpuAmps", mem_isAllocated(qureg.cpuAmps)? localMemStr : na},
266 {
"gpuAmps", mem_isAllocated(qureg.gpuAmps)? localMemStr : na},
267 {
"cpuCommBuffer", mem_isAllocated(qureg.cpuCommBuffer)? localMemStr : na},
268 {
"gpuCommBuffer", mem_isAllocated(qureg.gpuCommBuffer)? localMemStr : na},
269 {
"globalTotal", globalMemStr},
285 return validateAndCreateCustomQureg(numQubits, isDensMatr, useDistrib, useGpuAccel, useMultithread, __func__);
292 int autoMode = modeflag::USE_AUTO;
293 return validateAndCreateCustomQureg(numQubits, isDensMatr, autoMode, autoMode, autoMode, __func__);
300 int autoMode = modeflag::USE_AUTO;
301 return validateAndCreateCustomQureg(numQubits, isDensMatr, autoMode, autoMode, autoMode, __func__);
306 validate_envIsInit(__func__);
311 return validateAndCreateCustomQureg(numQubits, isDensMatr, env.isDistributed, env.isGpuAccelerated, env.isMultithreaded, __func__);
316 validate_envIsInit(__func__);
321 return validateAndCreateCustomQureg(numQubits, isDensMatr, env.isDistributed, env.isGpuAccelerated, env.isMultithreaded, __func__);
326 validate_quregFields(qureg, __func__);
329 Qureg clone = validateAndCreateCustomQureg(
330 qureg.numQubits, qureg.isDensityMatrix, qureg.isDistributed,
331 qureg.isGpuAccelerated, qureg.isMultithreaded, __func__);
341 validate_quregFields(qureg, __func__);
344 cpu_deallocNumaArray(qureg.cpuAmps, qureg.numAmpsPerNode);
347 if (qureg.isDistributed)
348 cpu_deallocArray(qureg.cpuCommBuffer);
351 if (qureg.isGpuAccelerated)
352 gpu_deallocArray(qureg.gpuAmps);
355 if (qureg.isGpuAccelerated && qureg.isDistributed)
356 gpu_deallocArray(qureg.gpuCommBuffer);
364 validate_quregFields(qureg, __func__);
365 validate_numReportedNewlinesAboveZero(__func__);
371 print_label(
"Qureg");
372 printDeploymentInfo(qureg);
373 printDimensionInfo(qureg);
374 printDistributionInfo(qureg);
375 printMemoryInfo(qureg);
378 print_oneFewerNewlines();
385 validate_quregFields(qureg, __func__);
386 validate_numReportedNewlinesAboveZero(__func__);
390 size_t localMem = mem_getLocalQuregMemoryRequired(qureg.numAmpsPerNode);
391 if (qureg.isDistributed)
395 localMem +=
sizeof(qureg);
399 print_header(qureg, localMem);
403 print_oneFewerNewlines();
410 validate_quregFields(qureg, __func__);
413 if (qureg.isGpuAccelerated)
414 gpu_copyCpuToGpu(qureg);
417 validate_quregFields(qureg, __func__);
420 if (qureg.isGpuAccelerated)
421 gpu_copyGpuToCpu(qureg);
426 validate_quregFields(qureg, __func__);
427 validate_localAmpIndices(qureg, localStartInd, numLocalAmps, __func__);
437 if (!qureg.isGpuAccelerated)
442 gpu_copyCpuToGpu(&qureg.cpuAmps[localStartInd], &qureg.gpuAmps[localStartInd], numLocalAmps);
445 validate_quregFields(qureg, __func__);
446 validate_localAmpIndices(qureg, localStartInd, numLocalAmps, __func__);
456 if (!qureg.isGpuAccelerated)
461 gpu_copyGpuToCpu(&qureg.gpuAmps[localStartInd], &qureg.cpuAmps[localStartInd], numLocalAmps);
466 validate_quregFields(qureg, __func__);
467 validate_quregIsStateVector(qureg, __func__);
468 validate_basisStateIndices(qureg, startInd, numAmps, __func__);
470 localiser_statevec_getAmps(outAmps, qureg, startInd, numAmps);
475 validate_quregFields(qureg, __func__);
476 validate_quregIsDensityMatrix(qureg, __func__);
477 validate_basisStateRowCols(qureg, startRow, startCol, numRows, numCols, __func__);
479 localiser_densmatr_getAmps(outAmps, qureg, startRow, startCol, numRows, numCols);
502 validate_quregFields(qureg, __func__);
503 validate_quregIsStateVector(qureg, __func__);
504 validate_basisStateIndex(qureg, index, __func__);
506 return localiser_statevec_getAmp(qureg, index);
508extern "C" void _wrap_getQuregAmp(qcomp* out,
Qureg qureg, qindex index) {
515 validate_quregFields(qureg, __func__);
516 validate_quregIsDensityMatrix(qureg, __func__);
517 validate_basisStateRowCol(qureg, row, column, __func__);
519 qindex ind = util_getGlobalFlatIndex(qureg, row, column);
520 qcomp amp = localiser_statevec_getAmp(qureg, ind);
523extern "C" void _wrap_getDensityQuregAmp(qcomp* out,
Qureg qureg, qindex row, qindex column) {
539 auto callback = [&]() { validate_tempListAllocSucceeded(
false, numAmps,
sizeof(qcomp), __func__); };
540 util_tryAllocVector(out, numAmps, callback);
551 vector<vector<qcomp>> out;
552 qindex numElems = numRows * numCols;
553 auto callback1 = [&]() { validate_tempListAllocSucceeded(
false, numElems,
sizeof(qcomp), __func__); };
554 util_tryAllocMatrix(out, numRows, numCols, callback1);
558 auto callback2 = [&]() { validate_tempListAllocSucceeded(
false, numRows,
sizeof(qcomp*), __func__); };
559 util_tryAllocVector(ptrs, numRows, callback2);
562 for (qindex i=0; i<numRows; i++)
563 ptrs[i] = out[i].data();
void setQuregToClone(Qureg outQureg, Qureg inQureg)
void initZeroState(Qureg qureg)
Qureg createDensityQureg(int numQubits)
Qureg createForcedQureg(int numQubits)
Qureg createForcedDensityQureg(int numQubits)
Qureg createCloneQureg(Qureg qureg)
Qureg createCustomQureg(int numQubits, int isDensMatr, int useDistrib, int useGpuAccel, int useMultithread)
Qureg createQureg(int numQubits)
void destroyQureg(Qureg qureg)
qcomp getQuregAmp(Qureg qureg, qindex index)
void getDensityQuregAmps(qcomp **outAmps, Qureg qureg, qindex startRow, qindex startCol, qindex numRows, qindex numCols)
void getQuregAmps(qcomp *outAmps, Qureg qureg, qindex startInd, qindex numAmps)
qcomp getDensityQuregAmp(Qureg qureg, qindex row, qindex column)
void reportQureg(Qureg qureg)
void reportQuregParams(Qureg qureg)
void syncQuregFromGpu(Qureg qureg)
void syncSubQuregToGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps)
void syncSubQuregFromGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps)
void syncQuregToGpu(Qureg qureg)