Skip to content

Commit

Permalink
Double-eigenvalue perm and float expectation methods
Browse files Browse the repository at this point in the history
  • Loading branch information
WrathfulSpatula committed Jul 31, 2023
1 parent f18ddcb commit af00abd
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 86 deletions.
16 changes: 16 additions & 0 deletions include/pinvoke_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,22 @@ MICROSOFT_QUANTUM_DECL double FactorizedExpectation(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, uintq* c);
MICROSOFT_QUANTUM_DECL double FactorizedExpectationRdm(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, uintq* c, _In_ bool r);
#if FPPOW < 6
MICROSOFT_QUANTUM_DECL double FactorizedExpectationFp(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, float* c);
MICROSOFT_QUANTUM_DECL double FactorizedExpectationFpRdm(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, float* c, _In_ bool r);
#elif FPPOW < 7
MICROSOFT_QUANTUM_DECL double FactorizedExpectationFp(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, double* c);
MICROSOFT_QUANTUM_DECL double FactorizedExpectationFpRdm(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, double* c, _In_ bool r);
#else
MICROSOFT_QUANTUM_DECL double FactorizedExpectationFp(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, boost::multiprecision::float128* c);
MICROSOFT_QUANTUM_DECL double FactorizedExpectationFpRdm(_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q,
_In_ uintq m, boost::multiprecision::float128* c, _In_ bool r);
#endif

MICROSOFT_QUANTUM_DECL void DumpIds(_In_ uintq sid, _In_ IdCallback callback);
MICROSOFT_QUANTUM_DECL void Dump(_In_ uintq sid, _In_ ProbAmpCallback callback);
Expand Down
26 changes: 26 additions & 0 deletions include/qinterface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2396,6 +2396,32 @@ class QInterface : public ParallelFor {
return ExpectationBitsFactorized(bits, perms, offset);
}

/**
* Get expectation value of bits, given a (floating-point) array of qubit weights
*
* The weighter-per-qubit expectation value of is returned, with each "bits" entry corresponding to a "weights"
* entry.
*
* \warning PSEUDO-QUANTUM
*/
virtual real1_f ExpectationFloatsFactorized(
const std::vector<bitLenInt>& bits, const std::vector<real1_f>& weights);

/**
* Get (reduced density matrix) expectation value of bits, given a (floating-point) array of qubit weights
*
* The weighter-per-qubit expectation value of is returned, with each "bits" entry corresponding to a "weights"
* entry. If there are stabilizer ancillae, they are traced out of the reduced density matrix, giving an approximate
* result.
*
* \warning PSEUDO-QUANTUM
*/
virtual real1_f ExpectationFloatsFactorizedRdm(
bool roundRz, const std::vector<bitLenInt>& bits, const std::vector<real1_f>& weights)
{
return ExpectationFloatsFactorized(bits, weights);
}

