Skip to content

Commit

Permalink
added inv-shifted-weighted-distance phase function
Browse files Browse the repository at this point in the history
tested with 1, 16 threads, GPU, 1-2 nodes
  • Loading branch information
TysonRayJones committed Jul 11, 2023
1 parent ceaeb7b commit ce6bded
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 22 deletions.
22 changes: 18 additions & 4 deletions QuEST/include/QuEST.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ typedef struct Vector
* - \p INVERSE_DISTANCE maps state \f$|x_1\rangle|x_2\rangle|y_1\rangle|y_2\rangle\dots\f$ to \f$1/\sqrt{(x_1-x_2)^2 + (y_1-y_2)^2 + \dots}\f$
* - \p SCALED_INVERSE_DISTANCE maps state \f$|x_1\rangle|x_2\rangle|y_1\rangle|y_2\rangle\dots\f$ to \f$\text{coeff}/\sqrt{(x_1-x_2)^2 + (y_1-y_2)^2 + \dots}\f$
* - \p SCALED_INVERSE_SHIFTED_DISTANCE maps state \f$|x_1\rangle|x_2\rangle|y_1\rangle|y_2\rangle\dots\f$ to \f$\text{coeff}/\sqrt{(x_1-x_2-\Delta_x)^2 + (y_1-y_2-\Delta_y)^2 + \dots}\f$
* - \p SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE maps state \f$|x_1\rangle|x_2\rangle|y_1\rangle|y_2\rangle\dots\f$ to \f$\text{coeff}/\sqrt{f_x \, (x_1-x_2-\Delta_x)^2 + f_y \; (y_1-y_2-\Delta_y)^2 + \dots}\f$
*
* @ingroup type
* @author Tyson Jones
Expand All @@ -231,7 +232,8 @@ typedef struct Vector
enum phaseFunc {
NORM=0, SCALED_NORM=1, INVERSE_NORM=2, SCALED_INVERSE_NORM=3, SCALED_INVERSE_SHIFTED_NORM=4,
PRODUCT=5, SCALED_PRODUCT=6, INVERSE_PRODUCT=7, SCALED_INVERSE_PRODUCT=8,
DISTANCE=9, SCALED_DISTANCE=10, INVERSE_DISTANCE=11, SCALED_INVERSE_DISTANCE=12, SCALED_INVERSE_SHIFTED_DISTANCE=13};
DISTANCE=9, SCALED_DISTANCE=10, INVERSE_DISTANCE=11, SCALED_INVERSE_DISTANCE=12, SCALED_INVERSE_SHIFTED_DISTANCE=13, SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE=14
};

