The Quantum Exact Simulation Toolkit v4.3.0
Loading...
Searching...
No Matches

Functions for overwriting Qureg amplitudes. More...

Functions

void setDensityQuregAmps (Qureg qureg, qindex startRow, qindex startCol, qcomp **amps, qindex numRows, qindex numCols)
 
void setDensityQuregFlatAmps (Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)
 
void setQuregAmps (Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)
 
void setQuregToClone (Qureg outQureg, Qureg inQureg)
 
void setQuregToMixture (Qureg out, qreal *probs, Qureg *in, int numIn)
 
void setQuregToPartialTrace (Qureg out, Qureg in, int *traceOutQubits, int numTraceQubits)
 
void setQuregToPauliStrSum (Qureg qureg, PauliStrSum sum)
 
void setQuregToReducedDensityMatrix (Qureg out, Qureg in, int *retainQubits, int numRetainQubits)
 
qreal setQuregToRenormalized (Qureg qureg)
 
void setQuregToWeightedSum (Qureg out, qcomp *coeffs, Qureg *in, int numIn)
 

Detailed Description

Functions for overwriting Qureg amplitudes.

Function Documentation

◆ setDensityQuregAmps()

void setDensityQuregAmps ( Qureg qureg,
qindex startRow,
qindex startCol,
qcomp ** amps,
qindex numRows,
qindex numCols )

Overwrites a rectangular block of density-matrix amplitudes.

  • Amplitudes outside the given block are unchanged.
  • There is no validation nor requirement that the new amplitudes, together with the remaining original amplitudes, produce a validly normalised density matrix. Normalization can be re-established with a subsequent call to setQuregToRenormalized().
  • When qureg is distributed, startRow, startCol, numRows and numCols are treated globally and use of this function is ergo agnostic to distribution. Therefore, every process should contain identical amps.
  • When qureg is GPU-accelerated, only its GPU amplitudes are updated.

The equivalent function for a statevector is setQuregAmps().

Formulae

Let \(\dmrho=\) qureg with \(N\) qubits, and with \((r,c)\)-th global amplitude \(\alpha_{r,c}\). Let \(s_r=\) startRow, \(s_c=\) startCol, \(n_r=\) numRows and \(n_c=\) numCols, and let \(\beta_{j,k}\) be the \((j,k)\)-th element of amps, i.e. amps[j][k].

This function overwrites qureg from

\[ \dmrho = \sum\limits_{r=0}^{2^N-1} \sum\limits_{c=0}^{2^N-1} \alpha_{r,c} \ket{r}\bra{c} \]

by modifying only the global rows \([s_r,s_r+n_r)\) and columns \([s_c,s_c+n_c)\), such that

\[ \alpha_{s_r+j,\,s_c+k} \rightarrow \beta_{j,k} \quad\quad \forall \; j \in [0,n_r), \; k \in [0,n_c). \]

Expressed as a matrix,

\[ \dmrho = \begin{pmatrix} \alpha_{0,0} & \alpha_{0,1} & \dots & \alpha_{0,2^N-1} \\ \alpha_{1,0} & \alpha_{1,1} & \\ \vdots & & \ddots \\ \alpha_{2^N-1,0} & & & \alpha_{2^N-1,2^N-1} \end{pmatrix}, \]

the state is modified to contain the sub-matrix below. Grey dots indicate \(\alpha_{ij}\) above.