/**
* Direct measure of bit probability to be in |1> state, treating all ancillary qubits as post-selected T gate
* gadgets
Expand Down
10 changes: 9 additions & 1 deletion include/qstabilizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,12 @@ class QStabilizer : public QInterface {
void setBasisProb(const real1_f& nrm, real1* outputProbs);

/// Returns the (partial) expectation value from a state vector amplitude.
real1_f getExpectation(const real1_f& nrm, const std::vector<bitCapInt>& bitPowers, bitCapInt offset);
real1_f getExpectation(const real1_f& nrm, const std::vector<bitCapInt>& bitPowers,
const std::vector<bitCapInt>& perms, bitCapInt offset);

/// Returns the (partial) expectation value from a state vector amplitude.
real1_f getExpectation(
const real1_f& nrm, const std::vector<bitCapInt>& bitPowers, const std::vector<real1_f>& weights);

void DecomposeDispose(const bitLenInt start, const bitLenInt length, QStabilizerPtr toCopy);

Expand Down Expand Up @@ -282,6 +287,9 @@ class QStabilizer : public QInterface {
real1_f ExpectationBitsFactorized(
const std::vector<bitLenInt>& bits, const std::vector<bitCapInt>& perms, bitCapInt offset = 0U);

/// Get expectation qubits, interpreting each permutation as a floating-point value.
real1_f ExpectationFloatsFactorized(const std::vector<bitLenInt>& bits, const std::vector<real1_f>& weights);

/// Under assumption of a QStabilizerHybrid ancillary buffer, trace out the permutation probability
/// of the reduced density matrx without ancillae.
real1_f ProbPermRdm(bitCapInt perm, bitLenInt ancillaeStart);
Expand Down
37 changes: 26 additions & 11 deletions include/qstabilizerhybrid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,26 @@ class QStabilizerHybrid : public QParity, public QInterface {
}
void RdmCloneFlush(real1_f threshold = FP_NORM_EPSILON);

real1_f ExpectationFactorized(bool isFloat, const std::vector<bitLenInt>& bits, const std::vector<bitCapInt>& perms,
const std::vector<real1_f>& weights, bitCapInt offset, bool roundRz)
{
if (engine) {
return isFloat ? engine->ExpectationFloatsFactorizedRdm(roundRz, bits, weights)
: engine->ExpectationBitsFactorizedRdm(roundRz, bits, perms, offset);
;
}

CombineAncillae();

if (!roundRz) {
return isFloat ? stabilizer->ExpectationFloatsFactorizedRdm(roundRz, bits, weights)
: stabilizer->ExpectationBitsFactorizedRdm(roundRz, bits, perms, offset);
}

return isFloat ? RdmCloneHelper()->stabilizer->ExpectationFloatsFactorizedRdm(roundRz, bits, weights)
: RdmCloneHelper()->stabilizer->ExpectationBitsFactorizedRdm(roundRz, bits, perms, offset);
}

real1_f ApproxCompareHelper(
QStabilizerHybridPtr toCompare, bool isDiscreteBool, real1_f error_tol = TRYDECOMPOSE_EPSILON);

Expand Down Expand Up @@ -746,17 +766,12 @@ class QStabilizerHybrid : public QParity, public QInterface {
real1_f ExpectationBitsFactorizedRdm(
bool roundRz, const std::vector<bitLenInt>& bits, const std::vector<bitCapInt>& perms, bitCapInt offset = 0U)
{
if (engine) {
return engine->ExpectationBitsFactorizedRdm(roundRz, bits, perms, offset);
}

CombineAncillae();

if (!roundRz) {
return stabilizer->ExpectationBitsFactorized(bits, perms, offset);
}

return RdmCloneHelper()->stabilizer->ExpectationBitsFactorized(bits, perms, offset);
return ExpectationFactorized(false, bits, perms, std::vector<real1_f>(), offset, roundRz);
}
real1_f ExpectationFloatsFactorizedRdm(
bool roundRz, const std::vector<bitLenInt>& bits, const std::vector<real1_f>& weights)
{
return ExpectationFactorized(true, bits, std::vector<bitCapInt>(), weights, 0U, roundRz);
}

bool TrySeparate(bitLenInt qubit);
Expand Down
66 changes: 30 additions & 36 deletions include/qunit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,46 +401,12 @@ class QUnit : public QParity, public QInterface {
virtual real1_f ExpectationBitsFactorized(
const std::vector<bitLenInt>& bits, const std::vector<bitCapInt>& perms, bitCapInt offset = 0U)
{
if (perms.size() < bits.size()) {
throw std::invalid_argument(
"QUnit::ExpectationBitsFactorized() must supply at least as many 'perms' as bits!");
}

ThrowIfQbIdArrayIsBad(bits, qubitCount,
"QUnit::ExpectationBitsAll parameter qubits vector values must be within allocated qubit bounds!");

if (shards[0U].unit && (shards[0U].unit->GetQubitCount() == qubitCount)) {
OrderContiguous(shards[0U].unit);
return shards[0U].unit->ExpectationBitsFactorized(bits, perms, offset);
}

QUnitPtr clone = std::dynamic_pointer_cast<QUnit>(Clone());
QInterfacePtr unit = clone->EntangleAll(true);
clone->OrderContiguous(unit);

return unit->ExpectationBitsFactorized(bits, perms, offset);
return ExpectationFactorized(false, false, bits, perms, std::vector<real1_f>(), offset, false);
}
virtual real1_f ExpectationBitsFactorizedRdm(
bool roundRz, const std::vector<bitLenInt>& bits, const std::vector<bitCapInt>& perms, bitCapInt offset = 0U)
{
if (perms.size() < bits.size()) {
throw std::invalid_argument(
"QUnit::ExpectationBitsFactorized() must supply at least as many 'perms' as bits!");
}

ThrowIfQbIdArrayIsBad(bits, qubitCount,
"QUnit::ExpectationBitsAllRdm parameter qubits vector values must be within allocated qubit bounds!");

if (shards[0U].unit && (shards[0U].unit->GetQubitCount() == qubitCount)) {
OrderContiguous(shards[0U].unit);
return shards[0U].unit->ExpectationBitsFactorizedRdm(roundRz, bits, perms, offset);
}

QUnitPtr clone = std::dynamic_pointer_cast<QUnit>(Clone());
QInterfacePtr unit = clone->EntangleAll(true);
clone->OrderContiguous(unit);

return unit->ExpectationBitsFactorizedRdm(roundRz, bits, perms, offset);
return ExpectationFactorized(true, false, bits, perms, std::vector<real1_f>(), offset, roundRz);
}
virtual void UpdateRunningNorm(real1_f norm_thresh = REAL1_DEFAULT_ARG);
virtual void NormalizeState(
Expand Down Expand Up @@ -510,6 +476,34 @@ class QUnit : public QParity, public QInterface {
bitCapInt GetIndexedEigenstate(bitLenInt start, bitLenInt length, const unsigned char* values);
#endif

real1_f ExpectationFactorized(bool isRdm, bool isFloat, const std::vector<bitLenInt>& bits,
const std::vector<bitCapInt>& perms, const std::vector<real1_f>& weights, bitCapInt offset, bool roundRz)
{
if ((isFloat && (weights.size() < bits.size())) || (!isFloat && (perms.size() < bits.size()))) {
throw std::invalid_argument("QUnit::ExpectationFactorized() must supply at least as many weights as bits!");
}

ThrowIfQbIdArrayIsBad(bits, qubitCount,
"QUnit::ExpectationFactorized parameter qubits vector values must be within allocated qubit bounds!");

if (shards[0U].unit && (shards[0U].unit->GetQubitCount() == qubitCount)) {
OrderContiguous(shards[0U].unit);
return isFloat ? (isRdm ? shards[0U].unit->ExpectationFloatsFactorizedRdm(roundRz, bits, weights)
: shards[0U].unit->ExpectationFloatsFactorized(bits, weights))
: (isRdm ? shards[0U].unit->ExpectationBitsFactorizedRdm(roundRz, bits, perms, offset)
: shards[0U].unit->ExpectationBitsFactorized(bits, perms, offset));
}

QUnitPtr clone = std::dynamic_pointer_cast<QUnit>(Clone());
QInterfacePtr unit = clone->EntangleAll(true);
clone->OrderContiguous(unit);

return isFloat ? (isRdm ? unit->ExpectationFloatsFactorizedRdm(roundRz, bits, weights)
: unit->ExpectationFloatsFactorized(bits, weights))
: (isRdm ? unit->ExpectationBitsFactorizedRdm(roundRz, bits, perms, offset)
: unit->ExpectationBitsFactorized(bits, perms, offset));
}

virtual QInterfacePtr Entangle(std::vector<bitLenInt> bits);
virtual QInterfacePtr Entangle(std::vector<bitLenInt*> bits);
virtual QInterfacePtr EntangleRange(bitLenInt start, bitLenInt length, bool isForProb = false);
Expand Down
2 changes: 2 additions & 0 deletions include/qunitclifford.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ class QUnitClifford : public QInterface {
real1_f ExpectationBitsFactorized(
const std::vector<bitLenInt>& bits, const std::vector<bitCapInt>& perms, bitCapInt offset = 0U);

real1_f ExpectationFloatsFactorized(const std::vector<bitLenInt>& bits, const std::vector<real1_f>& weights);

real1_f ProbPermRdm(bitCapInt perm, bitLenInt ancillaeStart);

real1_f ProbMask(bitCapInt mask, bitCapInt permutation);
Expand Down
64 changes: 48 additions & 16 deletions src/pinvoke_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2405,7 +2405,7 @@ MICROSOFT_QUANTUM_DECL double PermutationExpectationRdm(_In_ uintq sid, _In_ uin
return _PermutationExpectation(sid, n, q, r, true);
}

double _FactorizedExpectation(uintq sid, uintq n, uintq* q, uintq m, uintq* c, bool r, bool isRdm)
double _FactorizedExpectation(uintq sid, uintq n, uintq* q, uintq m, uintq* c, real1_f* f, bool r, bool isRdm)
{
SIMULATOR_LOCK_GUARD_DOUBLE(sid)

Expand All @@ -2416,25 +2416,38 @@ double _FactorizedExpectation(uintq sid, uintq n, uintq* q, uintq m, uintq* c, b
}

std::vector<bitCapInt> _c;
_c.reserve(n);
if (c) {
_c.reserve(n);
#if QBCAPPOW < 7
for (uintq i = 0U; i < n; ++i) {
_c.push_back(c[i]);
}
for (uintq i = 0U; i < n; ++i) {
_c.push_back(c[i]);
}
#else
for (uintq i = 0U; i < n; ++i) {
bitCapInt perm = 0U;
for (uintq j = 0U; j < m; ++j) {
perm <<= 64U;
perm |= c[i * m + j];
for (uintq i = 0U; i < n; ++i) {
bitCapInt perm = 0U;
for (uintq j = 0U; j < m; ++j) {
perm <<= 64U;
perm |= c[i * m + j];
}
_c.push_back(perm);
}
_c.push_back(perm);
}
#endif
}

std::vector<real1_f> _f;
if (f) {
const uintq n2 = n << 1U;
_f.reserve(n2);
for (uintq i = 0U; i < n2; ++i) {
_f.push_back(_f[i]);
}
}

try {
return isRdm ? (double)simulator->ExpectationBitsFactorizedRdm(r, _q, _c)
: (double)simulator->ExpectationBitsFactorized(_q, _c);
return c ? isRdm ? (double)simulator->ExpectationBitsFactorizedRdm(r, _q, _c)
: (double)simulator->ExpectationBitsFactorized(_q, _c)
: isRdm ? (double)simulator->ExpectationFloatsFactorizedRdm(r, _q, _f)
: (double)simulator->ExpectationFloatsFactorized(_q, _f);
} catch (const std::exception& ex) {
simulatorErrors[sid] = 1;
std::cout << ex.what() << std::endl;
Expand All @@ -2448,7 +2461,7 @@ double _FactorizedExpectation(uintq sid, uintq n, uintq* q, uintq m, uintq* c, b
MICROSOFT_QUANTUM_DECL double FactorizedExpectation(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, uintq* c)
{
return _FactorizedExpectation(sid, n, q, m, c, false, false);
return _FactorizedExpectation(sid, n, q, m, c, NULL, false, false);
}

/**
Expand All @@ -2458,7 +2471,26 @@ MICROSOFT_QUANTUM_DECL double FactorizedExpectation(
MICROSOFT_QUANTUM_DECL double FactorizedExpectationRdm(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, uintq* c, _In_ bool r)
{
return _FactorizedExpectation(sid, n, q, m, c, r, true);
return _FactorizedExpectation(sid, n, q, m, c, NULL, r, true);
}

/**
* (External API) Get the permutation expectation value, based upon the order of input qubits.
*/
MICROSOFT_QUANTUM_DECL double FactorizedExpectationFp(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, real1_f* c)
{
return _FactorizedExpectation(sid, n, q, m, NULL, c, false, false);
}

/**
* (External API) Get the permutation expectation value, based upon the order of input qubits, treating all ancillary
* qubits as post-selected T gate gadgets.
*/
MICROSOFT_QUANTUM_DECL double FactorizedExpectationFpRdm(
_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* q, _In_ uintq m, real1_f* c, _In_ bool r)
{
return _FactorizedExpectation(sid, n, q, m, NULL, c, r, true);
}

MICROSOFT_QUANTUM_DECL void QFT(_In_ uintq sid, _In_ uintq n, _In_reads_(n) uintq* c)
Expand Down
Loading

0 comments on commit af00abd

Please sign in to comment.