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