\[ \def\x{{\color{gray}\circ}} \dmrho \rightarrow \begin{array}{c@{\;}c} & \hspace{0.5em} \overset{\scriptstyle [s_c,\,s_c+n_c)}{\overline{\hspace{10.5em}}} \hspace{-0.5em} \\[1ex] \lower1.0em\hbox{$ \scriptstyle [s_r,\,s_r+n_r) \quad \left\{\vphantom{\begin{matrix} \beta_{0,0} \\ \beta_{1,0} \\ \vdots \\ \beta_{n_r-1,0} \end{matrix}}\right. $} & \begin{pmatrix} \x & \x & \x & \x & \x & \x & \x \\ \x & \x & \x & \x & \x & \x & \x \\ \x & \x & \beta_{0,0} & \beta_{0,1} & \cdots & \beta_{0,n_c-1} & \x \\ \x & \x & \beta_{1,0} & \beta_{1,1} & \cdots & \beta_{1,n_c-1} & \x \\ \x & \x & \vdots & \vdots & \ddots & \vdots & \x \\ \x & \x & \beta_{n_r-1,0} & \beta_{n_r-1,1} & \cdots & \beta_{n_r-1,n_c-1} & \x \\ \x & \x & \x & \x & \x & \x & \x \end{pmatrix} \end{array} \]

Constraints
  • Argument qureg must be a density matrix, and ergo compatible with a 2D range. Statevectors can be overwritten at a 1D range with setQuregAmps(). Density matrices can also be overwritten with a 1D contiguous range when flattening the density matrix column-major with setDensityQuregFlatAmps().
Equivalences
  • When qureg is **_not_** distributed, this function is equivalent to manual modification of the CPU elements, followed by copies to GPU (except that this function does not modify Qureg::cpuAmps when qureg is not GPU-accelerated).
    for (qindex c=0; c<numCols; c++) {
    qindex flatInd = (startCol + c) * (1LL << qureg.numQubits) + startRow;
    for (qindex r=0; r<numRows; r++)
    qureg.cpuAmps[flatInd + r] = amps[r][c];
    syncSubQuregToGpu(qureg, flatInd, numRows);
    }
    // beware, syncQuregToGpu() would copy over stale, unmodified CPU amps
    // restore qureg.cpuAmps when !qureg.isGpuAccelerated
    void syncSubQuregToGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps)
    Definition qureg.cpp:425
  • When qureg is distributed, the logic is complicated by each specified global column range overlapping some, none or all of a node's partition. It follows the same pattern as demonstrated in setQuregAmps(), through column-wise linearisation of the density matrix.
  • When amps are within a single column (numCols==1), or span multiple full columns (numRows==(1<<qureg.numQubits)), this function becomes equivalent to calling setDensityQuregFlatAmps(), passing amps as a column-flattened 1D array.
Example
  • When numRows and numCols are sufficiently small such that the matrix amps can fit onto every distributed node, this function can be used in a manner totally agnostic to distribution and/or qureg deployments. In C++, an overload accepts amps as nested std::vector<qcomp>:

    std::vector<std::vector<qcomp>> amps = {
    {1, 2, 3},
    {4, 5, 6}};
    setDensityQuregAmps(qureg, startRow, startCol, amps, 2, 3);
    void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qcomp **amps, qindex numRows, qindex numCols)
    Qureg createDensityQureg(int numQubits)
    Definition qureg.cpp:297
    Definition qureg.h:49

    In C, amps must be a double pointer (and alas not an array):

    qcomp ampsArr[2][3] = {
    {1, 2, 3},
    {4, 5, 6}};
    qcomp* ampsPtr[] = {ampsArr[0], ampsArr[1]};
    setDensityQuregAmps(qureg, startRow, startCol, ampsPtr, 2, 3);
    void initBlankState(Qureg qureg)
  • When numRows or numCols is large, one can avoid the superfluous storing of all amps simultaneously, by repeatedly calling setDensityQuregAmps(), each time passing a tractable sub-block, regardless of how qureg is distributed.
    // global block
    const qindex startRow = 1234567;
    const qindex startCol = 7654321;
    const qindex totalNumRows = 1000000; // divides evenly into batches below
    const qindex totalNumCols = 1000000;
    // local memory budget
    const qindex batchNumRows = 100;
    const qindex batchNumCols = 200;
    // memory for a single batch
    qcomp** ampsBatch = ... // 2D malloc of size (batchNumRows, batchNumCols)
    for (qindex row=0; row<totalNumRows; row+=batchNumRows) {
    for (qindex col=0; col<totalNumCols; col+=batchNumCols) {
    // populate this two-dimensional batch
    for (qindex r=0; r<batchNumRows; r++)
    for (qindex c=0; c<batchNumCols; c++)
    amps[r][c] = ...
    qureg, startRow + row, startCol + col,
    ampsBatch, batchNumRows, batchNumCols);
    }
    }
