Operators

Non-physical operators which may be non-unitary, non-norm-preserving, even non-Hermitian. More...

Functions

void applyDiagonalOp (Qureg qureg, DiagonalOp op)
 Apply a diagonal operator, which is possibly non-unitary and non-Hermitian, to the entire qureg. More...
 
void applyFullQFT (Qureg qureg)
 Applies the quantum Fourier transform (QFT) to the entirety of qureg. More...
 
void applyGateMatrixN (Qureg qureg, int *targs, int numTargs, ComplexMatrixN u)
 Apply a gate specified by a general N-by-N matrix, which may be non-unitary, on any number of target qubits. More...
 
void applyGateSubDiagonalOp (Qureg qureg, int *targets, int numTargets, SubDiagonalOp op)
 Apply a many-qubit unitary specified as a diagonal matrix upon a specific set of qubits of a quantum register. More...
 
void applyMatrix2 (Qureg qureg, int targetQubit, ComplexMatrix2 u)
 Apply a general 2-by-2 matrix, which may be non-unitary. More...
 
void applyMatrix4 (Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
 Apply a general 4-by-4 matrix, which may be non-unitary. More...
 
void applyMatrixN (Qureg qureg, int *targs, int numTargs, ComplexMatrixN u)
 Apply a general N-by-N matrix, which may be non-unitary, on any number of target qubits. More...
 
void applyMultiControlledMatrixN (Qureg qureg, int *ctrls, int numCtrls, int *targs, int numTargs, ComplexMatrixN u)
 Apply a general N-by-N matrix, which may be non-unitary, with additional controlled qubits. More...
 
void applyMultiVarPhaseFunc (Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int *numTermsPerReg)
 Induces a phase change upon each amplitude of qureg, determined by a multi-variable exponential polynomial "phase function". More...
 
void applyMultiVarPhaseFuncOverrides (Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int *numTermsPerReg, long long int *overrideInds, qreal *overridePhases, int numOverrides)
 Induces a phase change upon each amplitude of qureg, determined by a multi-variable exponential polynomial "phase function", and an explicit set of 'overriding' values at specific state indices. More...
 
void applyNamedPhaseFunc (Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode)
 Induces a phase change upon each amplitude of qureg, determined by a named (and potentially multi-variable) phase function. More...
 
void applyNamedPhaseFuncOverrides (Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, long long int *overrideInds, qreal *overridePhases, int numOverrides)
 Induces a phase change upon each amplitude of qureg, determined by a named (and potentially multi-variable) phase function, and an explicit set of 'overriding' values at specific state indices. More...
 
void applyParamNamedPhaseFunc (Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, qreal *params, int numParams)
 Induces a phase change upon each amplitude of qureg, determined by a named, paramaterized (and potentially multi-variable) phase function. More...
 
void applyParamNamedPhaseFuncOverrides (Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, qreal *params, int numParams, long long int *overrideInds, qreal *overridePhases, int numOverrides)
 Induces a phase change upon each amplitude of qureg, determined by a named, parameterised (and potentially multi-variable) phase function, and an explicit set of 'overriding' values at specific state indices. More...
 
void applyPauliHamil (Qureg inQureg, PauliHamil hamil, Qureg outQureg)
 Modifies outQureg to be the result of applying PauliHamil (a Hermitian but not necessarily unitary operator) to inQureg. More...
 
void applyPauliSum (Qureg inQureg, enum pauliOpType *allPauliCodes, qreal *termCoeffs, int numSumTerms, Qureg outQureg)
 Modifies outQureg to be the result of applying the weighted sum of Pauli products (a Hermitian but not necessarily unitary operator) to inQureg. More...
 
void applyPhaseFunc (Qureg qureg, int *qubits, int numQubits, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int numTerms)
 Induces a phase change upon each amplitude of qureg, determined by the passed exponential polynomial "phase function". More...
 
void applyPhaseFuncOverrides (Qureg qureg, int *qubits, int numQubits, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int numTerms, long long int *overrideInds, qreal *overridePhases, int numOverrides)
 Induces a phase change upon each amplitude of qureg, determined by the passed exponential polynomial "phase function", and an explicit set of 'overriding' values at specific state indices. More...
 
void applyProjector (Qureg qureg, int qubit, int outcome)
 Force the target qubit of qureg into the given classical outcome, via a non-renormalising projection. More...
 
void applyQFT (Qureg qureg, int *qubits, int numQubits)
 Applies the quantum Fourier transform (QFT) to a specific subset of qubits of the register qureg. More...
 
void applySubDiagonalOp (Qureg qureg, int *targets, int numTargets, SubDiagonalOp op)
 Left-apply a many-qubit a diagonal matrix upon a specific set of qubits of a quantum register. More...
 
void applyTrotterCircuit (Qureg qureg, PauliHamil hamil, qreal time, int order, int reps)
 Applies a trotterisation of unitary evolution \( \exp(-i \, \text{hamil} \, \text{time}) \) to qureg. More...
 

Detailed Description

Non-physical operators which may be non-unitary, non-norm-preserving, even non-Hermitian.

Function Documentation

◆ applyDiagonalOp()

void applyDiagonalOp ( Qureg  qureg,
DiagonalOp  op 
)

Apply a diagonal operator, which is possibly non-unitary and non-Hermitian, to the entire qureg.

Let \(d_j = \text{op.real}[j] + (\text{op.imag}[j])\,\text{i} \), and

\[ \hat{D} = \begin{pmatrix} d_0 \\ & d_1 \\ & & \ddots \\ & & & d_{2^{\text{op.numQubits}}-1} \end{pmatrix}. \]

If qureg is a state-vector \(|\psi\rangle\), this function performs \(|\psi\rangle \rightarrow \hat{D} \, |\psi\rangle\).
If qureg is a density-matrix \(\rho\), this function performs \(\rho \rightarrow \hat{D}\, \rho\). Notice this has not applied \(\hat{D}\) in the fashion of a unitary.

‍If your operator is unitary with unit amplitudes, the phases of which can be described by an analytic expression, you should instead use applyPhaseFunc() or applyNamedPhaseFunc() for significant memory and runtime savings.

‍To apply a diagonal operator upon a specific subset of qubits, use applySubDiagonalOp()

See also
Parameters
[in,out]quregthe state to operate the diagonal operator upon
[in]opthe diagonal operator to apply
Exceptions
invalidQuESTInputError()
  • if op was not created
  • if op acts on a different number of qubits than qureg represents
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyFullQFT()

void applyFullQFT ( Qureg  qureg)

Applies the quantum Fourier transform (QFT) to the entirety of qureg.

The effected unitary circuit (shown here for 4 qubits, bottom qubit is 0) resembles

though is performed more efficiently.

  • If qureg is a state-vector, the output amplitudes are the discrete Fourier transform (DFT) of the input amplitudes, in the exact ordering. This is true even if qureg is unnormalised.
    Precisely,

    \[ \text{QFT} \, \left( \sum\limits_{x=0}^{2^N-1} \alpha_x |x\rangle \right) = \frac{1}{\sqrt{2^N}} \sum\limits_{x=0}^{2^N-1} \left( \sum\limits_{y=0}^{2^N-1} e^{2 \pi \, i \, x \, y / 2^N} \; \alpha_y \right) |x\rangle \]

  • If qureg is a density matrix \(\rho\), it will be changed under the unitary action of the QFT. This can be imagined as each mixed state-vector undergoing the DFT on its amplitudes. This is true even if qureg is unnormalised.

    \[ \rho \; \rightarrow \; \text{QFT} \; \rho \; \text{QFT}^{\dagger} \]

‍This function merges contiguous controlled-phase gates into single invocations of applyNamedPhaseFunc(), and hence is significantly faster than performing the QFT circuit directly.

Furthermore, in distributed mode, this function requires only \(\log_2(\text{\#nodes})\) rounds of pair-wise communication, and hence is exponentially faster than directly performing the DFT on the amplitudes of qureg.

See also
  • applyQFT() to apply the QFT to a sub-register of qureg.
Parameters
[in,out]qurega state-vector or density matrix to modify
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyGateMatrixN()

void applyGateMatrixN ( Qureg  qureg,
int *  targs,
int  numTargs,
ComplexMatrixN  u 
)

Apply a gate specified by a general N-by-N matrix, which may be non-unitary, on any number of target qubits.

This function applies the given matrix to both statevector and density matrices as if it were a valid unitary gate. Hence this function is equivalent to multiQubitUnitary(), albeit the unitarity of u is not checked nor enforced. This function differs from applyMatrixN() on density matrices.

This function may leave qureg is an unnormalised state.

See also
Parameters
[in,out]quregobject representing the set of all qubits
[in]targsa list of the target qubits, ordered least significant to most in u
[in]numTargsthe number of target qubits
[in]umatrix to apply, which need not be unitary
Exceptions
invalidQuESTInputError()
  • if any index in targs is outside of [0, qureg.numQubitsRepresented)
  • if targs are not unique
  • if u is not of a compatible size with numTargs
  • if a node cannot fit the required number of target amplitudes in distributed mode
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyGateSubDiagonalOp()

void applyGateSubDiagonalOp ( Qureg  qureg,
int *  targets,
int  numTargets,
SubDiagonalOp  op 
)

Apply a many-qubit unitary specified as a diagonal matrix upon a specific set of qubits of a quantum register.

This is identical to function diagonalUnitary(), except here unitarity is not numerically checked nor enforced. That is, op is mathematically treated as if it were unitary despite its true unitarity. This is useful for numerically relaxing the precision of unitarity.

‍To apply the operator as if it were e.g. Hermitian, use applySubDiagonalOp().

See also
Parameters
[in,out]quregthe Qureg instance to operate upon
[in]targetsthe list of target qubit indices
[in]numTargetsthe length of list targets, which must match the dimension of op
[in]opa SubDiagonalOp initialised to any complex values
Exceptions
invalidQuESTInputError()
  • if numTargets does not match the size of op
  • if numTargets is invalid (<0 or larger than qureg)
  • if numTargets contains an invalid qubit index, or a repetition
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyMatrix2()

void applyMatrix2 ( Qureg  qureg,
int  targetQubit,
ComplexMatrix2  u 
)

Apply a general 2-by-2 matrix, which may be non-unitary.

The matrix is left-multiplied onto the state, for both state-vectors and density matrices.

Note this differs from the action of unitary() on a density matrix.

This function may leave qureg is an unnormalised state.

See also
Parameters
[in,out]quregobject representing the set of all qubits
[in]targetQubitqubit to operate u upon
[in]umatrix to apply
Exceptions
invalidQuESTInputError()
  • if targetQubit is outside [0, qureg.numQubitsRepresented)
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyMatrix4()

void applyMatrix4 ( Qureg  qureg,
int  targetQubit1,
int  targetQubit2,
ComplexMatrix4  u 
)

Apply a general 4-by-4 matrix, which may be non-unitary.

The matrix is left-multiplied onto the state, for both state-vectors and density matrices.

Note this differs from the action of twoQubitUnitary() on a density matrix.

targetQubit1 is treated as the least significant qubit in u, such that a row in u is dotted with the vector \( |\text{targetQubit2} \;\; \text{targetQubit1}\rangle : \{ |00\rangle, |01\rangle, |10\rangle, |11\rangle \} \)

For example,

applyMatrix4(qureg, a, b, u);
void applyMatrix4(Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general 4-by-4 matrix, which may be non-unitary.
Definition: QuEST.c:1124

will invoke multiplication

\[ \begin{pmatrix} u_{00} & u_{01} & u_{02} & u_{03} \\ u_{10} & u_{11} & u_{12} & u_{13} \\ u_{20} & u_{21} & u_{22} & u_{23} \\ u_{30} & u_{31} & u_{32} & u_{33} \end{pmatrix} \begin{pmatrix} |ba\rangle = |00\rangle \\ |ba\rangle = |01\rangle \\ |ba\rangle = |10\rangle \\ |ba\rangle = |11\rangle \end{pmatrix} \]

This function may leave qureg is an unnormalised state.

Note that in distributed mode, this routine requires that each node contains at least 4 amplitudes. This means an q-qubit register (state vector or density matrix) can be distributed by at most 2^q/4 nodes.

See also
Parameters
[in,out]quregobject representing the set of all qubits
[in]targetQubit1first qubit to operate on, treated as least significant in u
[in]targetQubit2second qubit to operate on, treated as most significant in u
[in]umatrix to apply
Exceptions
invalidQuESTInputError()
  • if targetQubit1 or targetQubit2 are outside [0, qureg.numQubitsRepresented)
  • if targetQubit1 equals targetQubit2
  • if each node cannot fit 4 amplitudes in distributed mode
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyMatrixN()

void applyMatrixN ( Qureg  qureg,
int *  targs,
int  numTargs,
ComplexMatrixN  u 
)

Apply a general N-by-N matrix, which may be non-unitary, on any number of target qubits.

The matrix is left-multiplied onto the state, for both state-vectors and density matrices. Note this differs from the action of multiQubitUnitary() on a density matrix.

The first target qubit in targs is treated as least significant in u. For example,

applyMatrixN(qureg, (int []) {a, b, c}, 3, u);
void applyMatrixN(Qureg qureg, int *targs, int numTargs, ComplexMatrixN u)
Apply a general N-by-N matrix, which may be non-unitary, on any number of target qubits.
Definition: QuEST.c:1134

will invoke multiplication

\[ \begin{pmatrix} u_{00} & u_{01} & u_{02} & u_{03} & u_{04} & u_{05} & u_{06} & u_{07} \\ u_{10} & u_{11} & u_{12} & u_{13} & u_{14} & u_{15} & u_{16} & u_{17} \\ u_{20} & u_{21} & u_{22} & u_{23} & u_{24} & u_{25} & u_{26} & u_{27} \\ u_{30} & u_{31} & u_{32} & u_{33} & u_{34} & u_{35} & u_{36} & u_{37} \\ u_{40} & u_{41} & u_{42} & u_{43} & u_{44} & u_{45} & u_{46} & u_{47} \\ u_{50} & u_{51} & u_{52} & u_{53} & u_{54} & u_{55} & u_{56} & u_{57} \\ u_{60} & u_{61} & u_{62} & u_{63} & u_{64} & u_{65} & u_{66} & u_{67} \\ u_{70} & u_{71} & u_{72} & u_{73} & u_{74} & u_{75} & u_{76} & u_{77} \\ \end{pmatrix} \begin{pmatrix} |cba\rangle = |000\rangle \\ |cba\rangle = |001\rangle \\ |cba\rangle = |010\rangle \\ |cba\rangle = |011\rangle \\ |cba\rangle = |100\rangle \\ |cba\rangle = |101\rangle \\ |cba\rangle = |110\rangle \\ |cba\rangle = |111\rangle \end{pmatrix} \]

This function may leave qureg is an unnormalised state.

The passed ComplexMatrix must be a compatible size with the specified number of target qubits, otherwise an error is thrown.

Note that in multithreaded mode, each thread will clone 2^numTargs amplitudes, and store these in the runtime stack. Using t threads, the total memory overhead of this function is t*2^numTargs. For many targets (e.g. 16 qubits), this may cause a stack-overflow / seg-fault (e.g. on a 1 MiB stack).

Note too that in distributed mode, this routine requires that each node contains at least 2^numTargs amplitudes in the register. This means an q-qubit register (state vector or density matrix) can be distributed by at most 2^q / 2^numTargs nodes.

See also
Parameters
[in,out]quregobject representing the set of all qubits
[in]targsa list of the target qubits, ordered least significant to most in u
[in]numTargsthe number of target qubits
[in]umatrix to apply
Exceptions
invalidQuESTInputError()
  • if any index in targs is outside of [0, qureg.numQubitsRepresented)
  • if targs are not unique
  • if u is not of a compatible size with numTargs
  • if a node cannot fit the required number of target amplitudes in distributed mode
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyMultiControlledMatrixN()

void applyMultiControlledMatrixN ( Qureg  qureg,
int *  ctrls,
int  numCtrls,
int *  targs,
int  numTargs,
ComplexMatrixN  u 
)

Apply a general N-by-N matrix, which may be non-unitary, with additional controlled qubits.

The matrix is left-multiplied onto the state, for both state-vectors and density matrices. Hence, this function differs from multiControlledMultiQubitUnitary() by more than just permitting a non-unitary matrix.

This function may leave qureg is an unnormalised state.

Any number of control and target qubits can be specified. This effects the many-qubit matrix

\[ \begin{pmatrix} 1 \\ & 1 \\\ & & \ddots \\ & & & u_{00} & u_{01} & \dots \\ & & & u_{10} & u_{11} & \dots \\ & & & \vdots & \vdots & \ddots \end{pmatrix} \]

on the control and target qubits.

The target qubits in targs are treated as ordered least significant to most significant in u.

The passed ComplexMatrix must be a compatible size with the specified number of target qubits, otherwise an error is thrown.

Note that in multithreaded mode, each thread will clone 2^numTargs amplitudes, and store these in the runtime stack. Using t threads, the total memory overhead of this function is t*2^numTargs. For many targets (e.g. 16 qubits), this may cause a stack-overflow / seg-fault (e.g. on a 1 MiB stack).

Note that in distributed mode, this routine requires that each node contains at least 2^numTargs amplitudes. This means an q-qubit register (state vector or density matrix) can be distributed by at most 2^q / 2^numTargs nodes.

Parameters
[in,out]quregobject representing the set of all qubits
[in]ctrlsa list of the control qubits
[in]numCtrlsthe number of control qubits
[in]targsa list of the target qubits, ordered least to most significant
[in]numTargsthe number of target qubits
[in]umatrix to apply
Exceptions
invalidQuESTInputError()
  • if any index in ctrls and targs is outside of [0, qureg.numQubitsRepresented)
  • if ctrls and targs are not unique
  • if matrix u is not a compatible size with numTargs
  • if a node cannot fit the required number of target amplitudes in distributed mode
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyMultiVarPhaseFunc()

void applyMultiVarPhaseFunc ( Qureg  qureg,
int *  qubits,
int *  numQubitsPerReg,
int  numRegs,
enum bitEncoding  encoding,
qreal coeffs,
qreal exponents,
int *  numTermsPerReg 
)

Induces a phase change upon each amplitude of qureg, determined by a multi-variable exponential polynomial "phase function".

This is a multi-variable extension of applyPhaseFunc(), whereby multiple sub-registers inform separate variables in the exponential polynomial function, and effects a diagonal unitary operator.

  • Arguments coeffs, exponents and numTermsPerReg together specify a real exponential polynomial \(f(\vec{r})\) of the form

    \[ f(r_1, \; \dots, \; r_{\text{numRegs}}) = \sum\limits_j^{\text{numRegs}} \; \sum\limits_{i}^{\text{numTermsPerReg}[j]} \; c_{i,j} \; {r_j}^{\; p_{i,j}}\,, \]

    where both coefficients \(c_{i,j}\) and exponents \(p_{i,j}\) can be any real number, subject to constraints described below.

    While coeffs and exponents are flat lists, they should be considered grouped into #numRegs sublists with lengths given by numTermsPerReg (which itself has length numRegs).

    For example,
    int numRegs = 3;
    qreal coeffs[] = {1, 2, 4, -3.14};
    qreal exponents[] = {2, 1, 5, 0.5 };
    int numTermsPerReg[] = {1, 2, 1 };
    #define qreal
    A precision-agnostic floating point number, as determined by QuEST_PREC.
    constitutes the function

    \[ f(\vec{r}) = 1 \, {r_1}^2 + 2 \, {r_2} + 4 \, {r_2}^{5} - 3.14 \, {r_3}^{0.5}. \]


    ‍This means lists coeffs and exponents should both be of length equal to the sum of numTermsPerReg. Unlike applyPhaseFunc(), applyMultiVarPhaseFunc() places additional constraints on the exponents in \(f(\vec{r})\), due to the exponentially growing costs of overriding diverging indices. Namely:

    1. exponents must not contain a negative number, since this would result in a divergence when that register is zero, which would need to be overriden for every other register basis state. If \(f(\vec{r})\) must contain a negative exponent, you should instead call applyPhaseFuncOverrides() once for each register/variable, and override the zero index for the relevant variable. This works, because

      \[ \exp( i \sum_j f_j(r_j) ) = \prod_j \exp(i f_j(r_j) ). \]

    2. exponents must not contain a fractional number if endoding = TWOS_COMPLEMENT, because such a term would produce illegal complex values at negative register indices. Similar to the problem above, each negative register index would require overriding at every index of the other registers, and hence require an exponential number of overrides. Therefore, if \(f(\vec{r})\) must contain a negative exponent, you should instead call applyPhaseFuncOverrides() once for each register/variable, and override every negative index of each register in turn.


  • Lists qubits and numQubitsPerReg together describe #numRegs sub-registers of qureg, which can each contain a different number of qubits.
    Although qubits is a flat list of unique qubit indices, it should be imagined grouped into #numRegs sub-lists, of lengths given by numQubitsPerReg.

    For example,
    int qubits[] = {0,1, 3,4,5, 7}
    int numQubitsPerReg[] = {2, 3, 1};
    int numRegs = 3;
    describes three sub-registers, which are bolded below in an eight-qubit zero-state.

    \[ |r_3\rangle \; |0\rangle \; |r_2\rangle \; |0\rangle \; |r_1\rangle = |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{00}\rangle \]

    Note that the qubits need not be ordered increasing, and qubits within each sub-register are assumed ordered least to most significant in that sub-register.

    ‍List qubits should have length equal to the sum of elements in numQubitsPerReg.

  • Each sub-register is associated with a variable \(r_j\) in phase function \(f(\vec{r})\).
    For a given computational basis state of qureg, the value of each variable is determined by the binary value in the corresponding sub-register, when intepreted with bitEncoding encoding.
    See bitEncoding for more information.

  • The function \(f(\vec{r})\) specifies the phase change to induce upon amplitude \(\alpha\) of computational basis state with the nominated sub-registers encoding values \(r_1, \; \dots\).

    \[ \alpha \, |r_{\text{numRegs}}, \; \dots, \; r_2, \; r_1 \rangle \rightarrow \, \exp(i f(\vec{r}\,)) \; \alpha \, |r_{\text{numRegs}}, \; \dots, \; r_2, \; r_1 \rangle. \]

    For example, using the sub-registers in the previous example and encoding = UNSIGNED, the following states receive amplitude factors:

    \[ \begin{aligned} |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{00}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=0)} \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{01}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=1)} \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{10}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=2)} \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{11}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=3)} \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |1\rangle \; |\mathbf{00}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=0)} \\ & \;\;\;\vdots \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{111}\rangle \; |0\rangle \; |\mathbf{01}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=7,r_1=1)} \\ & \;\;\;\vdots \\ |\mathbf{1}\rangle \; |0\rangle \; |\mathbf{111}\rangle \; |0\rangle \; |\mathbf{11}\rangle & \rightarrow \, e^{i f(r_3=1,r_2=7,r_1=3)} \end{aligned} \]

  • If qureg is a density matrix \(\rho\), then its elements are modified as

    \[ \alpha \, |j\rangle\langle k| \; \rightarrow \; \exp(i \, (f(\vec{r}_j) - f(\vec{r}_k)) \, ) \; \alpha \, |j\rangle\langle k|, \]

    where \(f(\vec{r}_j)\) and \(f(\vec{r}_k)\) are determined as above.

  • The interpreted phase function can be previewed in the QASM log, as a comment.
    For example:
    void applyMultiVarPhaseFunc(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int *numTermsPerReg)
    Induces a phase change upon each amplitude of qureg, determined by a multi-variable exponential polyn...
    Definition: QuEST.c:769
    void startRecordingQASM(Qureg qureg)
    Enable QASM recording.
    Definition: QuEST.c:87
    void printRecordedQASM(Qureg qureg)
    Print recorded QASM to stdout.
    Definition: QuEST.c:99
    would show, for the above example,
    // Here, applyMultiVarPhaseFunc() multiplied a complex scalar of the form
    // exp(i (
    // + 1 x^2
    // + 2 y + 4 y^(-1)
    // - 3.14 z^0.5 ))
    // upon substates informed by qubits (under an unsigned binary encoding)
    // |x> = {0, 1}
    // |y> = {3, 4, 5}
    // |z> = {7}

