Skip to content

Commit 8213557

Browse files
committed
scaffolded HPC deployment
1 parent 1540702 commit 8213557

File tree

11 files changed

+272
-12
lines changed

11 files changed

+272
-12
lines changed

quest/include/operations.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@
77
#ifndef OPERATIONS_H
88
#define OPERATIONS_H
99

10+
#include "quest/include/qureg.h"
11+
#include "quest/include/structures.h"
1012

13+
// enable invocation by both C and C++ binaries
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
19+
20+
/*
21+
* GATES
22+
*/
23+
24+
void unitary(Qureg qureg, int target, CompMatr1 matrix);
25+
26+
27+
28+
// end de-mangler
29+
#ifdef __cplusplus
30+
}
31+
#endif
1132

1233
#endif // OPERATIONS_H

quest/src/api/operations.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,28 @@
22
* API definitions for effecting operators (such as gates and unitaries)
33
* upon Quregs which are instantiated as either statevectors or
44
* density matrices.
5-
*/
5+
*/
6+
7+
#include "quest/include/qureg.h"
8+
#include "quest/include/structures.h"
9+
10+
#include "quest/src/core/validation.hpp"
11+
#include "quest/src/core/utilities.hpp"
12+
#include "quest/src/core/localiser.hpp"
13+
14+
15+
// enable invocation by both C and C++ binaries
16+
extern "C" {
17+
18+
19+
void unitary(Qureg qureg, int target, CompMatr1 matrix) {
20+
validate_target(qureg, target, __func__);
21+
validate_matrixIsUnitary(matrix, __func__);
22+
23+
statevec_oneTargetGate(qureg, target, matrix);
24+
if (qureg.isDensityMatrix)
25+
statevec_oneTargetGate(qureg, util_getShifted(target, qureg), util_getConj(matrix));
26+
}
27+
28+
29+
} // end de-mangler