Parameters
[in,out]quregthe density matrix to modify.
[in]startRowthe first global density-matrix row index to overwrite.
[in]startColthe first global density-matrix column index to overwrite.
[in]ampsa numRows by numCols matrix of amplitudes, as row-major nested pointers.
[in]numRowsthe total number of rows to overwrite.
[in]numColsthe total number of columns to overwrite.
Exceptions
error
  • if qureg is uninitialised.
  • if qureg is not a density matrix.
  • if startRow, startCol, numRows and numCols describe a block outside qureg.
See also
Attention
This function's input validation has not yet been unit tested, so erroneous usage may produce unexpected output. Please use with caution!
Author
Tyson Jones

Definition at line 157 of file initialisations.cpp.

157 {
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}

Referenced by TEST_CASE().

◆ setDensityQuregFlatAmps()

void setDensityQuregFlatAmps ( Qureg qureg,
qindex startInd,
qcomp * amps,
qindex numAmps )

Overwrites a contiguous range of density-matrix amplitudes, indexing qureg as a column-linearised form.

Formulae

Let \( \dmrho = \) qureg contain \(N\) qubits, with amplitudes \( \alpha_{ij} \).

\[ \dmrho = \sum\limits_i^{2^N} \sum\limits_j^{2^N} \alpha_{ij} \ket{i}\bra{j}. \]

Internally, this matrix of dimension \( 2^N \times 2^N \) is stored in a vectorised form \( \ket{\rho} \) of dimension \( 2^{2N} \times 1 \), which concatenates the columns of \( \dmrho \).

\[ \begin{aligned} \ket{\rho} &= \sum\limits_i^{2^N} \sum\limits_j^{2^N} \alpha_{ij} \ket{j} \ket{i} \\ &= \sum\limits_k^{2^{2N}} \beta_k \ket{k} \end{aligned} \]

Let \(s = \) startInd, \(n = \) numAmps, and \(\gamma_i = \) amps[i]. This function overwrites amplitudes \(\beta_k : s \le k < s + n \) with \(\gamma_k\).

Equivalences
  • This is equivalent to calling setQuregAmps() upon qureg, with identical parameters, when treating the column-wise linearised qureg as a statevector.
Parameters
[in,out]quregthe density matrix to modify.
[in]startIndthe first flattened, global index to overwrite.
[in]ampsan array of numAmps amplitudes.
[in]numAmpsthe number of flattened amplitudes to overwrite.
Exceptions
error
  • if qureg is uninitialised or is not a density matrix.
  • if startInd or numAmps describes a range outside the flattened matrix.
Attention
This function's input validation has not yet been unit tested, so erroneous usage may produce unexpected output. Please use with caution!
Author
Tyson Jones

Definition at line 166 of file initialisations.cpp.

166 {
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}

Referenced by TEST_CASE().

◆ setQuregAmps()

void setQuregAmps ( Qureg qureg,
qindex startInd,
qcomp * amps,
qindex numAmps )

Overwrites a contiguous range of statevector amplitudes.

  • Amplitudes outside the given range are unchanged.
  • There is no validation nor requirement that the new amplitudes, together with the remaining original amplitudes, produce a validly normalised state. Normalization can be re-established with a subsequent call to setQuregToRenormalized().
  • When qureg is distributed, startInd and numAmps are treated globally and use of this function is ergo agnostic to distribution. Therefore, every process should contain identical amps, although only elements which fall within a process' statevector partition will be consulted by a particular process.
  • When qureg is GPU-accelerated, only its GPU amplitudes are updated.