See also
Parameters
[in,out]quregthe state-vector or density matrix to be modified
[in]qubitsa list of all the qubit indices contained in each sub-register
[in]numQubitsPerRega list of the lengths of each sub-list in qubits
[in]numRegsthe number of sub-registers, which is the length of both numQubitsPerReg and numTermsPerReg
[in]encodingthe bitEncoding under which to infer the binary value \(r_j\) from the bits of a sub-register
[in]coeffsthe coefficients of all terms of the exponential polynomial phase function \(f(\vec{r})\)
[in]exponentsthe exponents of all terms of the exponential polynomial phase function \(f(\vec{r})\)
[in]numTermsPerRega list of the number of coeff and exponent terms supplied for each variable/sub-register
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits has an invalid index (i.e. does not satisfy 0 <= qubit < qureg.numQubitsRepresented)
  • if the elements of qubits are not unique (including if sub-registers overlap)
  • if numRegs <= 0 or numRegs > 100 (constrained by MAX_NUM_REGS_APPLY_ARBITRARY_PHASE in QuEST_precision.h)
  • if encoding is not a valid bitEncoding
  • if the size of any sub-register is incompatible with encoding (e.g. contains fewer than two qubits in encoding = TWOS_COMPLEMENT)
  • if any element of numTermsPerReg is < 1
  • if exponents contains a negative number
  • if exponents contains a fractional number despite encoding = TWOS_COMPLEMENT
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyMultiVarPhaseFuncOverrides()

