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