Skip to content

Commit

Permalink
QUnit buffer debug (#361)
Browse files Browse the repository at this point in the history
* #357: identified new bug

* Simplifying unit test

* #357: removing phase/invert buffer composition

* #357: Isolating new bug

* #357: Simplifying unit test

* Refactor

* Reverting and optimizing

* Always only either ctrl or anti

* Rever CTRL_AND_ANTI inverts on phase buffering
  • Loading branch information
WrathfulSpatula authored May 25, 2020
1 parent 39f78d4 commit 7cca595
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 50 deletions.
12 changes: 10 additions & 2 deletions include/qunit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ class QEngineShard : public ParallelFor {
protected:
void OptimizeBuffer(ShardToPhaseMap& localMap, GetBufferFn remoteMapGet, AddAnglesFn phaseFn, bool makeThisControl)
{
if (IsInvert()) {
return;
}

PhaseShardPtr buffer;
QEngineShardPtr partner;

Expand All @@ -315,7 +319,8 @@ class QEngineShard : public ParallelFor {
buffer = phaseShard->second;
partner = phaseShard->first;

if (buffer->isInvert || (isPlusMinus != partner->isPlusMinus) || !IS_ARG_0(buffer->cmplxDiff)) {
if (buffer->isInvert || (isPlusMinus != partner->isPlusMinus) || !IS_ARG_0(buffer->cmplxDiff) ||
partner->IsInvert()) {
continue;
}

Expand Down Expand Up @@ -519,6 +524,7 @@ class QEngineShard : public ParallelFor {
if (buffer->isInvert) {
buffer->cmplxDiff = -buffer->cmplxSame;
buffer->isInvert = false;
} else {
}
} else {
if (buffer->isInvert) {
Expand Down Expand Up @@ -578,6 +584,8 @@ class QEngineShard : public ParallelFor {
return false;
}

bool IsInvert() { return IsInvertTarget() || IsInvertControl(); }

bool operator==(const QEngineShard& rhs) { return (mapped == rhs.mapped) && (unit == rhs.unit); }
bool operator!=(const QEngineShard& rhs) { return (mapped != rhs.mapped) || (unit != rhs.unit); }
};
Expand Down Expand Up @@ -923,7 +931,7 @@ class QUnit : public QInterface {
void RevertBasis2Qb(const bitLenInt& i, const RevertExclusivity& exclusivity = INVERT_AND_PHASE,
const RevertControl& controlExclusivity = CONTROLS_AND_TARGETS,
const RevertAnti& antiExclusivity = CTRL_AND_ANTI, std::set<bitLenInt> exceptControlling = {},
std::set<bitLenInt> exceptTargetedBy = {}, const bool& dumpSkipped = false);
std::set<bitLenInt> exceptTargetedBy = {}, const bool& dumpSkipped = false, const bool& skipOptimized = false);

void Flush0Eigenstate(const bitLenInt& i)
{
Expand Down
88 changes: 40 additions & 48 deletions src/qunit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1341,9 +1341,8 @@ void QUnit::CZ(bitLenInt control, bitLenInt target)

TransformBasis1Qb(false, control);

RevertBasis2Qb(control, ONLY_INVERT, CONTROLS_AND_TARGETS, ONLY_CTRL, { target }, {});
RevertBasis2Qb(target, ONLY_INVERT, CONTROLS_AND_TARGETS, ONLY_CTRL, {}, { control });
RevertBasis2Qb(control, ONLY_INVERT, ONLY_TARGETS, ONLY_ANTI);
RevertBasis2Qb(control, ONLY_INVERT, CONTROLS_AND_TARGETS, CTRL_AND_ANTI, { target }, {});
RevertBasis2Qb(target, ONLY_INVERT, CONTROLS_AND_TARGETS, CTRL_AND_ANTI, {}, { control });

shards[target].AddPhaseAngles(&(shards[control]), ONE_CMPLX, -ONE_CMPLX);
return;
Expand Down Expand Up @@ -1636,14 +1635,8 @@ void QUnit::ApplyControlledSinglePhase(const bitLenInt* cControls, const bitLenI

TransformBasis1Qb(false, control);

RevertBasis2Qb(control, ONLY_INVERT, CONTROLS_AND_TARGETS, ONLY_CTRL, { target }, {});
RevertBasis2Qb(target, ONLY_INVERT, CONTROLS_AND_TARGETS, ONLY_CTRL, {}, { control });
if (!IS_ARG_0(bottomRight)) {
RevertBasis2Qb(control, ONLY_INVERT, ONLY_TARGETS, ONLY_ANTI);
}
if (!IS_ARG_0(topLeft)) {
RevertBasis2Qb(target, ONLY_INVERT, ONLY_CONTROLS, ONLY_ANTI);
}
RevertBasis2Qb(control, ONLY_INVERT, CONTROLS_AND_TARGETS, CTRL_AND_ANTI, { target }, {});
RevertBasis2Qb(target, ONLY_INVERT, CONTROLS_AND_TARGETS, CTRL_AND_ANTI, {}, { control });

shards[target].AddPhaseAngles(&(shards[control]), topLeft, bottomRight);
delete[] controls;
Expand Down Expand Up @@ -1720,14 +1713,8 @@ void QUnit::ApplyAntiControlledSinglePhase(const bitLenInt* cControls, const bit

TransformBasis1Qb(false, control);

RevertBasis2Qb(control, ONLY_INVERT, CONTROLS_AND_TARGETS, ONLY_ANTI, { target }, {});
RevertBasis2Qb(target, ONLY_INVERT, CONTROLS_AND_TARGETS, ONLY_ANTI, {}, { control });
if (!IS_ARG_0(topLeft)) {
RevertBasis2Qb(control, ONLY_INVERT, ONLY_TARGETS, ONLY_CTRL);
}
if (!IS_ARG_0(bottomRight)) {
RevertBasis2Qb(target, ONLY_INVERT, ONLY_CONTROLS, ONLY_CTRL);
}
RevertBasis2Qb(control, ONLY_INVERT, CONTROLS_AND_TARGETS, CTRL_AND_ANTI, { target }, {});
RevertBasis2Qb(target, ONLY_INVERT, CONTROLS_AND_TARGETS, CTRL_AND_ANTI, {}, { control });

shards[target].AddAntiPhaseAngles(&(shards[control]), bottomRight, topLeft);
delete[] controls;
Expand Down Expand Up @@ -3259,7 +3246,7 @@ void QUnit::ApplyBufferMap(const bitLenInt& bitIndex, ShardToPhaseMap bufferMap,

void QUnit::RevertBasis2Qb(const bitLenInt& i, const RevertExclusivity& exclusivity,
const RevertControl& controlExclusivity, const RevertAnti& antiExclusivity, std::set<bitLenInt> exceptControlling,
std::set<bitLenInt> exceptTargetedBy, const bool& dumpSkipped)
std::set<bitLenInt> exceptTargetedBy, const bool& dumpSkipped, const bool& skipOptimize)
{
QEngineShard& shard = shards[i];

Expand All @@ -3271,14 +3258,14 @@ void QUnit::RevertBasis2Qb(const bitLenInt& i, const RevertExclusivity& exclusiv

shard.CombineGates();

if ((controlExclusivity == ONLY_CONTROLS) && (exclusivity != ONLY_INVERT)) {
if (!skipOptimize && (controlExclusivity == ONLY_CONTROLS) && (exclusivity != ONLY_INVERT)) {
if (antiExclusivity != ONLY_ANTI) {
shard.OptimizeControls();
}
if (antiExclusivity != ONLY_CTRL) {
shard.OptimizeAntiControls();
}
} else if ((controlExclusivity == ONLY_TARGETS) && (exclusivity != ONLY_INVERT)) {
} else if (!skipOptimize && (controlExclusivity == ONLY_TARGETS) && (exclusivity != ONLY_INVERT)) {
if (antiExclusivity != ONLY_ANTI) {
shard.OptimizeTargets();
}
Expand Down Expand Up @@ -3310,7 +3297,7 @@ void QUnit::RevertBasis2Qb(const bitLenInt& i, const RevertExclusivity& exclusiv

void QUnit::CommuteH(const bitLenInt& bitIndex)
{
RevertBasis2Qb(bitIndex, INVERT_AND_PHASE, ONLY_CONTROLS);
RevertBasis2Qb(bitIndex, INVERT_AND_PHASE, ONLY_CONTROLS, CTRL_AND_ANTI, {}, {}, false, true);

QEngineShard& shard = shards[bitIndex];

Expand Down Expand Up @@ -3372,39 +3359,44 @@ void QUnit::CommuteH(const bitLenInt& bitIndex)
}
}

// TODO: Should be able to commute these:
if (anyInvert || anyAntiInvert) {
if (shard.targetOfShards.size() >= shard.antiTargetOfShards.size()) {
RevertBasis2Qb(bitIndex, INVERT_AND_PHASE, CONTROLS_AND_TARGETS, ONLY_ANTI);
} else {
RevertBasis2Qb(bitIndex, INVERT_AND_PHASE, CONTROLS_AND_TARGETS, ONLY_CTRL);
if (shard.targetOfShards.size() > 1U || shard.antiTargetOfShards.size() > 0U) {
targetOfShards = shard.targetOfShards;
for (phaseShard = targetOfShards.begin(); phaseShard != targetOfShards.end(); phaseShard++) {
buffer = phaseShard->second;

if (phaseShard->second->isInvert != anyInvert ||
(anyInvert && norm(polarDiff + polarSame) <= ampThreshold)) {
partner = phaseShard->first;
control = FindShardIndex(*partner);

ApplyBuffer(phaseShard, control, bitIndex, false);
shard.RemovePhaseControl(partner);
}
}
}

targetOfShards = shard.targetOfShards;
for (phaseShard = targetOfShards.begin(); phaseShard != targetOfShards.end(); phaseShard++) {
buffer = phaseShard->second;
if (shard.antiTargetOfShards.size() > 1U || shard.targetOfShards.size() > 0U) {
targetOfShards = shard.antiTargetOfShards;
for (phaseShard = targetOfShards.begin(); phaseShard != targetOfShards.end(); phaseShard++) {
buffer = phaseShard->second;

if (phaseShard->second->isInvert != anyInvert || (anyInvert && norm(polarDiff + polarSame) <= ampThreshold)) {
partner = phaseShard->first;
control = FindShardIndex(*partner);
if (phaseShard->second->isInvert != anyAntiInvert ||
(anyAntiInvert && norm(polarDiff + polarSame) <= ampThreshold)) {
partner = phaseShard->first;
control = FindShardIndex(*partner);

ApplyBuffer(phaseShard, control, bitIndex, false);
shard.RemovePhaseControl(partner);
ApplyBuffer(phaseShard, control, bitIndex, true);
shard.RemovePhaseAntiControl(partner);
}
}
}

targetOfShards = shard.antiTargetOfShards;
for (phaseShard = targetOfShards.begin(); phaseShard != targetOfShards.end(); phaseShard++) {
buffer = phaseShard->second;

if (phaseShard->second->isInvert != anyAntiInvert ||
(anyAntiInvert && norm(polarDiff + polarSame) <= ampThreshold)) {
partner = phaseShard->first;
control = FindShardIndex(*partner);

ApplyBuffer(phaseShard, control, bitIndex, true);
shard.RemovePhaseAntiControl(partner);
// TODO: Should be able to commute these:
if (anyInvert != anyAntiInvert) {
if (shard.targetOfShards.size() >= shard.antiTargetOfShards.size()) {
RevertBasis2Qb(bitIndex, INVERT_AND_PHASE, CONTROLS_AND_TARGETS, ONLY_ANTI);
} else {
RevertBasis2Qb(bitIndex, INVERT_AND_PHASE, CONTROLS_AND_TARGETS, ONLY_CTRL);
}
}

Expand Down
141 changes: 141 additions & 0 deletions test/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4730,6 +4730,100 @@ TEST_CASE_METHOD(QInterfaceTestFixture, "test_inversion_buffers")
}
crossEntropy = ONE_R1 - sqrt(crossEntropy) / 10000;
REQUIRE(crossEntropy > 0.97);

qftReg->SetPermutation(0);
qftReg->H(0, 5);
qftReg->CZ(1, 2);
qftReg->CZ(0, 4);
qftReg->X(1);
qftReg->H(2);
qftReg->CZ(3, 4);
qftReg->CZ(0, 2);
qftReg->H(0);
qftReg->H(3);
testCaseResult = qftReg->MultiShotMeasureMask(qPowers, 8, 10000);

goldStandard->SetPermutation(0);
goldStandard->H(0, 5);
goldStandard->CZ(1, 2);
goldStandard->CZ(0, 4);
goldStandard->X(1);
goldStandard->H(2);
goldStandard->CZ(3, 4);
goldStandard->CZ(0, 2);
goldStandard->H(0);
goldStandard->H(3);
goldStandardResult = goldStandard->MultiShotMeasureMask(qPowers, 8, 10000);

crossEntropy = ZERO_R1;
for (int perm = 0; perm < 256; perm++) {
measurementBin = goldStandardResult.find(perm);
if (measurementBin == goldStandardResult.end()) {
goldBinResult = 0;
} else {
goldBinResult = measurementBin->second;
}

measurementBin = testCaseResult.find(perm);
if (measurementBin == testCaseResult.end()) {
testBinResult = 0;
} else {
testBinResult = measurementBin->second;
}
crossEntropy += (testBinResult - goldBinResult) * (testBinResult - goldBinResult);
}
if (crossEntropy < ZERO_R1) {
crossEntropy = ZERO_R1;
}
crossEntropy = ONE_R1 - sqrt(crossEntropy) / 10000;
REQUIRE(crossEntropy > 0.97);

qftReg->SetPermutation(0);
qftReg->H(0, 4);
qftReg->CZ(0, 3);
qftReg->CZ(1, 2);
qftReg->H(2);
qftReg->CZ(1, 0);
qftReg->CZ(2, 3);
qftReg->H(1);
qftReg->CZ(0, 1);
qftReg->H(0, 4);
testCaseResult = qftReg->MultiShotMeasureMask(qPowers, 8, 10000);

goldStandard->SetPermutation(0);
goldStandard->H(0, 4);
goldStandard->CZ(0, 3);
goldStandard->CZ(1, 2);
goldStandard->H(2);
goldStandard->CZ(1, 0);
goldStandard->CZ(2, 3);
goldStandard->H(1);
goldStandard->CZ(0, 1);
goldStandard->H(0, 4);
goldStandardResult = goldStandard->MultiShotMeasureMask(qPowers, 8, 10000);

crossEntropy = ZERO_R1;
for (int perm = 0; perm < 256; perm++) {
measurementBin = goldStandardResult.find(perm);
if (measurementBin == goldStandardResult.end()) {
goldBinResult = 0;
} else {
goldBinResult = measurementBin->second;
}

measurementBin = testCaseResult.find(perm);
if (measurementBin == testCaseResult.end()) {
testBinResult = 0;
} else {
testBinResult = measurementBin->second;
}
crossEntropy += (testBinResult - goldBinResult) * (testBinResult - goldBinResult);
}
if (crossEntropy < ZERO_R1) {
crossEntropy = ZERO_R1;
}
crossEntropy = ONE_R1 - sqrt(crossEntropy) / 10000;
REQUIRE(crossEntropy > 0.97);
}

bitLenInt pickRandomBit(QInterfacePtr qReg, std::set<bitLenInt>* unusedBitsPtr)
Expand Down Expand Up @@ -4911,6 +5005,53 @@ TEST_CASE("test_universal_circuit_digital_cross_entropy", "[supreme]")
crossEntropy = ZERO_R1;
}
crossEntropy = ONE_R1 - sqrt(crossEntropy) / ITERATIONS;

if (crossEntropy <= 0.97) {
for (d = 0; d < Depth; d++) {
std::vector<int>& layer1QbRands = gate1QbRands[d];
for (i = 0; i < layer1QbRands.size(); i++) {
int gate1Qb = layer1QbRands[i];
if (gate1Qb == 0) {
std::cout << "qftReg->H(" << (int)i << ");" << std::endl;
// testCase->H(i);
} else if (gate1Qb == 1) {
std::cout << "qftReg->X(" << (int)i << ");" << std::endl;
// testCase->X(i);
} else if (gate1Qb == 2) {
std::cout << "qftReg->Y(" << (int)i << ");" << std::endl;
// testCase->Y(i);
} else if (gate1Qb == 3) {
std::cout << "qftReg->T(" << (int)i << ");" << std::endl;
// testCase->T(i);
} else {
// Identity test
}
}

std::vector<MultiQubitGate>& layerMultiQbRands = gateMultiQbRands[d];
for (i = 0; i < layerMultiQbRands.size(); i++) {
MultiQubitGate multiGate = layerMultiQbRands[i];
if (multiGate.gate == 0) {
std::cout << "qftReg->Swap(" << (int)multiGate.b1 << "," << (int)multiGate.b2 << ");"
<< std::endl;
// testCase->Swap(multiGate.b1, multiGate.b2);
} else if (multiGate.gate == 1) {
std::cout << "qftReg->CZ(" << (int)multiGate.b1 << "," << (int)multiGate.b2 << ");"
<< std::endl;
// testCase->CZ(multiGate.b1, multiGate.b2);
} else if (multiGate.gate == 2) {
std::cout << "qftReg->CNOT(" << (int)multiGate.b1 << "," << (int)multiGate.b2 << ");"
<< std::endl;
// testCase->CNOT(multiGate.b1, multiGate.b2);
} else {
std::cout << "qftReg->CCNOT(" << (int)multiGate.b1 << "," << (int)multiGate.b2 << ","
<< (int)multiGate.b3 << ");" << std::endl;
// testCase->CCNOT(multiGate.b1, multiGate.b2, multiGate.b3);
}
}
}
}

REQUIRE(crossEntropy > 0.97);
}
}
Expand Down

0 comments on commit 7cca595

Please sign in to comment.