void applyMultiVarPhaseFuncOverrides ( Qureg  qureg,
int *  qubits,
int *  numQubitsPerReg,
int  numRegs,
enum bitEncoding  encoding,
qreal coeffs,
qreal exponents,
int *  numTermsPerReg,
long long int *  overrideInds,
qreal overridePhases,
int  numOverrides 
)

Induces a phase change upon each amplitude of qureg, determined by a multi-variable exponential polynomial "phase function", and an explicit set of 'overriding' values at specific state indices.

See applyMultiVarPhaseFunc() first for a full description.

  • As in applyMultiVarPhaseFunc(), the arguments coeffs and exponents specify a multi-variable phase function \(f(\vec{r})\), where \(\vec{r}\) is determined by the sub-registers in qubits, and bitEncoding encoding for each basis state of qureg.

  • Additionally, overrideInds is a list of length numOverrides which specifies the values of \(\vec{r}\) for which to explicitly set the induced phase change.
    While flat, overrideInds should be imagined grouped into sub-lists of length numRegs, which specify the full \(\{r_1,\; \dots \;r_{\text{numRegs}} \} \) coordinate to override.
    Each sublist corresponds to a single element of overridePhases.
    For example,
    int numRegs = 3;
    int numOverrides = 2;
    long long int overrideInds[] = { 0,0,0, 1,2,3 };
    qreal overridePhases[] = { M_PI, - M_PI };
    denotes that any basis state of qureg with sub-register values \(\{r_3,r_2,r_1\} = \{0, 0, 0\}\) (or \(\{r_3,r_2,r_1\} = \{1,2,3\}\)) should receive phase change \(\pi\) (or \(-\pi\)) in lieu of \(\exp(i f(r_3=0,r_2=0,r_1=0))\).

    ‍Note that you cannot use applyMultiVarPhaseFuncOverrides() to override divergences in \(f(\vec{r})\), since each diverging value \(r_j\) would need to be overriden as an \(\vec{r}\) coordinate for every basis state of the other registers; the number of overrides grows exponentially. Ergo, if exponents contains a negative number (diverging at \(r_j=0\)), or exponents contains a fractional number despite encoding = TWOS_COMPLEMENT (producing complex phases at negative indices), you must instead call applyPhaseFuncOverrides() for each variable in turn and override the diverging \(r_j\) (each independently of the other registers).

  • The interpreted overrides can be previewed in the QASM log, as a comment.
    For example:
    void applyMultiVarPhaseFuncOverrides(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int *numTermsPerReg, long long int *overrideInds, qreal *overridePhases, int numOverrides)
    Induces a phase change upon each amplitude of qureg, determined by a multi-variable exponential polyn...
    Definition: QuEST.c:786
    may show
    // Here, applyMultiVarPhaseFunc() multiplied ...
    // though with overrides
    // |x=0, y=0, z=0> -> exp(i 3.14159)
    // |x=1, y=2, z=3> -> exp(i (-3.14159))