The equivalent function for a density matrix is setDensityQuregAmps().

Formulae

Let \(\svpsi=\) qureg with \(N\) qubits, and with \(i\)-th global amplitude \(\alpha_i\). Let \(s=\) startInd, \(n=\) numAmps, and let \(\beta_j\) be the \(j\)-th element of amps.

This function overwrites qureg from \(\svpsi=\sum_{i=0}^{2^N-1} \alpha_i \ket{i}\) to

\[ \svpsi \rightarrow \sum\limits_{i=0}^{s-1} \alpha_i \ket{i} + \sum\limits_{j=0}^{n-1} \beta_j \ket{j + s} + \sum\limits_{i=s+n}^{2^N-1} \alpha_i \ket{i} \]

where amplitudes at global indices in \([s,s+n)\) have been modified. Expressed as a row-vector,

\[ \svpsi = \begin{pmatrix} \alpha_0 & \alpha_1 & \dots & \alpha_{2^N-1} \end{pmatrix} \]

is modified to become

\[ \svpsi \rightarrow \begin{pmatrix} \alpha_0 & \alpha_1 & \dots & \alpha_{s-1} & \beta_0 & \beta_1 & \dots & \beta_{n-1} & \alpha_{s + n} & \dots & \alpha_{2^N-1} \end{pmatrix}. \]

Constraints
Equivalences
  • When qureg is **_not_** distributed, this function is equivalent to (but much faster than) manual modification of the CPU elements, followed by a copy to GPU (except that this function does not modify Qureg::cpuAmps when qureg is not GPU-accelerated).
    for (qindex i=0; i<numAmps; i++)
    qureg.cpuAmps[i + startInd] = amps[i];
    syncSubQuregToGpu(qureg, startInd, numAmps);
    // beware, syncQuregToGpu() would copy over stale, unmodified CPU amps
    // restore qureg.cpuAmps when !qureg.isGpuAccelerated
  • When qureg is distributed, the logic is complicated by the specified global range of amplitudes overlapping some, none or all of a node's partition.

    qcomp* amps[numAmps] = // global
    qindex dim = qureg.numAmpsPerNode;
    qindex endInd = startInd + numAmps;
    qindex nodeStartInd = (qureg.rank ) * dim;
    qindex nodeEndInd = (qureg.rank + 1) * dim;
    bool nodeContainsAmps = (startInd < nodeEndInd) && (endInd > nodeStartInd);
    qindex localStartInd = (startInd < nodeStartInd)? 0 : startInd % dim;
    qindex localEndInd = (endInd > nodeEndInd)? dim : endInd % dim;
    qindex numLocalAmps = nodeContainsAmps * (localEndInd - localStartInd);
    qindex nodeOffset = nodeStartInd + localStartInd - startInd;
    for (qindex i=0; i<numLocalAmps; i++)
    qureg.cpuAmps[localStartInd + i] = amps[nodeOffset + i]
    syncSubQuregToGpu(qureg, localStartInd, numLocalAmps);
    // restore qureg.cpuAmps when !qureg.isGpuAccelerated