quest/src/core/accelerator.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,28 @@
66
* and location (qureg's amplitudes or buffer space), as is
77
* performed by localiser.cpp. These subroutines are ergo
88
* embarrassingly parallel.
9-
*/
9+
*/
10+
11+
#include "quest/include/qureg.h"
12+
#include "quest/include/structures.h"
13+
14+
#include "quest/src/cpu/cpu_subroutines.hpp"
15+
#include "quest/src/gpu/gpu_subroutines.hpp"
16+
17+
18+
19+
void statevec_oneTargetGate_subA(Qureg qureg, int target, CompMatr1 matrix) {
20+
21+
if (qureg.isGpuAccelerated)
22+
gpu_statevec_oneTargetGate_subA(qureg, target, matrix);
23+
else
24+
cpu_statevec_oneTargetGate_subA(qureg, target, matrix);
25+
26+
}
27+
void statevec_oneTargetGate_subB(Qureg qureg, qcomp fac0, qcomp fac1) {
28+
29+
if (qureg.isGpuAccelerated)
30+
gpu_statevec_oneTargetGate_subB(qureg, fac0, fac1);
31+
else
32+
cpu_statevec_oneTargetGate_subB(qureg, fac0, fac1);
33+
}

quest/src/core/accelerator.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111
#ifndef ACCELERATOR_HPP
1212
#define ACCELERATOR_HPP
1313

14+
#include "quest/include/qureg.h"
15+
#include "quest/include/structures.h"
16+
17+
18+
19+
void statevec_oneTargetGate_subA(Qureg qureg, int target, CompMatr1 matrix);
20+
21+
void statevec_oneTargetGate_subB(Qureg qureg, qcomp fac0, qcomp fac1);
22+
1423

1524

1625
#endif // ACCELERATOR_HPP

quest/src/core/localiser.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,53 @@
66
* embarrassingly parallel subroutines in accelerator.cpp. This is
77
* done agnostically of whether amplitudes of the Qureg are being
88
* stored in RAM (CPU) or VRAM (GPU).
9-
*/
9+
*/
10+
11+
#include "quest/include/qureg.h"
12+
#include "quest/include/structures.h"
13+
14+
#include "quest/src/comm/comm_routines.hpp"
15+
#include "quest/src/core/bitwise.hpp"
16+
#include "quest/src/core/accelerator.hpp"
17+
18+
19+
20+
/*
21+
* PRIVATE
22+
*/
23+
24+
25+
bool oneTargetGateRequiresComm(Qureg qureg, int target) {
26+
if (!qureg.isDistributed)
27+
return false;
28+
29+
return target >= qureg.logNumAmpsPerNode;
30+
}
31+
32+
33+
34+
/*
35+
* OPERATORS
36+
*/
37+
38+
39+
void statevec_oneTargetGate(Qureg qureg, int target, CompMatr1 matrix) {
40+
41+
if (!oneTargetGateRequiresComm(qureg, target))
42+
statevec_oneTargetGate_subA(qureg, target, matrix);
43+
44+
else {
45+
// exchange all amps (receive to buffer)
46+
int rankTarget = target - qureg.logNumAmpsPerNode;
47+
int pairRank = flipBit(qureg.rank, rankTarget);
48+
49+
comm_exchangeAmpsToBuffers(qureg, pairRank);
50+
51+
// extract relevant gate elements
52+
int bit = getBit(qureg.rank, rankTarget);
53+
qcomp fac0 = matrix.elems[bit][bit];
54+
qcomp fac1 = matrix.elems[bit][!bit];
55+
56+
statevec_oneTargetGate_subB(qureg, fac0, fac1);
57+
}
58+
}

quest/src/core/localiser.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@
1111
#ifndef LOCALISER_HPP
1212
#define LOCALISER_HPP
1313

14+
#include "quest/include/qureg.h"
15+
#include "quest/include/structures.h"
16+
17+
18+
19+
/*
20+
* OPERATORS
21+
*/
22+
23+
void statevec_oneTargetGate(Qureg qureg, int target, CompMatr1 matrix);
24+
1425

1526

1627
#endif // LOCALISER_HPP

quest/src/core/validation.cpp

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "quest/src/core/errors.hpp"
1212
#include "quest/src/core/bitwise.hpp"
1313
#include "quest/src/core/memory.hpp"
14+
#include "quest/src/core/utilities.hpp"
1415
#include "quest/src/comm/comm_config.hpp"
1516
#include "quest/src/cpu/cpu_config.hpp"
1617
#include "quest/src/gpu/gpu_config.hpp"
@@ -180,8 +181,17 @@ namespace report {
180181
std::string INVALID_EXISTING_ALLOC_OF_COMPLEX_MATRIX =
181182
"Invalid CompMatrN. One or more rows of the 2D elements array was seemingly unallocated.";
182183

183-
std::string INVALID_COMP_MATR_PROPERTIES =
184-
"Invalid CompMatrN. Targeted ${NUM_QUBITS} qubits and had a dimension of ${NUM_ROWS} x ${NUM_ROWS}.";
184+
std::string INVALID_COMP_MATR_1_FIELDS =
185+
"Invalid CompMatr1. Targeted ${NUM_QUBITS} qubits (instead of 1) and had a dimension of ${NUM_ROWS}x${NUM_ROWS} (instead of 2x2). It is likely this matrix was not initialised with getCompMatr1().";
186+
187+
std::string INVALID_COMP_MATR_2_FIELDS =
188+
"Invalid CompMatr2. Targeted ${NUM_QUBITS} qubits (instead of 2) and had a dimension of ${NUM_ROWS}x${NUM_ROWS} (instead of 4x4). It is likely this matrix was not initialised with getCompMatr2().";
189+
190+
std::string INVALID_COMP_MATR_N_FIELDS =
191+
"Invalid CompMatrN. Targeted ${NUM_QUBITS} qubits and had a dimension of ${NUM_ROWS}x${NUM_ROWS}. It is likely this matrix was not initialised with createCompMatrN().";
192+
193+
std::string MATRIX_NOT_UNITARY =
194+
"The given complex matrix was not (approximately) unitary.";
185195

186196

187197
/*
@@ -190,6 +200,14 @@ namespace report {
190200

191201
std::string INVALID_STATE_INDEX =
192202
"Classical state index ${STATE_IND} is invalid for the given ${NUM_QUBITS} qubit Qureg. Index must be greater than or equal to zero, and cannot equal nor exceed the number of unique classical states (2^${NUM_QUBITS} = ${NUM_STATES}).";
203+
204+
205+
/*
206+
* OPERATOR PARAMETERS
207+
*/
208+
209+
std::string INVALID_TARGET_QUBIT =
210+
"Invalid target qubit (${TARGET}). Must be greater than or equal to zero, and less than the number of qubits in the Qureg (${NUM_QUBITS}).";
193211
}
194212

195213

@@ -204,7 +222,6 @@ void default_invalidQuESTInputError(const char* msg, const char* func) {
204222
// safe to call even before MPI has been setup
205223
if (comm_getRank() == 0)
206224
std::cout
207-
<< std::endl
208225
<< "QuEST encountered a validation error during function '" << func << "':\n"
209226
<< msg << "\nExiting..."
210227
<< std::endl;
@@ -672,20 +689,52 @@ void validate_newOrExistingMatrixAllocs(CompMatrN matr, bool isNewMatr, const ch
672689
assertThat(matr.elems[r] != NULL, errMsg, caller);
673690
}
674691

675-
void validate_matrixInit(CompMatrN matr, const char* caller) {
692+
693+
/*
694+
* EXISTING MATRICES
695+
*/
696+
697+
template <class T>
698+
void assertMatrixFieldsAreValid(T matr, std::string errMsg, const char* caller) {
676699

677700
tokenSubs vars = {
678701
{"${NUM_QUBITS}", matr.numQubits},
679702
{"${NUM_ROWS}", matr.numRows}};
680703

681704
bool validDims = (matr.numQubits >= 1) && (matr.numRows == powerOf2(matr.numQubits));
682-
assertThat(validDims, report::INVALID_COMP_MATR_PROPERTIES, vars, caller);
705+
assertThat(validDims, errMsg, vars, caller);
706+
}
707+
708+
void validate_matrixInit(CompMatr1 matr, const char* caller) {
709+
assertMatrixFieldsAreValid(matr, report::INVALID_COMP_MATR_1_FIELDS, caller);
710+
}
711+
void validate_matrixInit(CompMatr2 matr, const char* caller) {
712+
assertMatrixFieldsAreValid(matr, report::INVALID_COMP_MATR_2_FIELDS, caller);
713+
}
714+
void validate_matrixInit(CompMatrN matr, const char* caller) {
715+
assertMatrixFieldsAreValid(matr, report::INVALID_COMP_MATR_N_FIELDS, caller);
716+
validate_newOrExistingMatrixAllocs(matr, false, caller);
717+
}
718+
719+
template <class T>
720+
void assertMatrixIsUnitary(T matr, const char* caller) {
683721

684-
bool isNewMatr = false;
685-
validate_newOrExistingMatrixAllocs(matr, isNewMatr, caller);
722+
validate_matrixInit(matr, caller);
723+
assertThat(util_isUnitary(matr), report::MATRIX_NOT_UNITARY, caller);
724+
}
725+
726+
void validate_matrixIsUnitary(CompMatr1 matr, const char* caller) {
727+
assertMatrixIsUnitary(matr, caller);
728+
}
729+
void validate_matrixIsUnitary(CompMatr2 matr, const char* caller) {
730+
assertMatrixIsUnitary(matr, caller);
731+
}
732+
void validate_matrixIsUnitary(CompMatrN matr, const char* caller) {
733+
assertMatrixIsUnitary(matr, caller);
686734
}
687735

688736

737+
689738
/*
690739
* QUREG INITIALISATIONS
691740
*/
@@ -701,3 +750,18 @@ void validate_initClassicalStateIndex(Qureg qureg, qindex ind, const char* calle
701750

702751
assertThat(ind >= 0 && ind < maxIndExcl, report::INVALID_STATE_INDEX, vars, caller);
703752
}
753+
754+
755+
756+
/*
757+
* OPERATOR PARAMETERS
758+
*/
759+
760+
void validate_target(Qureg qureg, int target, const char* caller) {
761+
762+
tokenSubs vars = {
763+
{"${TARGET}", target},
764+
{"${NUM_QUBITS}", qureg.numQubits}};
765+
766+
assertThat(target >= 0 && target < qureg.numQubits, report::INVALID_TARGET_QUBIT, vars, caller);
767+
}

quest/src/core/validation.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,14 @@ void validate_newOrExistingMatrixAllocs(CompMatrN matr, bool isNewMatr, const ch
6666
* EXISTING MATRIX
6767
*/
6868

69+
void validate_matrixInit(CompMatr1 matr, const char* caller);
70+
void validate_matrixInit(CompMatr2 matr, const char* caller);
6971
void validate_matrixInit(CompMatrN matr, const char* caller);
7072

73+
void validate_matrixIsUnitary(CompMatr1 matr, const char* caller);
74+
void validate_matrixIsUnitary(CompMatr2 matr, const char* caller);
75+
void validate_matrixIsUnitary(CompMatrN matr, const char* caller);
76+
7177

7278

7379
/*
@@ -78,4 +84,12 @@ void validate_initClassicalStateIndex(Qureg qureg, qindex ind, const char* calle
7884

7985

8086

87+
/*
88+
* OPERATOR PARAMETERS
89+
*/
90+
91+
void validate_target(Qureg qureg, int target, const char* caller);
92+
93+
94+
8195
#endif // VALIDATION_HPP

quest/src/cpu/cpu_subroutines.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,40 @@
33
* accelerator.cpp.
44
*/
55

6-
#include "quest/src/cpu/cpu_config.hpp"
6+
#include "quest/include/types.h"
7+
#include "quest/include/qureg.h"
8+
#include "quest/include/structures.h"
9+
10+
#include "quest/src/core/bitwise.hpp"
11+
12+
13+
14+
void cpu_statevec_oneTargetGate_subA(Qureg qureg, int target, CompMatr1 matrix) {
15+
16+
qindex numIts = qureg.numAmpsPerNode / 2;
17+
18+
qcomp m00 = matrix.elems[0][0];
19+
qcomp m01 = matrix.elems[0][1];
20+
qcomp m10 = matrix.elems[1][0];
21+
qcomp m11 = matrix.elems[1][1];
22+
23+
for (qindex j=0; j<numIts; j++) {
24+
25+
qindex i0 = insertBit(j, target, 0);
26+
qindex i1 = flipBit(i0, target);
27+
28+
qcomp amp0 = qureg.cpuAmps[i0];
29+
qcomp amp1 = qureg.cpuAmps[i1];
30+
31+
qureg.cpuAmps[i0] = m00*amp0 + m01*amp1;
32+
qureg.cpuAmps[i1] = m10*amp0 + m11*amp1;
33+
}
34+
}
35+
36+
void cpu_statevec_oneTargetGate_subB(Qureg qureg, qcomp fac0, qcomp fac1) {
37+
38+
qindex numIts = qureg.numAmpsPerNode;
39+
40+
for (qindex i=0; i<numIts; i++)
41+
qureg.cpuAmps[i] = fac0*qureg.cpuAmps[i] + fac1*qureg.cpuCommBuffer[i];
42+
}

0 commit comments

Comments
 (0)