See also
Parameters
[in,out]quregthe state-vector or density-matrix to be modified
[in]qubitsa list of all the qubit indices contained in each sub-register
[in]numQubitsPerRega list of the lengths of each sub-list in qubits
[in]numRegsthe number of sub-registers, which is the length of both numQubitsPerReg and numTermsPerReg
[in]encodingthe bitEncoding under which to infer the binary value \(r_j\) from the bits of a sub-register
[in]coeffsthe coefficients of all terms of the exponential polynomial phase function \(f(\vec{r})\)
[in]exponentsthe exponents of all terms of the exponential polynomial phase function \(f(\vec{r})\)
[in]numTermsPerRega list of the number of coeff and exponent terms supplied for each variable/sub-register
[in]overrideIndsa flattened list of sub-register coordinates (values of \(\vec{r}\)) of which to explicit set the phase change
[in]overridePhasesa list of replacement phase changes, for the corresponding \(\vec{r}\) values in overrideInds
[in]numOverridesthe lengths of list overridePhases (but not necessarily of overrideInds)
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits has an invalid index (i.e. does not satisfy 0 <= qubit < qureg.numQubitsRepresented)
  • if the elements of qubits are not unique (including if sub-registers overlap)
  • if numRegs <= 0 or numRegs > 100 (constrained by MAX_NUM_REGS_APPLY_ARBITRARY_PHASE in QuEST_precision.h)
  • if encoding is not a valid bitEncoding
  • if the size of any sub-register is incompatible with encoding (e.g. contains fewer than two qubits in encoding = TWOS_COMPLEMENT)
  • if any element of numTermsPerReg is < 1
  • if exponents contains a negative number
  • if exponents contains a fractional number despite encoding = TWOS_COMPLEMENT
  • if any value in overrideInds is not producible by its corresponding sub-register under the given encoding (e.g. 2 unsigned qubits cannot represent index 9)
  • if numOverrides < 0
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyNamedPhaseFunc()

void applyNamedPhaseFunc ( Qureg  qureg,
int *  qubits,
int *  numQubitsPerReg,
int  numRegs,
enum bitEncoding  encoding,
enum phaseFunc  functionNameCode 
)

Induces a phase change upon each amplitude of qureg, determined by a named (and potentially multi-variable) phase function.

This effects a diagonal unitary operator, with a phase function \(f(\vec{r})\) which may not be simply expressible as an exponential polynomial in functions applyPhaseFunc() and applyMultiVarPhaseFunc().