/** Flags for specifying how the bits in sub-register computational basis states
* are mapped to indices in functions like applyPhaseFunc().
Expand Down Expand Up @@ -6816,7 +6818,7 @@ void applyNamedPhaseFuncOverrides(Qureg qureg, int* qubits, int* numQubitsPerReg
* > divergence parameter whenever the denominator is smaller than (or equal to)
* > machine precision `REAL_EPS`.
*
* - Functions allowing the shifting of sub-register values, which are \p SCALED_INVERSE_SHIFTED_NORM
* - Functions allowing the shifting of unweighted sub-register values, which are \p SCALED_INVERSE_SHIFTED_NORM,
* and \p SCALED_INVERSE_SHIFTED_DISTANCE, need these shift values to be passed in the \p params
* argument _after_ the scaling and divergence override parameters listed above. The function
* \p SCALED_INVERSE_SHIFTED_NORM needs as many extra parameters, as there are sub-registers;
Expand Down Expand Up @@ -6848,8 +6850,20 @@ void applyNamedPhaseFuncOverrides(Qureg qureg, int* qubits, int* numQubitsPerReg
* 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}.
* \f]
*
* > You can further override \f$f(\vec{r}, \vec{\theta})\f$ at one or more \f$\vec{r}\f$ values
* > via applyParamNamedPhaseFuncOverrides().
* - Function \p SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE, which effects phase
* \f[
* \text{coeff}/\sqrt{f_x \, (x_1-x_2-\Delta_x)^2 + f_y \; (y_1-y_2-\Delta_y)^2 + \dots}
* \f]
* (and phase \f$\phi\f$ at divergences)
* accepts parameters in the following order:
* \f[
* \{ \; \text{coeff}, \; \phi, \; f_x, \; \Delta x, \; f_y, \; \Delta y, \; \dots \; \}
* \f]
* > Note that where the denominator's \f$\text{sqrt}\f$ argument would be negative (and the resulting
* > phase function _complex_), the phase is instead set to the divergence parameter \f$\phi\f$.
*
* > You can further override \f$f(\vec{r}, \vec{\theta})\f$ at one or more \f$\vec{r}\f$ values
* > via applyParamNamedPhaseFuncOverrides().
*
* - The interpreted parameterised phase function can be previewed in the QASM log, as a comment. \n
* For example:
Expand Down
13 changes: 11 additions & 2 deletions QuEST/src/CPU/QuEST_cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4594,16 +4594,25 @@ void statevec_applyParamNamedPhaseFuncOverrides(
// compute Euclidean distance related phases
else if (phaseFuncName == DISTANCE || phaseFuncName == INVERSE_DISTANCE ||
phaseFuncName == SCALED_DISTANCE || phaseFuncName == SCALED_INVERSE_DISTANCE ||
phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE) {
phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE) {

dist = 0;
if (phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE) {
for (r=0; r<numRegs; r+=2)
dist += (phaseInds[r] - phaseInds[r+1] - params[2+r/2])*(phaseInds[r] - phaseInds[r+1] - params[2+r/2]);
}
else if (phaseFuncName == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE) {
for (r=0; r<numRegs; r+=2)
dist += params[2+r] * (phaseInds[r] - phaseInds[r+1] - params[2+r+1])*(phaseInds[r] - phaseInds[r+1] - params[2+r+1]);
}
else
for (r=0; r<numRegs; r+=2)
dist += (phaseInds[r+1] - phaseInds[r])*(phaseInds[r+1] - phaseInds[r]);

// if sqrt() arg would be negative, set it to divergence param
if (dist < 0)
dist = 0;

dist = sqrt(dist);

if (phaseFuncName == DISTANCE)
Expand All @@ -4612,7 +4621,7 @@ void statevec_applyParamNamedPhaseFuncOverrides(
phase = (dist == 0.)? params[0] : 1/dist; // smallest non-zero dist is 1
else if (phaseFuncName == SCALED_DISTANCE)
phase = params[0] * dist;
else if (phaseFuncName == SCALED_INVERSE_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE)
else if (phaseFuncName == SCALED_INVERSE_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE)
phase = (dist <= REAL_EPS)? params[1] : params[0] / dist; // unless shifted closer to 0
}
}
Expand Down
14 changes: 12 additions & 2 deletions QuEST/src/GPU/QuEST_gpu.cu
Original file line number Diff line number Diff line change
Expand Up @@ -3929,7 +3929,7 @@ __global__ void statevec_applyParamNamedPhaseFuncOverridesKernel(
// compute Euclidean distance related phases
else if (phaseFuncName == DISTANCE || phaseFuncName == INVERSE_DISTANCE ||
phaseFuncName == SCALED_DISTANCE || phaseFuncName == SCALED_INVERSE_DISTANCE ||
phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE) {
phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE) {

qreal dist = 0;
if (phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE) {
Expand All @@ -3938,11 +3938,21 @@ __global__ void statevec_applyParamNamedPhaseFuncOverridesKernel(
dist += dif*dif;
}
}
else if (phaseFuncName == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE) {
for (int r=0; r<numRegs; r+=2) {
qreal dif = (phaseInds[r*stride+offset] - phaseInds[(r+1)*stride+offset] - params[2+r+1]);
dist += params[2+r] * dif*dif;
}
}
else
for (int r=0; r<numRegs; r+=2) {
qreal dif = (phaseInds[(r+1)*stride+offset] - phaseInds[r*stride+offset]);
dist += dif*dif;
}

// if sqrt() arg would be negative, set it to divergence param
if (dist < 0)
dist = 0;
dist = sqrt(dist);

if (phaseFuncName == DISTANCE)
Expand All @@ -3951,7 +3961,7 @@ __global__ void statevec_applyParamNamedPhaseFuncOverridesKernel(
phase = (dist == 0.)? params[0] : 1/dist; // smallest non-zero dist is 1
else if (phaseFuncName == SCALED_DISTANCE)
phase = params[0] * dist;
else if (phaseFuncName == SCALED_INVERSE_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE)
else if (phaseFuncName == SCALED_INVERSE_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_DISTANCE || phaseFuncName == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE)
phase = (dist <= REAL_EPS)? params[1] : params[0] / dist; // unless shifted closer
}
}
Expand Down
25 changes: 15 additions & 10 deletions QuEST/src/QuEST_validation.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,15 @@ static const char* errorMessages[] = {
[E_INVALID_NUM_PHASE_FUNC_OVERRIDES] = "Invalid number of phase function overrides specified. Must be >=0, and for single-variable phase functions, <=2^numQubits (the maximum unique binary values of the sub-register). Note that uniqueness of overriding indices is not checked.",
[E_INVALID_PHASE_FUNC_OVERRIDE_UNSIGNED_INDEX] = "Invalid phase function override index, in the UNSIGNED encoding. Must be >=0, and <= the maximum index possible of the corresponding qubit subregister (2^numQubits-1).",
[E_INVALID_PHASE_FUNC_OVERRIDE_TWOS_COMPLEMENT_INDEX] = "Invalid phase function override index, in the TWOS_COMPLEMENT encoding. Must be between (inclusive) -2^(N-1) and +2^(N-1)-1, where N is the number of qubits (including the sign qubit).",
[E_INVALID_PHASE_FUNC_NAME] = "Invalid named phase function, which must be one of {NORM, SCALED_NORM, INVERSE_NORM, SCALED_INVERSE_NORM, PRODUCT, SCALED_PRODUCT, INVERSE_PRODUCT, SCALED_INVERSE_PRODUCT, DISTANCE, SCALED_DISTANCE, INVERSE_DISTANCE, SCALED_INVERSE_DISTANCE}.",
[E_INVALID_NUM_NAMED_PHASE_FUNC_PARAMS] = "Invalid number of parameters passed for the given named phase function. {NORM, PRODUCT, DISTANCE} accept 0 parameters, {INVERSE_NORM, INVERSE_PRODUCT, INVERSE_DISTANCE} accept 1 parameter (the phase at the divergence), {SCALED_NORM, SCALED_INVERSE_NORM, SCALED_PRODUCT} accept 1 parameter (the scaling coefficient), {SCALED_INVERSE_PRODUCT, SCALED_DISTANCE, SCALED_INVERSE_DISTANCE} accept 2 parameters (the coefficient then divergence phase), SCALED_INVERSE_SHIFTED_NORM accepts 2 + (number of sub-registers) parameters (the coefficient, then the divergence phase, followed by the offset for each sub-register), SCALED_INVERSE_SHIFTED_DISTANCE accepts 2 + (number of sub-registers) / 2 parameters (the coefficient, then the divergence phase, followed by the offset for each pair of sub-registers).",
[E_INVALID_PHASE_FUNC_NAME] = "Invalid named phase function, which must be one of {NORM, SCALED_NORM, INVERSE_NORM, SCALED_INVERSE_NORM, SCALED_INVERSE_SHIFTED_NORM, PRODUCT, SCALED_PRODUCT, INVERSE_PRODUCT, SCALED_INVERSE_PRODUCT, DISTANCE, SCALED_DISTANCE, INVERSE_DISTANCE, SCALED_INVERSE_DISTANCE, SCALED_INVERSE_SHIFTED_DISTANCE, SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE}.",
[E_INVALID_NUM_NAMED_PHASE_FUNC_PARAMS] = "Invalid number of parameters passed for the given named phase function. {NORM, PRODUCT, DISTANCE} accept 0 parameters, {INVERSE_NORM, INVERSE_PRODUCT, INVERSE_DISTANCE} accept 1 parameter (the phase at the divergence), {SCALED_NORM, SCALED_INVERSE_NORM, SCALED_PRODUCT} accept 1 parameter (the scaling coefficient), {SCALED_INVERSE_PRODUCT, SCALED_DISTANCE, SCALED_INVERSE_DISTANCE} accept 2 parameters (the coefficient then divergence phase), SCALED_INVERSE_SHIFTED_NORM accepts 2 + (number of sub-registers) parameters (the coefficient, then the divergence phase, followed by the offset for each sub-register), SCALED_INVERSE_SHIFTED_DISTANCE accepts 2 + (number of sub-registers) / 2 parameters (the coefficient, then the divergence phase, followed by the offset for each pair of sub-registers), SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE accepts 2 + (number of sub-registers) parameters (the coefficient, then the divergence phase, followed by the factor and offset for each pair of sub-registers).",
[E_INVALID_BIT_ENCODING] = "Invalid bit encoding. Must be one of {UNSIGNED, TWOS_COMPLEMENT}.",
[E_INVALID_NUM_QUBITS_TWOS_COMPLEMENT] = "A sub-register contained too few qubits to employ TWOS_COMPLEMENT encoding. Must use >1 qubits (allocating one for the sign).",
[E_NEGATIVE_EXPONENT_WITHOUT_ZERO_OVERRIDE] = "The phase function contained a negative exponent which would diverge at zero, but the zero index was not overriden.",
[E_FRACTIONAL_EXPONENT_WITHOUT_NEG_OVERRIDE] = "The phase function contained a fractional exponent, which in TWOS_COMPLEMENT encoding, requires all negative indices are overriden. However, one or more negative indices were not overriden.",
[E_NEGATIVE_EXPONENT_MULTI_VAR] = "The phase function contained an illegal negative exponent. One must instead call applyPhaseFuncOverrides() once for each register, so that the zero index of each register is overriden, independent of the indices of all other registers.",
[E_FRACTIONAL_EXPONENT_MULTI_VAR] = "The phase function contained a fractional exponent, which is illegal in TWOS_COMPLEMENT encoding, since it cannot be (efficiently) checked that all negative indices were overriden. One must instead call applyPhaseFuncOverrides() once for each register, so that each register's negative indices can be overriden, independent of the indices of all other registers.",
[E_INVALID_NUM_REGS_DISTANCE_PHASE_FUNC] = "Phase functions DISTANCE, INVERSE_DISTANCE, SCALED_DISTANCE and SCALED_INVERSE_DISTANCE require a strictly even number of sub-registers.",
[E_INVALID_NUM_REGS_DISTANCE_PHASE_FUNC] = "Phase functions DISTANCE, INVERSE_DISTANCE, SCALED_DISTANCE, SCALED_INVERSE_DISTANCE, SCALED_INVERSE_SHIFTED_DISTANCE and SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE require a strictly even number of sub-registers.",
[E_NOT_ENOUGH_ADDRESSABLE_MEMORY] = "Could not allocate memory. Requested more memory than system can address.",
[E_QUREG_NOT_ALLOCATED] = "Could not allocate memory for Qureg. Possibly insufficient memory.",
[E_QUREG_NOT_ALLOCATED_ON_GPU] = "Could not allocate memory for Qureg on GPU. Possibly insufficient memory.",
Expand Down Expand Up @@ -984,9 +984,18 @@ void validatePhaseFuncName(enum phaseFunc funcCode, int numRegs, int numParams,
funcCode == INVERSE_DISTANCE ||
funcCode == SCALED_DISTANCE ||
funcCode == SCALED_INVERSE_DISTANCE ||
funcCode == SCALED_INVERSE_SHIFTED_DISTANCE,
funcCode == SCALED_INVERSE_SHIFTED_DISTANCE ||
funcCode == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE,
E_INVALID_PHASE_FUNC_NAME, caller);

if (funcCode == DISTANCE ||
funcCode == INVERSE_DISTANCE ||
funcCode == SCALED_DISTANCE ||
funcCode == SCALED_INVERSE_DISTANCE ||
funcCode == SCALED_INVERSE_SHIFTED_DISTANCE ||
funcCode == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE)
QuESTAssert(numRegs%2 == 0, E_INVALID_NUM_REGS_DISTANCE_PHASE_FUNC, caller);

if (funcCode == NORM ||
funcCode == PRODUCT ||
funcCode == DISTANCE)
Expand All @@ -1013,12 +1022,8 @@ void validatePhaseFuncName(enum phaseFunc funcCode, int numRegs, int numParams,
if (funcCode == SCALED_INVERSE_SHIFTED_DISTANCE)
QuESTAssert(numParams == 2 + numRegs / 2, E_INVALID_NUM_NAMED_PHASE_FUNC_PARAMS, caller);

if (funcCode == DISTANCE ||
funcCode == INVERSE_DISTANCE ||
funcCode == SCALED_DISTANCE ||
funcCode == SCALED_INVERSE_DISTANCE ||
funcCode == SCALED_INVERSE_SHIFTED_DISTANCE)
QuESTAssert(numRegs%2 == 0, E_INVALID_NUM_REGS_DISTANCE_PHASE_FUNC, caller);
if (funcCode == SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE)
QuESTAssert(numParams == 2 + 2 * (numRegs / 2), E_INVALID_NUM_NAMED_PHASE_FUNC_PARAMS, caller);
}

void validateBitEncoding(int numQubits, enum bitEncoding encoding, const char* caller) {
Expand Down

0 comments on commit ce6bded

Please sign in to comment.