forked from QuEST-Kit/QuEST
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpaulis.cpp
More file actions
293 lines (195 loc) · 8.24 KB
/
Copy pathpaulis.cpp
File metadata and controls
293 lines (195 loc) · 8.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/** @file
* API functions for creating PauliStr and PauliStrSum,
* and initialising and reporting them
*
* @author Tyson Jones
*/
#include "quest/include/precision.h"
#include "quest/include/paulis.h"
#include "quest/src/core/paulilogic.hpp"
#include "quest/src/core/validation.hpp"
#include "quest/src/core/utilities.hpp"
#include "quest/src/core/parser.hpp"
#include "quest/src/core/printer.hpp"
#include "quest/src/core/memory.hpp"
#include "quest/src/comm/comm_config.hpp"
#include "quest/src/comm/comm_routines.hpp"
#include "quest/src/cpu/cpu_config.hpp"
#include <vector>
#include <string>
using std::string;
using std::vector;
/*
* PRIVATE UTILITIES
*/
bool didAnyAllocsFailOnAnyNode(PauliStrSum sum) {
bool anyFail = (
! mem_isAllocated(sum.strings) ||
! mem_isAllocated(sum.coeffs) ||
! mem_isAllocated(sum.isApproxHermitian) );
if (comm_isInit())
anyFail = comm_isTrueOnAllNodes(anyFail);
return anyFail;
}
void freePauliStrSum(PauliStrSum sum) {
// these do not need to be allocated (freeing nullptr is legal)
cpu_deallocPauliStrings(sum.strings);
cpu_deallocArray(sum.coeffs);
util_deallocEpsilonSensitiveHeapFlag(sum.isApproxHermitian);
}
void freeAllMemoryIfAnyAllocsFailed(PauliStrSum sum) {
// do nothing if everything allocated successfully between all nodes
if (!didAnyAllocsFailOnAnyNode(sum))
return;
// otherwise free every successful allocation (freeing nullptr is legal)
freePauliStrSum(sum);
}
/*
* PAULI STRING INITIALISATION
*
* some of which are exposed directly to C, and some of which are C++-only overloads
*/
extern "C" PauliStr getPauliStr(const char* paulis, int* indices, int numPaulis) {
validate_newPauliStrParams(paulis, indices, numPaulis, MAX_NUM_PAULIS_PER_STR, __func__);
// begin masks at all-identity 'I' = 0
PAULI_MASK_TYPE lowPaulis = 0;
PAULI_MASK_TYPE highPaulis = 0;
// change targeted indices to the given Paulis
for (int i=0; i<numPaulis; i++) {
// cast single Pauli to full precision mask to enable below shifts
auto pauli = (PAULI_MASK_TYPE) parser_getPauliIntFromChar(paulis[i]);
// add the Pauli to either the lower or upper pauli masks
if (indices[i] < MAX_NUM_PAULIS_PER_MASK)
lowPaulis |= pauli << (2*indices[i]);
else
highPaulis |= pauli << (2*(indices[i] - MAX_NUM_PAULIS_PER_MASK));
}
// return a new stack PauliStr instance (avoiding C++20 initialiser)
PauliStr out;
out.lowPaulis = lowPaulis;
out.highPaulis = highPaulis;
return out;
}
PauliStr getPauliStr(int* paulis, int* indices, int numPaulis) {
validate_newPauliStrParams(paulis, indices, numPaulis, MAX_NUM_PAULIS_PER_STR, __func__);
// validation ensures never causes stack overflow
char pauliChars[MAX_NUM_PAULIS_PER_STR + 1]; // +1 for null-terminal
// make a char array from the pauli codes, using an arbitrary
// choice of the Pauli characters accepted by the API (like IXYZ)
for (int i=0; i<numPaulis; i++)
pauliChars[i] = "IXYZ"[paulis[i]];
// including the trailing null char, used to infer string end/length
pauliChars[numPaulis] = '\0';
return getPauliStr(pauliChars, indices, numPaulis);
}
extern "C" PauliStr _getPauliStrFromInts(int* paulis, int* indices, int numPaulis) {
return getPauliStr(paulis, indices, numPaulis);
}
PauliStr getPauliStr(string paulis, int* indices, int numPaulis) {
// additionally validate 'paulis' string has 'numPaulis' chars
validate_newPauliStrNumChars(paulis.length(), numPaulis, __func__);
return getPauliStr(paulis.data(), indices, numPaulis); // validates
}
PauliStr getPauliStr(string paulis, vector<int> indices) {
// additionally validate 'paulis' string has 'numPaulis' chars
validate_newPauliStrNumChars(paulis.length(), indices.size(), __func__);
return getPauliStr(paulis.data(), indices.data(), indices.size()); // validates
}
PauliStr getPauliStr(string paulis) {
// pedantically validate the string length isn't so long that it would stackoverflow a vector
validate_newPauliStrNumPaulis(paulis.size(), MAX_NUM_PAULIS_PER_STR, __func__);
// automatically target the lowest-index qubits, interpreting rightmost is least significant
vector<int> indices(paulis.size());
for (size_t i=0; i<paulis.size(); i++)
indices[i] = paulis.size() - 1 - i;
return getPauliStr(paulis, indices); // validates
}
/*
* PAULI STRING SUM CREATION
*
* some of which are exposed directly to C, and some of which are C++-only overloads
*/
extern "C" PauliStrSum createPauliStrSum(PauliStr* strings, qcomp* coeffs, qindex numTerms) {
// note we do not require nor impose the strings to be unique
validate_newPauliStrSumParams(numTerms, __func__);
// prepare output PauliStrSum (avoiding C++20 designated initialiser)
PauliStrSum out;
out.numTerms = numTerms;
out.strings = cpu_allocPauliStrings(numTerms); // nullptr if failed
out.coeffs = cpu_allocArray(numTerms); // nullptr if failed
out.isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(); // nullptr if failed
// if either alloc failed, clear both before validation to avoid leak
freeAllMemoryIfAnyAllocsFailed(out);
validate_newPauliStrSumAllocs(out, numTerms*sizeof(PauliStr), numTerms*sizeof(qcomp), __func__);
// otherwise copy given data into new heap structure, and set initial flags
cpu_copyPauliStrSum(out, strings, coeffs);
util_setFlagToUnknown(out.isApproxHermitian);
return out;
}
PauliStrSum createPauliStrSum(vector<PauliStr> strings, vector<qcomp> coeffs) {
// additionally validate 'strings' and 'coeffs' are the same length
validate_newPauliStrSumMatchingListLens(strings.size(), coeffs.size(), __func__);
return createPauliStrSum(strings.data(), coeffs.data(), coeffs.size()); // validates
}
extern "C" PauliStrSum createInlinePauliStrSum(const char* str) {
// str must be null-terminated
return createInlinePauliStrSum(string(str));
}
PauliStrSum createInlinePauliStrSum(string str) {
bool rightIsLeastSig = true;
return parser_validateAndParsePauliStrSum(str, rightIsLeastSig, __func__);
}
extern "C" PauliStrSum createPauliStrSumFromFile(const char* fn) {
// fn must be null-terminated
return createPauliStrSumFromFile(string(fn));
}
PauliStrSum createPauliStrSumFromFile(string fn) {
validate_canReadFile(fn, __func__);
// all distributed nodes will simultaneously read the file (that's fine)
string str = parser_loadFile(fn);
bool rightIsLeastSig = true;
return parser_validateAndParsePauliStrSum(str, rightIsLeastSig, __func__);
}
extern "C" PauliStrSum createPauliStrSumFromReversedFile(const char* fn) {
// fn must be null-terminated
return createPauliStrSumFromReversedFile(string(fn));
}
PauliStrSum createPauliStrSumFromReversedFile(string fn) {
validate_canReadFile(fn, __func__);
// all distributed nodes will simultaneously read the file (that's fine)
string str = parser_loadFile(fn);
bool rightIsLeastSig = false;
return parser_validateAndParsePauliStrSum(str, rightIsLeastSig, __func__);
}
/*
* DESTROYERS
*/
extern "C" void destroyPauliStrSum(PauliStrSum sum) {
validate_pauliStrSumFields(sum, __func__);
freePauliStrSum(sum);
}
/*
* API REPORTERS
*/
extern "C" void reportPauliStr(PauliStr str) {
// no header, so no indentation
string indent = "";
print_elemsWithoutNewline(str, indent);
// print all user-set newlines (including none)
print_newlines();
}
extern "C" void reportPauliStrSum(PauliStrSum sum) {
validate_pauliStrSumFields(sum, __func__);
validate_numReportedNewlinesAboveZero(__func__);
// calculate memory usage
qindex numStrBytes = sum.numTerms * sizeof *sum.strings;
qindex numCoeffBytes = sum.numTerms * sizeof *sum.coeffs;
qindex numStrucBytes = sizeof(sum);
// we don't bother checking for overflow since total memory scales
// linearly with user input parameters, unlike Qureg and matrices.
qindex numTotalBytes = numStrBytes + numCoeffBytes + numStrucBytes;
print_header(sum, numTotalBytes);
print_elems(sum);
// exclude mandatory newline above
print_oneFewerNewlines();
}