Arguments qubits and numQubitsPerReg encode sub-registers of qureg in the same manner as in applyMultiVarPhaseFunc():

  • Lists qubits and numQubitsPerReg together describe #numRegs sub-registers of qureg, which can each contain a different number of qubits.
    Although qubits is a flat list of unique qubit indices, it should be imagined grouped into #numRegs sub-lists, of lengths given by numQubitsPerReg.

    For example,
    int qubits[] = {0,1, 3,4,5, 7}
    int numQubitsPerReg[] = {2, 3, 1};
    int numRegs = 3;
    describes three sub-registers, which are bolded below in an eight-qubit zero-state.

    \[ |r_3\rangle \; |0\rangle \; |r_2\rangle \; |0\rangle \; |r_1\rangle = |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{00}\rangle \]

    Note that the qubits need not be ordered increasing, and qubits within each sub-register are assumed ordered least to most significant in that sub-register.

    ‍List qubits should have length equal to the sum of elements in numQubitsPerReg.

  • Each sub-register is associated with a variable \(r_j\) in phase function \(f(\vec{r})\).
    For a given computational basis state of qureg, the value of each variable is determined by the binary value in the corresponding sub-register, when intepreted with bitEncoding encoding.
    See bitEncoding for more information.

  • Argument functionNameCode determines the phase function \(f(\vec{r})\).
    For example,
    int numRegs = 3;
    enum phaseFunc functionNameCode = NORM;
    phaseFunc
    Flags for specifying named phase functions.
    Definition: QuEST.h:249
    @ NORM
    Definition: QuEST.h:250
    describes phase function

    \[ f(\vec{r}) = \sqrt{ {r_1}^2 + {r_2}^2 + {r_3} ^2 }. \]

    See phaseFunc for a list and description of all named phase functions.
    Some phase functions, like SCALED_NORM, require passing additional parameters, through the function applyParamNamedPhaseFunc().

    ‍If the phase function \(f(\vec{r})\) diverges at one or more \(\vec{r}\) values, you should instead use applyNamedPhaseFuncOverrides() and specify explicit phase changes for these coordinates. Otherwise, the corresponding amplitudes of qureg will become indeterminate (like NaN).

  • The function \(f(\vec{r})\) specifies the phase change to induce upon amplitude \(\alpha\) of computational basis state with the nominated sub-registers encoding values \(r_1, \; \dots\).

    \[ \alpha \, |r_{\text{numRegs}}, \; \dots, \; r_2, \; r_1 \rangle \rightarrow \, \exp(i f(\vec{r}\,)) \; \alpha \, |r_{\text{numRegs}}, \; \dots, \; r_2, \; r_1 \rangle. \]

    For example, using the sub-registers in the above example and encoding = UNSIGNED, the following states receive amplitude factors:

    \[ \begin{aligned} |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{00}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=0)} \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{01}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=1)} \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{10}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=2)} \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |0\rangle \; |\mathbf{11}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=3)} \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{000}\rangle \; |1\rangle \; |\mathbf{00}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=0,r_1=0)} \\ & \;\;\;\vdots \\ |\mathbf{0}\rangle \; |0\rangle \; |\mathbf{111}\rangle \; |0\rangle \; |\mathbf{01}\rangle & \rightarrow \, e^{i f(r_3=0,r_2=7,r_1=1)} \\ & \;\;\;\vdots \\ |\mathbf{1}\rangle \; |0\rangle \; |\mathbf{111}\rangle \; |0\rangle \; |\mathbf{11}\rangle & \rightarrow \, e^{i f(r_3=1,r_2=7,r_1=3)} \end{aligned} \]


  • If qureg is a density matrix, its elements are modified to

    \[ \alpha \, |j\rangle\langle k| \; \rightarrow \; \exp(i (f(\vec{r}_j) \, - \, f(\vec{r}_k))) \; \alpha \, |j\rangle\langle k| \]

    where \(f(\vec{r}_j)\) and \(f(\vec{r}_k)\) are determined as above. This is equivalent to modification

    \[ \rho \; \rightarrow \; \hat{D} \, \rho \, \hat{D}^\dagger \]

    where \(\hat{D}\) is the diagonal unitary

    \[ \hat{D} = \text{diag}\, \{ \; e^{i f(\vec{r_0})}, \; e^{i f(\vec{r_1})}, \; \dots \; \}. \]


  • The interpreted phase function can be previewed in the QASM log, as a comment.
    For example:
    void applyNamedPhaseFunc(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode)
    Induces a phase change upon each amplitude of qureg, determined by a named (and potentially multi-var...
    Definition: QuEST.c:804
    @ INVERSE_DISTANCE
    Definition: QuEST.h:252
    may show
    // Here, applyNamedPhaseFunc() multiplied a complex scalar of form
    // exp(i 1 / sqrt((x-y)^2 + (z-t)^2))

See also
Parameters
[in,out]quregthe state-vector or density-matrix to be modified
[in]qubitsa list of all the qubit indices contained in each sub-register
[in]numQubitsPerRega list of the lengths of each sub-list in qubits
[in]numRegsthe number of sub-registers, which is the length of both numQubitsPerReg and numTermsPerReg
[in]encodingthe bitEncoding under which to infer the binary value \(r_j\) from the bits of a sub-register
[in]functionNameCodethe phaseFunc \(f(\vec{r})\)
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits has an invalid index (i.e. does not satisfy 0 <= qubit < qureg.numQubitsRepresented)
  • if the elements of qubits are not unique (including if sub-registers overlap)
  • if numRegs <= 0 or numRegs > 100 (constrained by MAX_NUM_REGS_APPLY_ARBITRARY_PHASE in QuEST_precision.h)
  • if encoding is not a valid bitEncoding
  • if the size of any sub-register is incompatible with encoding (e.g. contains fewer than two qubits in encoding = TWOS_COMPLEMENT)
  • if functionNameCode is not a valid phaseFunc
  • if functionNameCode requires additional parameters, which must instead be passed with applyParamNamedPhaseFunc()
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyNamedPhaseFuncOverrides()

void applyNamedPhaseFuncOverrides ( Qureg  qureg,
int *  qubits,
int *  numQubitsPerReg,
int  numRegs,
enum bitEncoding  encoding,
enum phaseFunc  functionNameCode,
long long int *  overrideInds,
qreal overridePhases,
int  numOverrides 
)

Induces a phase change upon each amplitude of qureg, determined by a named (and potentially multi-variable) phase function, and an explicit set of 'overriding' values at specific state indices.

See applyNamedPhaseFunc() first for a full description.

  • As in applyNamedPhaseFunc(), functionNameCode specifies a multi-variable phase function \(f(\vec{r})\), where \(\vec{r}\) is determined by the sub-registers in qubits, and bitEncoding encoding for each basis state of qureg.

  • Additionally, overrideInds is a list of length numOverrides which specifies the values of \(\vec{r}\) for which to explicitly set the induced phase change.
    While flat, overrideInds should be imagined grouped into sub-lists of length numRegs, which specify the full \(\{r_1,\; \dots \;r_{\text{numRegs}} \} \) coordinate to override.
    Each sublist corresponds to a single element of overridePhases.
    For example,
    int numRegs = 3;
    int numOverrides = 2;
    long long int overrideInds[] = { 0,0,0, 1,2,3 };
    qreal overridePhases[] = { M_PI, - M_PI };
    denotes that any basis state of qureg with sub-register values \(\{r_3,r_2,r_1\} = \{0, 0, 0\}\) (or \(\{r_3,r_2,r_1\} = \{1,2,3\}\)) should receive phase change \(\pi\) (or \(-\pi\)) in lieu of \(\exp(i f(r_3=0,r_2=0,r_1=0))\).

  • The interpreted overrides can be previewed in the QASM log, as a comment.
    For example:
    void applyNamedPhaseFuncOverrides(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, long long int *overrideInds, qreal *overridePhases, int numOverrides)
    Induces a phase change upon each amplitude of qureg, determined by a named (and potentially multi-var...
    Definition: QuEST.c:821
    may show
    // Here, applyNamedPhaseFunc() multiplied ...
    // though with overrides
    // |x=0, y=0, z=0> -> exp(i 3.14159)
    // |x=1, y=2, z=3> -> exp(i (-3.14159))

See also
Parameters
[in,out]quregthe state-vector pr density-matrix to be modified
[in]qubitsa list of all the qubit indices contained in each sub-register
[in]numQubitsPerRega list of the lengths of each sub-list in qubits
[in]numRegsthe number of sub-registers, which is the length of both numQubitsPerReg and numTermsPerReg
[in]encodingthe bitEncoding under which to infer the binary value \(r_j\) from the bits of a sub-register
[in]functionNameCodethe phaseFunc \(f(\vec{r})\)
[in]overrideIndsa flattened list of sub-register coordinates (values of \(\vec{r}\)) of which to explicit set the phase change
[in]overridePhasesa list of replacement phase changes, for the corresponding \(\vec{r}\) values in overrideInds
[in]numOverridesthe lengths of list overridePhases (but not necessarily of overrideInds)
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits has an invalid index (i.e. does not satisfy 0 <= qubit < qureg.numQubitsRepresented)
  • if the elements of qubits are not unique (including if sub-registers overlap)
  • if numRegs <= 0 or numRegs > 100 (constrained by MAX_NUM_REGS_APPLY_ARBITRARY_PHASE in QuEST_precision.h)
  • if encoding is not a valid bitEncoding
  • if the size of any sub-register is incompatible with encoding (e.g. contains fewer than two qubits in encoding = TWOS_COMPLEMENT)
  • if functionNameCode is not a valid phaseFunc
  • if functionNameCode requires additional parameters, which must instead be passed with applyParamNamedPhaseFunc()
  • if any value in overrideInds is not producible by its corresponding sub-register under the given encoding (e.g. 2 unsigned qubits cannot represent index 9)
  • if numOverrides < 0
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyParamNamedPhaseFunc()

void applyParamNamedPhaseFunc ( Qureg  qureg,
int *  qubits,
int *  numQubitsPerReg,
int  numRegs,
enum bitEncoding  encoding,
enum phaseFunc  functionNameCode,
qreal params,
int  numParams 
)

Induces a phase change upon each amplitude of qureg, determined by a named, paramaterized (and potentially multi-variable) phase function.

See applyNamedPhaseFunc() for full documentation.
This function merely accepts additional phaseFunc names which accept one (or more) parameters.

  • Argument functionNameCode, which determines the phase function \(f(\vec{r}, \vec{\theta})\), can include parameterised phaseFunc names like SCALED_NORM, which require additional parameters \(\vec{\theta}\) passed via list params.
    For example,
    enum phaseFunc functionNameCode = SCALED_PRODUCT;
    qreal params[] = {0.5};
    int numParams = 1;
    applyParamNamedPhaseFunc(..., functionNameCode, params, numParams);
    void applyParamNamedPhaseFunc(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, qreal *params, int numParams)
    Induces a phase change upon each amplitude of qureg, determined by a named, paramaterized (and potent...
    Definition: QuEST.c:839
    @ SCALED_PRODUCT
    Definition: QuEST.h:251
    invokes phase function

    \[ f(\vec{r}, \theta)|_{\theta=0.5} \; = \; 0.5 \prod_j^{\text{numRegs}} \; r_j\,. \]

    See phaseFunc for all named phased functions.
  • Functions with divergences, like INVERSE_NORM and SCALED_INVERSE_DISTANCE, must accompany an extra parameter to specify an overriding phase at the divergence. For example,
    enum phaseFunc functionNameCode = SCALED_INVERSE_NORM;
    qreal params[] = {0.5, M_PI};
    int numParams = 2;
    applyParamNamedPhaseFunc(..., functionNameCode, params, numParams);
    @ SCALED_INVERSE_NORM
    Definition: QuEST.h:250
    invokes phase function

    \[ f(\vec{r}, \theta)|_{\theta=0.5} \; = \; \begin{cases} \pi & \;\;\; \vec{r}=\vec{0} \\ \displaystyle 0.5 \left[ \sum_j^{\text{numRegs}} {r_j}^2 \right]^{-1/2} & \;\;\;\text{otherwise} \end{cases}. \]

    Notice the order of the parameters matches the order of the words in the phaseFunc.

    ‍Functions SCALED_INVERSE_SHIFTED_NORM and SCALED_INVERSE_SHIFTED_DISTANCE, which can have denominators arbitrarily close to zero, will invoke the divergence parameter whenever the denominator is smaller than (or equal to) machine precision REAL_EPS.

  • Functions allowing the shifting of unweighted sub-register values, which are SCALED_INVERSE_SHIFTED_NORM, and SCALED_INVERSE_SHIFTED_DISTANCE, need these shift values to be passed in the params argument after the scaling and divergence override parameters listed above. The function SCALED_INVERSE_SHIFTED_NORM needs as many extra parameters, as there are sub-registers; SCALED_INVERSE_SHIFTED_DISTANCE needs one extra parameter for each pair of sub-registers. For example,
    enum phaseFunc functionNameCode = SCALED_INVERSE_SHIFTED_NORM;
    int qubits[] = {0,1,2,3, 4,5,6,7};
    int qubitsPerReg[] = {4, 4};
    qreal params[] = {0.5, M_PI, 0.8, -0.3};
    int numParams = 4;
    applyParamNamedPhaseFunc(..., qubits, qubitsPerReg, 2, ..., functionNameCode, params, numParams);
    @ SCALED_INVERSE_SHIFTED_NORM
    Definition: QuEST.h:250
    invokes phase function

    \[ f(\vec{r}) \; = \; \begin{cases} \pi & \;\;\; \vec{r}=\vec{0} \\ \displaystyle 0.5 \left[(r_1-0.8)^2 + (r_2+0.3)^2\right]^{-1/2} & \;\;\;\text{otherwise} \end{cases}. \]

    and
    int qubits[] = {0,1, 2,3, 4,5, 6,7};
    int qubitsPerReg[] = {2, 2, 2, 2};
    qreal params[] = {0.5, M_PI, 0.8, -0.3};
    int numParams = 4;
    applyParamNamedPhaseFunc(..., qubits, qubitsPerReg, 4, ..., functionNameCode, params, numParams);
    @ SCALED_INVERSE_SHIFTED_DISTANCE
    Definition: QuEST.h:252
    invokes phase function

    \[ f(\vec{r}) \; = \; \begin{cases} \pi & \;\;\; \vec{r}=\vec{0} \\ \displaystyle 0.5 \left[(r_1-r_2-0.8)^2 + (r_3-r_4+0.3)^2\right]^{-1/2} & \;\;\;\text{otherwise} \end{cases}. \]

  • Function SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE, which effects phase

    \[ \text{coeff}/\sqrt{f_x \, (x_1-x_2-\Delta_x)^2 + f_y \; (y_1-y_2-\Delta_y)^2 + \dots} \]

    (and phase \(\phi\) at divergences) accepts parameters in the following order:

    \[ \{ \; \text{coeff}, \; \phi, \; f_x, \; \Delta x, \; f_y, \; \Delta y, \; \dots \; \} \]

    ‍Note that where the denominator's \(\text{sqrt}\) argument would be negative (and the resulting phase function complex), the phase is instead set to the divergence parameter \(\phi\).

    ‍You can further override \(f(\vec{r}, \vec{\theta})\) at one or more \(\vec{r}\) values via applyParamNamedPhaseFuncOverrides().

  • The interpreted parameterised phase function can be previewed in the QASM log, as a comment.
    For example: may show
    // Here, applyNamedPhaseFunc() multiplied a complex scalar of form
    // exp(i (-0.5) / (x y z))

See also
Parameters
[in,out]quregthe state-vector or density-matrix to be modified
[in]qubitsa list of all the qubit indices contained in each sub-register
[in]numQubitsPerRega list of the lengths of each sub-list in qubits
[in]numRegsthe number of sub-registers, which is the length of both numQubitsPerReg and numTermsPerReg
[in]encodingthe bitEncoding under which to infer the binary value \(r_j\) from the bits of a sub-register
[in]functionNameCodethe phaseFunc \(f(\vec{r}, \vec{\theta})\)
[in]paramsa list of any additional parameters needed by the phaseFunc functionNameCode
[in]numParamsthe length of list params
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits has an invalid index (i.e. does not satisfy 0 <= qubit < qureg.numQubitsRepresented)
  • if the elements of qubits are not unique (including if sub-registers overlap)
  • if numRegs <= 0 or numRegs > 100 (constrained by MAX_NUM_REGS_APPLY_ARBITRARY_PHASE in QuEST_precision.h)
  • if encoding is not a valid bitEncoding
  • if the size of any sub-register is incompatible with encoding (e.g. contains fewer than two qubits in encoding = TWOS_COMPLEMENT)
  • if functionNameCode is not a valid phaseFunc
  • if numParams is incompatible with functionNameCode (for example, no parameters were passed to SCALED_PRODUCT)
Author
Tyson Jones
Richard Meister (shifted functions)

Referenced by TEST_CASE().

◆ applyParamNamedPhaseFuncOverrides()

void applyParamNamedPhaseFuncOverrides ( Qureg  qureg,
int *  qubits,
int *  numQubitsPerReg,
int  numRegs,
enum bitEncoding  encoding,
enum phaseFunc  functionNameCode,
qreal params,
int  numParams,
long long int *  overrideInds,
qreal overridePhases,
int  numOverrides 
)

Induces a phase change upon each amplitude of qureg, determined by a named, parameterised (and potentially multi-variable) phase function, and an explicit set of 'overriding' values at specific state indices.

See applyParamNamedPhaseFunc() and applyNamedPhaseFunc() first for a full description.

  • As in applyParamNamedPhaseFunc(), functionNameCode specifies a parameterised multi-variable phase function \(f(\vec{r}, \vec{\theta})\), where \(\vec{\theta}\) is passed in list params, and \(\vec{r}\) is determined both by the sub-registers in qubits, and bitEncoding encoding for each basis state of qureg.

  • Additionally, overrideInds is a list of length numOverrides which specifies the values of \(\vec{r}\) for which to explicitly set the induced phase change.
    While flat, overrideInds should be imagined grouped into sub-lists of length numRegs, which specify the full \(\{r_1,\; \dots \;r_{\text{numRegs}} \} \) coordinate to override.
    Each sublist corresponds to a single element of overridePhases.
    For example,
    int numRegs = 3;
    int numOverrides = 2;
    long long int overrideInds[] = { 0,0,0, 1,2,3 };
    qreal overridePhases[] = { M_PI, - M_PI };
    denotes that any basis state of qureg with sub-register values \(\{r_3,r_2,r_1\} = \{0, 0, 0\}\) (or \(\{r_3,r_2,r_1\} = \{1,2,3\}\)) should receive phase change \(\pi\) (or \(-\pi\)) in lieu of \(\exp(i f(r_3=0,r_2=0,r_1=0, \vec{\theta}))\).

  • The interpreted overrides can be previewed in the QASM log, as a comment.
    For example:
    void applyParamNamedPhaseFuncOverrides(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, qreal *params, int numParams, long long int *overrideInds, qreal *overridePhases, int numOverrides)
    Induces a phase change upon each amplitude of qureg, determined by a named, parameterised (and potent...
    Definition: QuEST.c:856
    may show
    // Here, applyParamNamedPhaseFunc() multiplied ...
    // though with overrides
    // |x=0, y=0, z=0> -> exp(i 3.14159)
    // |x=1, y=2, z=3> -> exp(i (-3.14159))

See also
Parameters
[in,out]quregthe state-vector or density-matrix to be modified
[in]qubitsa list of all the qubit indices contained in each sub-register
[in]numQubitsPerRega list of the lengths of each sub-list in qubits
[in]numRegsthe number of sub-registers, which is the length of both numQubitsPerReg and numTermsPerReg
[in]encodingthe bitEncoding under which to infer the binary value \(r_j\) from the bits of a sub-register
[in]functionNameCodethe phaseFunc \(f(\vec{r}, \vec{\theta})\)
[in]paramsa list of any additional parameters \(\vec{\theta}\) needed by the phaseFunc functionNameCode
[in]numParamsthe length of list params
[in]overrideIndsa flattened list of sub-register coordinates (values of \(\vec{r}\)) of which to explicit set the phase change
[in]overridePhasesa list of replacement phase changes, for the corresponding \(\vec{r}\) values in overrideInds
[in]numOverridesthe lengths of list overridePhases (but not necessarily of overrideInds)
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits has an invalid index (i.e. does not satisfy 0 <= qubit < qureg.numQubitsRepresented)
  • if the elements of qubits are not unique (including if sub-registers overlap)
  • if numRegs <= 0 or numRegs > 100 (constrained by MAX_NUM_REGS_APPLY_ARBITRARY_PHASE in QuEST_precision.h)
  • if encoding is not a valid bitEncoding
  • if the size of any sub-register is incompatible with encoding (e.g. contains fewer than two qubits in encoding = TWOS_COMPLEMENT)
  • if functionNameCode is not a valid phaseFunc
  • if numParams is incompatible with functionNameCode (for example, no parameters were passed to SCALED_PRODUCT)
  • if any value in overrideInds is not producible by its corresponding sub-register under the given encoding (e.g. 2 unsigned qubits cannot represent index 9)
  • if numOverrides < 0
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyPauliHamil()

void applyPauliHamil ( Qureg  inQureg,
PauliHamil  hamil,
Qureg  outQureg 
)

Modifies outQureg to be the result of applying PauliHamil (a Hermitian but not necessarily unitary operator) to inQureg.

Note that afterward, outQureg may no longer be normalised and ergo not a state-vector or density matrix. Users must therefore be careful passing outQureg to other QuEST functions which assume normalisation in order to function correctly.

This is merely an encapsulation of applyPauliSum(), which can refer to for elaborated doc.

Letting hamil be expressed as \( \alpha = \sum_i c_i \otimes_j^{N} \hat{\sigma}_{i,j} \) (where \( c_i \in \) hamil.termCoeffs and \( N = \) hamil.numQubits), this function effects \( \alpha | \psi \rangle \) on state-vector \( |\psi\rangle \) and \(\alpha \rho\) (left matrix multiplication) on density matrix \( \rho \).

In theory, inQureg is unchanged though its state is temporarily modified and is reverted by re-applying Paulis (XX=YY=ZZ=I), so may see a change by small numerical errors. The initial state in outQureg is not used.

inQureg and outQureg must both be state-vectors, or both density matrices, of equal dimensions to hamil. inQureg cannot be outQureg.

This function works by applying each Pauli product in hamil to inQureg in turn, and adding the resulting state (weighted by a coefficient in termCoeffs) to the initially-blanked outQureg. Ergo it should scale with the total number of Pauli operators specified (excluding identities), and the qureg dimension.

See also
Parameters
[in]inQuregthe register containing the state which outQureg will be set to, under the action of hamil. inQureg should be unchanged, though may vary slightly due to numerical error.
[in]hamila weighted sum of products of pauli operators
[out]outQuregthe qureg to modify to be the result of applyling hamil to the state in inQureg
Exceptions
invalidQuESTInputError()
  • if any code in hamil.pauliCodes is not a valid Pauli code
  • if numSumTerms <= 0
  • if inQureg is not of the same type and dimensions as outQureg and hamil
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyPauliSum()

void applyPauliSum ( Qureg  inQureg,
enum pauliOpType allPauliCodes,
qreal termCoeffs,
int  numSumTerms,
Qureg  outQureg 
)

Modifies outQureg to be the result of applying the weighted sum of Pauli products (a Hermitian but not necessarily unitary operator) to inQureg.

Note that afterward, outQureg may no longer be normalised and ergo not a state-vector or density matrix. Users must therefore be careful passing outQureg to other QuEST functions which assume normalisation in order to function correctly.

Letting \( \alpha = \sum_i c_i \otimes_j^{N} \hat{\sigma}_{i,j} \) be the operators indicated by allPauliCodes (where \( c_i \in \) termCoeffs and \( N = \) qureg.numQubitsRepresented), this function effects \( \alpha | \psi \rangle \) on state-vector \( |\psi\rangle \) and \(\alpha \rho\) (left matrix multiplication) on density matrix \( \rho \).

allPauliCodes is an array of length numSumTerms*qureg.numQubitsRepresented which specifies which Pauli operators to apply, where 0 = PAULI_I, 1 = PAULI_X, 2 = PAULI_Y, 3 = PAULI_Z. For each sum term, a Pauli operator must be specified for EVERY qubit in qureg; each set of numSumTerms operators will be grouped into a product. termCoeffs is an arrray of length numSumTerms containing the term coefficients. For example, on a 3-qubit state-vector,

int paulis[6] = {PAULI_X, PAULI_I, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z};
qreal coeffs[2] = {1.5, -3.6};
applyPauliSum(inQureg, paulis, coeffs, 2, outQureg);
void applyPauliSum(Qureg inQureg, enum pauliOpType *allPauliCodes, qreal *termCoeffs, int numSumTerms, Qureg outQureg)
Modifies outQureg to be the result of applying the weighted sum of Pauli products (a Hermitian but no...
Definition: QuEST.c:1079
@ PAULI_Z
Definition: QuEST.h:113
@ PAULI_Y
Definition: QuEST.h:113
@ PAULI_I
Definition: QuEST.h:113
@ PAULI_X
Definition: QuEST.h:113

will apply Hermitian operation \( (1.5 X I I - 3.6 X Y Z) \) (where in this notation, the left-most operator applies to the least-significant qubit, i.e. that with index 0).

In theory, inQureg is unchanged though its state is temporarily modified and is reverted by re-applying Paulis (XX=YY=ZZ=I), so may see a change by small numerical errors. The initial state in outQureg is not used.

inQureg and outQureg must both be state-vectors, or both density matrices, of equal dimensions. inQureg cannot be outQureg.

This function works by applying each Pauli product to inQureg in turn, and adding the resulting state (weighted by a coefficient in termCoeffs) to the initially-blanked outQureg. Ergo it should scale with the total number of Pauli operators specified (excluding identities), and the qureg dimension.

See also
Parameters
[in]inQuregthe register containing the state which outQureg will be set to, under the action of the Hermitiain operator specified by the Pauli codes. inQureg should be unchanged, though may vary slightly due to numerical error.
[in]allPauliCodesa list of the Pauli codes (0=PAULI_I, 1=PAULI_X, 2=PAULI_Y, 3=PAULI_Z) of all Paulis involved in the products of terms. A Pauli must be specified for each qubit in the register, in every term of the sum.
[in]termCoeffsThe coefficients of each term in the sum of Pauli products
[in]numSumTermsThe total number of Pauli products specified
[out]outQuregthe qureg to modify to be the result of applyling the weighted Pauli sum operator to the state in inQureg
Exceptions
invalidQuESTInputError()
  • if any code in allPauliCodes is not in {0,1,2,3}
  • if numSumTerms <= 0
  • if inQureg is not of the same type and dimensions as outQureg
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyPhaseFunc()

void applyPhaseFunc ( Qureg  qureg,
int *  qubits,
int  numQubits,
enum bitEncoding  encoding,
qreal coeffs,
qreal exponents,
int  numTerms 
)

Induces a phase change upon each amplitude of qureg, determined by the passed exponential polynomial "phase function".

This effects a diagonal unitary of unit complex scalars, targeting the nominated qubits.

  • Arguments coeffs and exponents together specify a real exponential polynomial \(f(r)\) with numTerms terms, of the form

    \[ f(r) = \sum\limits_{i}^{\text{numTerms}} \text{coeffs}[i] \; r^{\, \text{exponents}[i]}\,, \]

    where both coeffs and exponents can be negative, positive and fractional. For example,
    qreal coeffs[] = {1, -3.14};
    qreal exponents[] = {2, -5.5};
    int numTerms = 2;
    constitutes the function

    \[ f(r) = 1 \, r^2 - 3.14 \, r^{-5.5}. \]

    Note you cannot use fractional exponents with encoding = TWOS_COMPLEMENT, since the negative indices would generate (illegal) complex phases, and must be overriden with applyPhaseFuncOverrides().

    ‍If your function \(f(r)\) diverges at one or more \(r\) values, you must instead use applyPhaseFuncOverrides() and specify explicit phase changes for these values. Otherwise, the corresponding amplitudes of the state-vector will become indeterminate (like NaN). Note that use of any negative exponent will result in divergences at \(r=0\).

  • The function \(f(r)\) specifies the phase change to induce upon amplitude \(\alpha\) of computational basis state with index \(r\), such that

    \[ \alpha \, |r\rangle \rightarrow \, \exp(i f(r)) \; \alpha \, |r\rangle. \]

    The index \(r\) associated with each computational basis state is determined by the binary value of the specified qubits (ordered least to most significant), interpreted under the given bitEncoding encoding.

    For example, under encoding = UNSIGNED and qubits = {0,1},

    \[ \begin{aligned} |0\mathbf{00}\rangle & \rightarrow \, e^{i f(0)}\,|0\mathbf{00}\rangle \\ |0\mathbf{01}\rangle & \rightarrow \, e^{i f(1)}\,|0\mathbf{01}\rangle \\ |0\mathbf{10}\rangle & \rightarrow \, e^{i f(2)}\,|0\mathbf{10}\rangle \\ |0\mathbf{11}\rangle & \rightarrow \, e^{i f(3)}\,|0\mathbf{11}\rangle \\ |1\mathbf{00}\rangle & \rightarrow \, e^{i f(0)}\,|1\mathbf{00}\rangle \\ |1\mathbf{01}\rangle & \rightarrow \, e^{i f(1)}\,|1\mathbf{01}\rangle \\ |1\mathbf{10}\rangle & \rightarrow \, e^{i f(2)}\,|1\mathbf{10}\rangle \\ |1\mathbf{11}\rangle & \rightarrow \, e^{i f(3)}\,|1\mathbf{11}\rangle \end{aligned} \]

  • If qureg is a density matrix \(\rho\), this function modifies qureg to

    \[ \rho \rightarrow \hat{D} \, \rho \, \hat{D}^\dagger \]

    where \(\hat{D}\) is the diagonal unitary operator

    \[ \hat{D} = \text{diag} \, \{ \; e^{i f(r_0)}, \; e^{i f(r_1)}, \; \dots \; \}. \]

    This means element \(\rho_{jk}\) is modified to

    \[ \alpha \, |j\rangle\langle k| \; \rightarrow \; e^{i (f(r_j) - f(r_k))} \; \alpha \, |j\rangle\langle k| \]


  • The interpreted phase function can be previewed in the QASM log, as a comment.
    For example:
    applyPhaseFunc(qureg, ...);
    void applyPhaseFunc(Qureg qureg, int *qubits, int numQubits, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int numTerms)
    Induces a phase change upon each amplitude of qureg, determined by the passed exponential polynomial ...
    Definition: QuEST.c:734
    may show
    // Here, applyPhaseFunc() multiplied a complex scalar of the form
    // exp(i (1 x^3))
    // upon every substate |x>, informed by qubits (under an unsigned binary encoding)
    // {4, 1, 2, 0}

‍This function may become numerically imprecise for quickly growing phase functions which admit very large phases, for example of 10^10.

See also
Parameters
[in,out]quregthe state-vector or density matrix to be modified
[in]qubitsa list of the indices of the qubits which will inform \(r\) for each amplitude in qureg
[in]numQubitsthe length of list qubits
[in]encodingthe bitEncoding under which to infer the binary value \(r\) from the bits of qubits in each basis state of qureg
[in]coeffsthe coefficients of the exponential polynomial phase function \(f(r)\)
[in]exponentsthe exponents of the exponential polynomial phase function \(f(r)\)
[in]numTermsthe length of list coeffs, which must be the same as that of exponents
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits has an invalid index (i.e. does not satisfy 0 <= qubit < qureg.numQubitsRepresented)
  • if the elements of qubits are not unique
  • if numQubits < 0 or numQubits >= qureg.numQubitsRepresented
  • if encoding is not a valid bitEncoding
  • if encoding is not compatible with numQubits (e.g. TWOS_COMPLEMENT with only 1 qubit)
  • if exponents contains a fractional number despite encoding = TWOS_COMPLEMENT (you must instead use applyPhaseFuncOverrides() and override all negative indices)
  • if exponents contains a negative power (you must instead use applyPhaseFuncOverrides() and override the zero index)
  • if numTerms <= 0
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyPhaseFuncOverrides()

void applyPhaseFuncOverrides ( Qureg  qureg,
int *  qubits,
int  numQubits,
enum bitEncoding  encoding,
qreal coeffs,
qreal exponents,
int  numTerms,
long long int *  overrideInds,
qreal overridePhases,
int  numOverrides 
)

Induces a phase change upon each amplitude of qureg, determined by the passed exponential polynomial "phase function", and an explicit set of 'overriding' values at specific state indices.

See applyPhaseFunc() first for a full description.

  • As in applyPhaseFunc(), the arguments coeffs and exponents specify a phase function \(f(r)\), where \(r\) is determined by qubits and encoding for each basis state of qureg.

  • Additionally, overrideInds is a list of length numOverrides which specifies the values of \(r\) for which to explicitly set the induced phase change.
    The overriding phase changes are specified in the corresponding elements of overridePhases.

    For example,
    int qubits[] = {0,1};
    enum bitEncoding encoding = UNSIGNED;
    long long int overrideInds[] = {2};
    qreal overridePhases[] = {M_PI};
    void applyPhaseFuncOverrides(Qureg qureg, int *qubits, int numQubits, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int numTerms, long long int *overrideInds, qreal *overridePhases, int numOverrides)
    Induces a phase change upon each amplitude of qureg, determined by the passed exponential polynomial ...
    Definition: QuEST.c:751
    bitEncoding
    Flags for specifying how the bits in sub-register computational basis states are mapped to indices in...
    Definition: QuEST.h:288
    @ UNSIGNED
    Definition: QuEST.h:288
    would effect the same diagonal unitary of applyPhaseFunc(), except that all instance of \(f(r=2)\) are overriden with phase \(\pi\).
    I.e.

    \[ \begin{aligned} |0\mathbf{00}\rangle & \rightarrow \, e^{i f(0)}\,|0\mathbf{00}\rangle \\ |0\mathbf{01}\rangle & \rightarrow \, e^{i f(1)}\,|0\mathbf{01}\rangle \\ |0\mathbf{10}\rangle & \rightarrow \, e^{i \pi} \hspace{12pt} |0\mathbf{10}\rangle \\ |0\mathbf{11}\rangle & \rightarrow \, e^{i f(3)}\,|0\mathbf{11}\rangle \\ |1\mathbf{00}\rangle & \rightarrow \, e^{i f(0)}\,|1\mathbf{00}\rangle \\ |1\mathbf{01}\rangle & \rightarrow \, e^{i f(1)}\,|1\mathbf{01}\rangle \\ |1\mathbf{10}\rangle & \rightarrow \, e^{i \pi} \hspace{12pt} |1\mathbf{10}\rangle \\ |1\mathbf{11}\rangle & \rightarrow \, e^{i f(3)}\,|1\mathbf{11}\rangle \end{aligned} \]

    Note that if encoding = TWOS_COMPLEMENT, and \(f(r)\) features a fractional exponent, then every negative phase index must be overriden. This is checked and enforced by QuEST's validation, unless there are more than 16 targeted qubits, in which case valid input is assumed (due to an otherwise prohibitive performance overhead).

    ‍Overriding phases are checked at each computational basis state of qureg before evaluating the phase function \(f(r)\), and hence are useful for avoiding singularities or errors at diverging values of \(r\).

  • If qureg is a density matrix \(\rho\), the overrides determine the diagonal unitary matrix \(\hat{D}\), which is then applied to qureg as

    \[ \rho \; \rightarrow \; \hat{D} \, \rho \hat{D}^\dagger. \]

    This means that with overrides \(f(r_j) \rightarrow \theta\) and \(f(r_k) \rightarrow \phi\), element \(\rho_{jk}\) is modified to

    \[ \alpha \, |j\rangle\langle k| \; \rightarrow \; \exp(\, i \, (\theta - \phi) \, ) \; \alpha \, |j\rangle\langle k|. \]


  • The interpreted phase function and list of overrides can be previewed in the QASM log, as a comment.
    For example: may show
    // Here, applyPhaseFunc() multiplied a complex scalar of the form
    // exp(i (0.3 x^(-5) + 4 x^1 + 1 x^3))
    // upon every substate |x>, informed by qubits (under a two's complement binary encoding)
    // {4, 1, 2, 0}
    // though with overrides
    // |0> -> exp(i 3.14159)
    // |1> -> exp(i (-3.14159))
    // |2> -> exp(i 0)

See also
Parameters
[in,out]quregthe state-vector or density matrix to be modified
[in]qubitsa list of the indices of the qubits which will inform \(r\) for each amplitude in qureg
[in]numQubitsthe length of list qubits
[in]encodingthe bitEncoding under which to infer the binary value \(r\) from the bits of qubits in each basis state of qureg
[in]coeffsthe coefficients of the exponential polynomial phase function \(f(r)\)
[in]exponentsthe exponents of the exponential polynomial phase function \(f(r)\)
[in]numTermsthe length of list coeffs, which must be the same as that of exponents
[in]overrideIndsa list of sub-state indices (values of \(r\)) of which to explicit set the phase change
[in]overridePhasesa list of replacement phase changes, for the corresponding \(r\) values in overrideInds (one to one)
[in]numOverridesthe lengths of lists overrideInds and overridePhases
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits has an invalid index (i.e. does not satisfy 0 <= qubit < qureg.numQubitsRepresented)
  • if the elements of qubits are not unique
  • if numQubits < 0 or numQubits >= qureg.numQubitsRepresented
  • if encoding is not a valid bitEncoding
  • if encoding is not compatible with numQubits (i.e. TWOS_COMPLEMENT with 1 qubit)
  • if numTerms <= 0
  • if any value in overrideInds is not producible by qubits under the given encoding (e.g. 2 unsigned qubits cannot represent index 9)
  • if numOverrides < 0
  • if exponents contains a negative power and the (consequently diverging) zero index is not contained in overrideInds
  • if encoding is TWOS_COMPLEMENT, and exponents contains a fractional number, but overrideInds does not contain every possible negative index (checked only up to 16 targeted qubits)
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyProjector()

void applyProjector ( Qureg  qureg,
int  qubit,
int  outcome 
)

Force the target qubit of qureg into the given classical outcome, via a non-renormalising projection.

This function zeroes all amplitudes in the state-vector or density-matrix which correspond to the opposite outcome given. Unlike collapseToOutcome(), it does not thereafter normalise qureg, and hence may leave it in a non-physical state.

Note there is no requirement that the outcome state has a non-zero proability, and hence this function may leave qureg in a blank state, like that produced by initBlankState().

See also
Parameters
[in,out]qurega state-vector or density matrix to modify
[in]qubitthe qubit to which to apply the projector
[in]outcomethe single-qubit outcome (0 or 1) to project qubit into
Exceptions
invalidQuESTInputError()
  • if qubit is outside [0, qureg.numQubitsRepresented)
  • if outcome is not in {0,1}
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyQFT()

void applyQFT ( Qureg  qureg,
int *  qubits,
int  numQubits 
)

Applies the quantum Fourier transform (QFT) to a specific subset of qubits of the register qureg.

The order of qubits affects the ultimate unitary. The canonical full-state QFT (applyFullQFT()) is achieved by targeting every qubit in increasing order.

The effected unitary circuit (shown here for numQubits = 4) resembles

though is performed more efficiently.

  • If qureg is a state-vector, the output amplitudes are a kronecker product of the discrete Fourier transform (DFT) acting upon the targeted amplitudes, and the remaining.
    Precisely,
    • let \(|x,r\rangle\) represent a computational basis state where \(x\) is the binary value of the targeted qubits, and \(r\) is the binary value of the remaining qubits.
    • let \(|x_j,r_j\rangle\) be the \(j\text{th}\) such state.
    • let \(n =\) numQubits, and \(N =\) qureg.numQubitsRepresented.
      Then, this function effects

      \[ (\text{QFT}\otimes 1) \, \left( \sum\limits_{j=0}^{2^N-1} \alpha_j \, |x_j,r_j\rangle \right) = \frac{1}{\sqrt{2^n}} \sum\limits_{j=0}^{2^N-1} \alpha_j \left( \sum\limits_{y=0}^{2^n-1} e^{2 \pi \, i \, x_j \, y / 2^n} \; |y,r_j \rangle \right) \]

  • If qureg is a density matrix \(\rho\), it will be changed under the unitary action of the QFT. This can be imagined as each mixed state-vector undergoing the DFT on its amplitudes. This is true even if qureg is unnormalised.

    \[ \rho \; \rightarrow \; \text{QFT} \; \rho \; \text{QFT}^{\dagger} \]

‍This function merges contiguous controlled-phase gates into single invocations of applyNamedPhaseFunc(), and hence is significantly faster than performing the QFT circuit directly.

Furthermore, in distributed mode, this function requires only \(\log_2(\text{\#nodes})\) rounds of pair-wise communication, and hence is exponentially faster than directly performing the DFT on the amplitudes of qureg.

See also
Parameters
[in,out]qurega state-vector or density matrix to modify
[in]qubitsa list of the qubits to operate the QFT upon
[in]numQubitsthe length of list qubits
Exceptions
invalidQuESTInputError()
  • if any qubit in qubits is invalid, i.e. outside [0, qureg.numQubitsRepresented)
  • if qubits contain any repetitions
  • if numQubits < 1
  • if numQubits >qureg.numQubitsRepresented
segmentation-fault
  • if qubits contains fewer elements than numQubits
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applySubDiagonalOp()

void applySubDiagonalOp ( Qureg  qureg,
int *  targets,
int  numTargets,
SubDiagonalOp  op 
)

Left-apply a many-qubit a diagonal matrix upon a specific set of qubits of a quantum register.

This is similar to applyGateSubDiagonalOp(), except that here, the operator op is only left multiplied onto density matrices.

Let \(\hat{D}\) denote the operator op. Precisely, this function effects

\[ |\psi\rangle \rightarrow \hat{D}_{\text{targets}} |\psi\rangle \]

upon state-vectors \(|\psi\rangle\), and

\[ \rho \rightarrow \hat{D}_{\text{targets}} \; \rho \]

upon density matrices \(\rho\), imposing no numerical conditions (like unitarity) upon op.

‍To apply op as if it were unitary, use applyGateSubDiagonalOp() (or use diagonalUnitary() to explicitly check/enforce unitarity).

‍To apply a full-Hilbert diagonal operator which must ergo itself be distributed, use applyDiagonalOp()

See also
Parameters
[in,out]quregthe Qureg instance to operate upon
[in]targetsthe list of target qubit indices
[in]numTargetsthe length of list targets, which must match the dimension of op
[in]opa SubDiagonalOp with any complex elements
Exceptions
invalidQuESTInputError()
  • if numTargets does not match the size of op
  • if numTargets is invalid (<0 or larger than qureg)
  • if numTargets contains an invalid qubit index, or a repetition
Author
Tyson Jones

Referenced by TEST_CASE().

◆ applyTrotterCircuit()

void applyTrotterCircuit ( Qureg  qureg,
PauliHamil  hamil,
qreal  time,
int  order,
int  reps 
)

Applies a trotterisation of unitary evolution \( \exp(-i \, \text{hamil} \, \text{time}) \) to qureg.

This is a sequence of unitary operators, effected by multiRotatePauli(), which together approximate the action of full unitary-time evolution under the given Hamiltonian.

Notate \( \text{hamil} = \sum_j^N c_j \, \hat \sigma_j \) where \(c_j\) is a real coefficient in hamil, \(\hat \sigma_j\) is the corresponding product of Pauli operators, of which there are a total \(N\). Then, order=1 performs first-order Trotterisation, whereby

\[ \exp(-i \, \text{hamil} \, \text{time}) \approx \prod\limits^{\text{reps}} \prod\limits_{j=1}^{N} \exp(-i \, c_j \, \text{time} \, \hat\sigma_j / \text{reps}) \]

order=2 performs the lowest order "symmetrized" Suzuki decomposition, whereby

\[ \exp(-i \, \text{hamil} \, \text{time}) \approx \prod\limits^{\text{reps}} \left[ \prod\limits_{j=1}^{N} \exp(-i \, c_j \, \text{time} \, \hat\sigma_j / (2 \, \text{reps})) \prod\limits_{j=N}^{1} \exp(-i \, c_j \, \text{time} \, \hat\sigma_j / (2 \, \text{reps})) \right] \]

Greater even values of order specify higher-order symmetrized decompositions \( S[\text{time}, \text{order}, \text{reps}] \) which satisfy

\[ S[\text{time}, \text{order}, 1] = \left( \prod\limits^2 S[p \, \text{time}, \text{order}-2, 1] \right) S[ (1-4p)\,\text{time}, \text{order}-2, 1] \left( \prod\limits^2 S[p \, \text{time}, \text{order}-2, 1] \right) \]

and

\[ S[\text{time}, \text{order}, \text{reps}] = \prod\limits^{\text{reps}} S[\text{time}/\text{reps}, \text{order}, 1] \]

where \( p = \left( 4 - 4^{1/(\text{order}-1)} \right)^{-1} \).

These formulations are taken from 'Finding Exponential Product Formulas of Higher Orders', Naomichi Hatano and Masuo Suzuki (2005) (arXiv).

Note that the applied Trotter circuit is captured by QASM, if QASM logging is enabled on qureg.
For example:

applyTrotterCircuit(qureg, hamil, 1, 2, 1);
void applyTrotterCircuit(Qureg qureg, PauliHamil hamil, qreal time, int order, int reps)
Applies a trotterisation of unitary evolution to qureg.
Definition: QuEST.c:1101

may show

// Beginning of Trotter circuit (time 1, order 2, 1 repetitions).
// Here, a multiRotatePauli with angle 0.5 and paulis X Y I was applied.
// Here, a multiRotatePauli with angle -0.5 and paulis I Z X was applied.
// Here, a multiRotatePauli with angle -0.5 and paulis I Z X was applied.
// Here, a multiRotatePauli with angle 0.5 and paulis X Y I was applied.
// End of Trotter circuit


See also
Parameters
[in,out]quregthe register to modify under the approximate unitary-time evolution
[in]hamilthe hamiltonian under which to approxiamte unitary-time evolution
[in]timethe target evolution time, which is permitted to be both positive and negative.
[in]orderthe order of Trotter-Suzuki decomposition to use. Higher orders (necessarily even) are more accurate but prescribe an exponentially increasing number of gates.
[in]repsthe number of repetitions of the decomposition of the given order. This improves the accuracy but prescribes a linearly increasing number of gates.
Exceptions
invalidQuESTInputError()
  • if qureg.numQubitsRepresented != hamil.numQubits
  • if hamil contains invalid parameters or Pauli codes,
  • if order is not in {1, 2, 4, 6, ...}
  • or if reps <= 0
Author
Tyson Jones

Referenced by TEST_CASE().