The Quantum Exact Simulation Toolkit v4.2.0
Loading...
Searching...
No Matches
initialisations.cpp
1/** @file
2 * API definitions for initialising Quregs into
3 * particular states. Note when a Qureg is GPU-
4 * accelerated, these functions only update the
5 * state in GPU memory; the CPU amps are unchanged.
6 *
7 * @author Tyson Jones
8 */
9
10#include "quest/include/qureg.h"
11#include "quest/include/calculations.h"
12#include "quest/include/initialisations.h"
13
14#include "quest/src/core/validation.hpp"
15#include "quest/src/core/localiser.hpp"
16#include "quest/src/core/utilities.hpp"
17#include "quest/src/core/bitwise.hpp"
18#include "quest/src/gpu/gpu_config.hpp"
19
20#include <algorithm>
21#include <cmath>
22#include <vector>
23
24using std::vector;
25
26
27
28/*
29 * C AND C++ AGNOSTIC FUNCTIONS
30 */
31
32// enable invocation by both C and C++ binaries
33extern "C" {
34
35
36/*
37 * INIT
38 */
39
40
41void initBlankState(Qureg qureg) {
42 validate_quregFields(qureg, __func__);
43
44 // |null> = {0, 0, 0, ...}
45 qcomp amp = 0;
46 localiser_statevec_initUniformState(qureg, amp);
47}
48
49
50void initZeroState(Qureg qureg) {
51 validate_quregFields(qureg, __func__);
52
53 // |0> = |0><0|
54 qindex ind = 0;
55 localiser_statevec_initClassicalState(qureg, ind);
56}
57
58
59void initPlusState(Qureg qureg) {
60 validate_quregFields(qureg, __func__);
61
62 // |+> = sum_i 1/sqrt(2^N) |i> where 2^N = numAmps
63 // |+><+| = sum_ij 1/2^N |i><j| where 2^N = sqrt(numAmps)
64 qcomp amp = 1.0 / std::sqrt(qureg.numAmps);
65 localiser_statevec_initUniformState(qureg, amp);
66}
67
68
69void initPureState(Qureg qureg, Qureg pure) {
70 validate_quregFields(qureg, __func__);
71 validate_quregFields(pure, __func__);
72 validate_quregCanBeInitialisedToPureState(qureg, pure, __func__);
73
74 (qureg.isDensityMatrix)?
75 localiser_densmatr_initPureState(qureg, pure):
76 localiser_statevec_setQuregToClone(qureg, pure);
77}
78
79
80void initClassicalState(Qureg qureg, qindex ind) {
81 validate_quregFields(qureg, __func__);
82 validate_basisStateIndex(qureg, ind, __func__);
83
84 // |ind><ind| = ||ind'>>
85 if (qureg.isDensityMatrix)
86 ind = util_getGlobalFlatIndex(qureg, ind, ind);
87
88 localiser_statevec_initClassicalState(qureg, ind);
89}
90
91
92void initDebugState(Qureg qureg) {
93 validate_quregFields(qureg, __func__);
94
95 localiser_statevec_initDebugState(qureg);
96}
97
98
99void initArbitraryPureState(Qureg qureg, qcomp* amps) {
100 validate_quregFields(qureg, __func__);
101
102 // set qureg = |amps> or |amps><amps|
103 (qureg.isDensityMatrix)?
104 localiser_densmatr_initArbitraryPureState(qureg, amps):
105 localiser_statevec_initArbitraryPureState(qureg, amps);
106}
107
108
109void initArbitraryMixedState(Qureg qureg, qcomp** amps) {
110 validate_quregFields(qureg, __func__);
111 validate_quregIsDensityMatrix(qureg, __func__);
112
113 localiser_densmatr_initArbitraryMixedState(qureg, amps);
114}
115
116
118 validate_quregFields(qureg, __func__);
119
120 // these invoked localiser functions may harmlessly
121 // re-call the API and re-perform input validation
122
123 if (qureg.isDensityMatrix)
124 localiser_densmatr_initUniformlyRandomPureStateAmps(qureg);
125 else {
126 localiser_statevec_initUnnormalisedUniformlyRandomPureStateAmps(qureg);
128 }
129}
130
131
132void initRandomMixedState(Qureg qureg, qindex numPureStates) {
133 validate_quregFields(qureg, __func__);
134 validate_quregIsDensityMatrix(qureg, __func__);
135 validate_numInitRandomPureStates(numPureStates, __func__);
136
137 localiser_densmatr_initMixtureOfUniformlyRandomPureStates(qureg, numPureStates);
138}
139
140
141
142/*
143 * SET
144 */
145
146
147void setQuregAmps(Qureg qureg, qindex startInd, qcomp* amps, qindex numAmps) {
148 validate_quregFields(qureg, __func__);
149 validate_quregIsStateVector(qureg, __func__);
150 validate_basisStateIndices(qureg, startInd, numAmps, __func__);
151
152 localiser_statevec_setAmps(amps, qureg, startInd, numAmps);
153}
154
155
156void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qcomp** amps, qindex numRows, qindex numCols) {
157 validate_quregFields(qureg, __func__);
158 validate_quregIsDensityMatrix(qureg, __func__);
159 validate_basisStateRowCols(qureg, startRow, startCol, numRows, numCols, __func__);
160
161 localiser_densmatr_setAmps(amps, qureg, startRow, startCol, numRows, numCols);
162}
163
164
165void setDensityQuregFlatAmps(Qureg qureg, qindex startInd, qcomp* amps, qindex numAmps) {
166 validate_quregFields(qureg, __func__);
167 validate_quregIsDensityMatrix(qureg, __func__);
168 validate_basisStateIndices(qureg, startInd, numAmps, __func__); // validation msg correct for density-matrix
169
170 localiser_statevec_setAmps(amps, qureg, startInd, numAmps);
171}
172
173
174void setQuregToClone(Qureg outQureg, Qureg inQureg) {
175 validate_quregFields(outQureg, __func__);
176 validate_quregFields(inQureg, __func__);
177 validate_quregsCanBeCloned(outQureg, inQureg, __func__);
178
179 // we invoke mixing/superposing, which involves superfluous
180 // floating-point operators but is not expected to cause an
181 // appreciable slowdown since simulation is often memory-bound
182 (outQureg.isDensityMatrix)?
183 localiser_densmatr_mixQureg(0, outQureg, 1, inQureg):
184 localiser_statevec_setQuregToClone(outQureg, inQureg);
185}
186
187
189 validate_quregFields(qureg, __func__);
190
191 qreal prob = calcTotalProb(qureg); // harmlessly re-validates
192 validate_quregRenormProbIsNotZero(prob, __func__);
193
194 qreal norm = (qureg.isDensityMatrix)? prob : std::sqrt(prob);
195 qreal fac = 1 / norm;
196 localiser_statevec_scaleAmps(qureg, fac);
197
198 return fac;
199}
200
201
203 validate_quregFields(qureg, __func__);
204 validate_quregIsDensityMatrix(qureg, __func__);
205 validate_pauliStrSumFields(sum, __func__);
206 validate_pauliStrSumTargets(sum, qureg, __func__);
207
208 // sum is permitted to be non-Hermitian, since Hermiticity
209 // is insufficient to ensure qureg would be physical/valid
210
211 localiser_densmatr_setAmpsToPauliStrSum(qureg, sum);
212}
213
214
215void setQuregToPartialTrace(Qureg out, Qureg in, int* traceOutQubits, int numTraceQubits) {
216 validate_quregFields(in, __func__);
217 validate_quregFields(out, __func__);
218 validate_quregIsDensityMatrix(in, __func__);
219 validate_quregIsDensityMatrix(out, __func__);
220 validate_targets(in, traceOutQubits, numTraceQubits, __func__);
221 validate_quregCanBeSetToReducedDensMatr(out, in, numTraceQubits, __func__);
222
223 auto targets = util_getVector(traceOutQubits, numTraceQubits);
224 localiser_densmatr_partialTrace(in, out, targets);
225}
226
227
228void setQuregToReducedDensityMatrix(Qureg out, Qureg in, int* retainQubits, int numRetainQubits) {
229 validate_quregFields(in, __func__);
230 validate_quregFields(out, __func__);
231 validate_quregIsDensityMatrix(in, __func__);
232 validate_quregIsDensityMatrix(out, __func__);
233 validate_targets(in, retainQubits, numRetainQubits, __func__);
234 validate_quregCanBeSetToReducedDensMatr(out, in, in.numQubits - numRetainQubits, __func__);
235
236 auto traceQubits = util_getNonTargetedQubits(retainQubits, numRetainQubits, in.numQubits);
237 localiser_densmatr_partialTrace(in, out, traceQubits);
238}
239
240
241void setQuregToWeightedSum(Qureg out, qcomp* coeffs, Qureg* in, int numIn) {
242 validate_quregFields(out, __func__);
243 validate_numQuregsInSum(numIn, __func__);
244 validate_quregsCanBeSummed(out, in, numIn, __func__); // also validates all init
245
246 auto coeffVec = util_getVector(coeffs, numIn);
247 auto inVec = util_getVector(in, numIn);
248 localiser_statevec_setQuregToWeightedSum(out, coeffVec, inVec);
249}
250
251
252void setQuregToMixture(Qureg out, qreal* probs, Qureg* in, int numIn) {
253 validate_quregFields(out, __func__);
254 validate_quregIsDensityMatrix(out, __func__);
255 validate_numQuregsInSum(numIn, __func__);
256 validate_quregsCanBeMixed(out, in, numIn, __func__); // also validates all init & densmatr
257 validate_probabilities(probs, numIn, __func__);
258
259 // convert probs to complex (assume this alloc never fails)
260 vector<qcomp> coeffVec(numIn);
261 for (int i=0; i<numIn; i++)
262 coeffVec[i] = getQcomp(probs[i], 0);
263
264 auto inVec = util_getVector(in, numIn);
265 localiser_statevec_setQuregToWeightedSum(out, coeffVec, inVec);
266}
267
268
269} // end de-mangler
270
271
272
273/*
274 * C++ OVERLOADS
275 */
276
277
278void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, vector<vector<qcomp>> amps) {
279
280 // C++-specific validation
281 validate_matrixRowsAllSameSize(amps, __func__);
282
283 // we must pass nested pointers to the C function, so alloc a vector
284 // of pointers of amps. We defensively check the temp vector allocates fine
285 vector<qcomp*> ptrs;
286 size_t len = amps.size();
287 auto callback = [&]() { validate_tempAllocSucceeded(false, len, sizeof(qcomp*), __func__); };
288 util_tryAllocVector(ptrs, len, callback);
289
290 // then set the pointers
291 for (size_t i=0; i<len; i++)
292 ptrs[i] = amps[i].data();
293
294 // C function performs main validation
295 setDensityQuregAmps(qureg, startRow, startCol, ptrs.data(), len, (len>0)? len : 0); // avoid seg-fault
296}
297
298void setQuregAmps(Qureg qureg, qindex startInd, vector<qcomp> amps) {
299 setQuregAmps(qureg, startInd, amps.data(), amps.size());
300}
301
302void setDensityQuregFlatAmps(Qureg qureg, qindex startInd, vector<qcomp> amps) {
303 setDensityQuregFlatAmps(qureg, startInd, amps.data(), amps.size());
304}
305
306void setQuregToPartialTrace(Qureg out, Qureg in, vector<int> traceOutQubits) {
307 setQuregToPartialTrace(out, in, traceOutQubits.data(), traceOutQubits.size());
308}
309
310void setQuregToReducedDensityMatrix(Qureg out, Qureg in, vector<int> retainQubits) {
311 setQuregToReducedDensityMatrix(out, in, retainQubits.data(), retainQubits.size());
312}
313
314void setQuregToWeightedSum(Qureg out, vector<qcomp> coeffs, vector<Qureg> in) {
315 validate_numQuregsMatchesCoeffs(in.size(), coeffs.size(), __func__);
316
317 setQuregToWeightedSum(out, coeffs.data(), in.data(), in.size());
318}
319
320void setQuregToMixture(Qureg out, vector<qreal> probs, vector<Qureg> in) {
321 validate_numQuregsMatchesProbs(in.size(), probs.size(), __func__);
322
323 setQuregToMixture(out, probs.data(), in.data(), in.size());
324}
qreal calcTotalProb(Qureg qureg)
void setDensityQuregFlatAmps(Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)
void setQuregToReducedDensityMatrix(Qureg out, Qureg in, int *retainQubits, int numRetainQubits)
void setQuregToWeightedSum(Qureg out, qcomp *coeffs, Qureg *in, int numIn)
void setQuregToPauliStrSum(Qureg qureg, PauliStrSum sum)
void setQuregToClone(Qureg outQureg, Qureg inQureg)
void setQuregToMixture(Qureg out, qreal *probs, Qureg *in, int numIn)
void setQuregAmps(Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)
void setQuregToPartialTrace(Qureg out, Qureg in, int *traceOutQubits, int numTraceQubits)
qreal setQuregToRenormalized(Qureg qureg)
void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qcomp **amps, qindex numRows, qindex numCols)
void initArbitraryPureState(Qureg qureg, qcomp *amps)
void initRandomPureState(Qureg qureg)
void initPlusState(Qureg qureg)
void initZeroState(Qureg qureg)
void initPureState(Qureg qureg, Qureg pure)
void initDebugState(Qureg qureg)
void initRandomMixedState(Qureg qureg, qindex numPureStates)
void initClassicalState(Qureg qureg, qindex ind)
void initBlankState(Qureg qureg)
static qcomp getQcomp(qreal re, qreal im)
Definition types.h:91
Definition qureg.h:49