Example
  • When numAmps is sufficiently small such that the array amps can fit onto every distributed node, this function can be used in a manner totally agnostic to distribution and/or qureg deployments.

    Qureg qureg = createQureg(35);
    qcomp amps[1000] = { ... };
    setQuregAmps(qureg, 300000000, amps, 1000);
    void setQuregAmps(Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)
    Qureg createQureg(int numQubits)
    Definition qureg.cpp:289
  • When numAmps is large, one can avoid the superfluous storing of all amps simultaneously, by repeatedly calling setQuregAmps(), each time passing a tractable sub-range, regardless of how qureg is distributed.
    Qureg qureg = createQureg(35);
    // global range
    const qindex startInd = 1234567;
    const qindex totalNumAmps = 1000000000; // 16 GB worth of double-prec qcomp
    // local memory budget
    const qindex batchSize = 10000000; // 160 MB worth
    qcomp amps[batchSize];
    int numBatches = totalNumAmps / batchSize; // divides evenly here for simplicity
    for (int batchInd=0; batchInd<numBatches; batchInd++) {
    // update amps, such that amps[i] is the desired amplitude
    // for global index (startInd + batchInd * batchSize)
    ...
    setQuregAmps(qureg, startInd + batchInd * batchSize, amps, batchSize);
    }
Parameters
[in,out]quregthe statevector to modify.
[in]startIndthe first global computational-basis index to overwrite.
[in]ampsan array of numAmps amplitudes.
[in]numAmpsthe total number of amplitudes to overwrite.
Exceptions
error
  • if qureg is uninitialised.
  • if qureg is not a statevector.
  • if startInd and numAmps describes a range outside qureg.
See also
Author
Tyson Jones

Definition at line 148 of file initialisations.cpp.

148 {
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}

Referenced by TEST_CASE(), and TEST_CASE().

◆ setQuregToClone()

void setQuregToClone ( Qureg outQureg,
Qureg inQureg )
Note
Documentation for this function or struct is under construction!
Warning
This function has not yet been unit tested and may contain bugs. Please use with caution!

Definition at line 175 of file initialisations.cpp.

175 {
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}

Referenced by createCloneQureg().

◆ setQuregToMixture()

void setQuregToMixture ( Qureg out,
qreal * probs,
Qureg * in,
int numIn )
Note
Documentation for this function or struct is under construction!
Warning
This function has not yet been unit tested and may contain bugs. Please use with caution!

Definition at line 253 of file initialisations.cpp.

253 {
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}
static qcomp getQcomp(qreal re, qreal im)
Definition types.h:91

◆ setQuregToPartialTrace()

void setQuregToPartialTrace ( Qureg out,
Qureg in,
int * traceOutQubits,
int numTraceQubits )
Note
Documentation for this function or struct is under construction!
Warning
This function has not yet been unit tested and may contain bugs. Please use with caution!

Definition at line 216 of file initialisations.cpp.

216 {
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}

◆ setQuregToPauliStrSum()

void setQuregToPauliStrSum ( Qureg qureg,
PauliStrSum sum )
Note
Documentation for this function or struct is under construction!
Attention
This function's input validation has not yet been unit tested, so erroneous usage may produce unexpected output. Please use with caution!

Definition at line 203 of file initialisations.cpp.

203 {
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}

Referenced by TEST_CASE().

◆ setQuregToReducedDensityMatrix()

void setQuregToReducedDensityMatrix ( Qureg out,
Qureg in,
int * retainQubits,
int numRetainQubits )
Note
Documentation for this function or struct is under construction!
Warning
This function has not yet been unit tested and may contain bugs. Please use with caution!

Definition at line 229 of file initialisations.cpp.

229 {
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}

◆ setQuregToRenormalized()

qreal setQuregToRenormalized ( Qureg qureg)
Note
Documentation for this function or struct is under construction!
Attention
This function's input validation has not yet been unit tested, so erroneous usage may produce unexpected output. Please use with caution!

Definition at line 189 of file initialisations.cpp.

189 {
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}
qreal calcTotalProb(Qureg qureg)

Referenced by initRandomPureState(), and TEST_CASE().

◆ setQuregToWeightedSum()

void setQuregToWeightedSum ( Qureg out,
qcomp * coeffs,
Qureg * in,
int numIn )
Note
Documentation for this function or struct is under construction!
Warning
This function has not yet been unit tested and may contain bugs. Please use with caution!

Definition at line 242 of file initialisations.cpp.

242 {
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}