Skip to content

Commit

Permalink
feat: ✨ Dependency/Interaction analysis now also recognises uses of t…
Browse files Browse the repository at this point in the history
…he full register (e.g. `x q` rather than `x q[0]`)
  • Loading branch information
DRovara committed Sep 19, 2024
1 parent f9f15af commit 3e727ce
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 9 deletions.
3 changes: 3 additions & 0 deletions include/backend/dd/DDSimDebug.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,6 @@ bool isSubStateVectorLegal(const Statevector& full,
std::vector<std::vector<Complex>>
getPartialTraceFromStateVector(const Statevector& sv,
const std::vector<size_t>& traceOut);

std::vector<std::string> getTargetVariables(DDSimulationState* ddsim,
size_t instruction);
2 changes: 2 additions & 0 deletions include/common/parsing/Utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ std::string replaceString(std::string str, const std::string& from,
const std::string& to);

std::string removeWhitespace(std::string str);

bool variablesEqual(const std::string& v1, const std::string& v2);
44 changes: 44 additions & 0 deletions src/backend/dd/DDSimDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,50 @@ Result destroyDDSimulationState(DDSimulationState* self) {
}

//-----------------------------------------------------------------------------------------

std::vector<std::string> getTargetVariables(DDSimulationState* ddsim,
size_t instruction) {
std::vector<std::string> result;
const auto& targets = ddsim->targetQubits[instruction];

Check warning on line 861 in src/backend/dd/DDSimDebug.cpp

View workflow job for this annotation

GitHub Actions / 🇨‌ Lint / 🚨 Lint

src/backend/dd/DDSimDebug.cpp:861:15 [clang-diagnostic-unused-variable]

unused variable 'targets'

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable targets is not used.
size_t parentFunction = -1ULL;
size_t i = instruction;
while (true) {
if (ddsim->functionDefinitions.find(i) !=
ddsim->functionDefinitions.end()) {
parentFunction = i;
break;
}
if (ddsim->instructionTypes[i] == RETURN) {
break;
}
i--;
}

const auto parameters = parentFunction != -1ULL
? ddsim->targetQubits[parentFunction]
: std::vector<std::string>{};
for (const auto& target : ddsim->targetQubits[instruction]) {
if (std::find(parameters.begin(), parameters.end(), target) !=
parameters.end()) {
result.push_back(target);
continue;
}
const auto foundRegister =
std::find_if(ddsim->qubitRegisters.begin(), ddsim->qubitRegisters.end(),
[target](const QubitRegisterDefinition& reg) {
return reg.name == target;
});
if (foundRegister != ddsim->qubitRegisters.end()) {
for (size_t j = 0; j < foundRegister->size; j++) {
result.push_back(target + "[" + std::to_string(j) + "]");
}
} else {
result.push_back(target);
}
}
return result;
}

size_t variableToQubit(DDSimulationState* ddsim, const std::string& variable) {
auto declaration = replaceString(variable, " ", "");
declaration = replaceString(declaration, "\t", "");
Expand Down
10 changes: 8 additions & 2 deletions src/backend/dd/DDSimDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ void visitCall(DDSimulationState* ddsim, size_t current, size_t qubitIndex,
}
break;
}
if (checkInstruction == 0) {
break;
}
checkInstruction--;
}
}
Expand Down Expand Up @@ -162,6 +165,9 @@ Result dddiagnosticsGetDataDependencies(Diagnostics* self, size_t instruction,

for (auto dep : ddsim->dataDependencies[current]) {
const auto depInstruction = dep.first;
if (ddsim->instructionTypes[depInstruction] == NOP) {
continue; // We don't want variable declarations as dependencies.
}
if (visited.find(depInstruction) == visited.end()) {
toVisit.insert(depInstruction);
}
Expand Down Expand Up @@ -203,7 +209,7 @@ Result dddiagnosticsGetInteractions(Diagnostics* self, size_t beforeInstruction,
continue;
}

auto& targets = ddsim->targetQubits[i];
auto targets = getTargetVariables(ddsim, i);
std::set<size_t> targetQubits;
for (const auto& target : targets) {
targetQubits.insert(variableToQubitAt(ddsim, target, i).first);
Expand Down Expand Up @@ -411,7 +417,7 @@ Result dddiagnosticsGetZeroControlInstructions(Diagnostics* self,
void dddiagnosticsOnStepForward(DDDiagnostics* diagnostics,
size_t instruction) {
auto* ddsim = diagnostics->simulationState;
const auto& targets = ddsim->targetQubits[instruction];
const auto targets = getTargetVariables(ddsim, instruction);

// Add actual qubits to tracker.
if (ddsim->instructionTypes[instruction] == SIMULATE ||
Expand Down
16 changes: 12 additions & 4 deletions src/common/parsing/CodePreprocessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ bool isClassicControlledGate(const std::string& line) {
(line.find(')') != std::string::npos);
}

bool isVariableDeclation(const std::string& line) {
return startsWith(trim(line), "qreg ") || startsWith(trim(line), "creg ");
}

FunctionDefinition parseFunctionDefinition(const std::string& signature) {
auto parts = splitString(
replaceString(replaceString(signature, "\n", " "), "\t", " "), ' ');
Expand Down Expand Up @@ -304,11 +308,15 @@ preprocessCode(const std::string& code, size_t startIndex,
for (auto& instr : instructions) {
auto vars = parseParameters(instr.code);
size_t idx = instr.lineNumber - 1;
while (!vars.empty() && (instr.lineNumber < instructions.size() ||
idx > instr.lineNumber - instructions.size())) {
while (instr.lineNumber != 0 && !vars.empty() &&
(instr.lineNumber < instructions.size() ||
idx > instr.lineNumber - instructions.size())) {
size_t foundIndex = 0;
for (const auto& var : variableUsages[idx]) {
const auto found = std::find(vars.begin(), vars.end(), var);
const auto found =
std::find_if(vars.begin(), vars.end(), [&var](const auto& v) {
return variablesEqual(v, var);
});
if (found != vars.end()) {
const auto newEnd = std::remove(vars.begin(), vars.end(), var);
vars.erase(newEnd, vars.end());
Expand All @@ -317,7 +325,7 @@ preprocessCode(const std::string& code, size_t startIndex,
}
foundIndex++;
}
if (idx - 1 == instr.lineNumber - instructions.size()) {
if (idx - 1 == instr.lineNumber - instructions.size() || idx == 0) {
break;
}
idx--;
Expand Down
13 changes: 13 additions & 0 deletions src/common/parsing/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,16 @@ std::string removeWhitespace(std::string str) {
str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());
return str;
}

bool variablesEqual(const std::string& v1, const std::string& v2) {
if (v1.find('[') != std::string::npos && v2.find('[') != std::string::npos) {
return v1 == v2;
}
if (v1.find('[') != std::string::npos) {
return variablesEqual(splitString(v1, '[')[0], v2);
}
if (v2.find('[') != std::string::npos) {
return variablesEqual(splitString(v2, '[')[0], v1);
}
return v1 == v2;
}
35 changes: 35 additions & 0 deletions test/test_custom_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,41 @@ TEST_F(CustomCodeTest, LargeProgram) {
ASSERT_EQ(state->getCurrentInstruction(state), 4);
}

TEST_F(CustomCodeTest, CollectiveGateAsDependency) {
loadCode(2, 0, "x q; barrier q[0];");
auto* diagnosis = state->getDiagnostics(state);
std::array<bool, 4> dependencies{};
ASSERT_EQ(
diagnosis->getDataDependencies(diagnosis, 3, false, dependencies.data()),
OK);
ASSERT_EQ(dependencies[0], false);
ASSERT_EQ(dependencies[1], false);
ASSERT_EQ(dependencies[2], true);
ASSERT_EQ(dependencies[3], true);
}

TEST_F(CustomCodeTest, CollectiveGateAsInteraction) {
loadCode(1, 0, "qreg p[1]; cx q, p; assert-ent q[0], p[0];");
ASSERT_EQ(state->runSimulation(state), OK);
ASSERT_TRUE(state->didAssertionFail(state));

auto* diagnosis = state->getDiagnostics(state);

std::array<bool, 2> interactions{};
ASSERT_EQ(diagnosis->getInteractions(diagnosis, 4, 0, interactions.data()),
OK);

ASSERT_TRUE(interactions[0]);
ASSERT_TRUE(interactions[1]);

std::array<ErrorCause, 1> causes{};

Check warning on line 303 in test/test_custom_code.cpp

View workflow job for this annotation

GitHub Actions / 🇨‌ Lint / 🚨 Lint

test/test_custom_code.cpp:303:14 [misc-include-cleaner]

no header providing "ErrorCause" is directly included
ASSERT_EQ(
diagnosis->potentialErrorCauses(diagnosis, causes.data(), causes.size()),
1);
ASSERT_EQ(causes[0].type, ControlAlwaysZero);

Check warning on line 307 in test/test_custom_code.cpp

View workflow job for this annotation

GitHub Actions / 🇨‌ Lint / 🚨 Lint

test/test_custom_code.cpp:307:29 [misc-include-cleaner]

no header providing "ControlAlwaysZero" is directly included
ASSERT_EQ(causes[0].instruction, 3);
}

TEST_F(CustomCodeTest, PaperExampleGrover) {
loadCode(3, 3,
"gate oracle q0, q1, q2, flag {"
Expand Down
3 changes: 0 additions & 3 deletions test/test_diagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ TEST_F(DiagnosticsTest, ZeroControlsWithJumps) {

TEST_F(DiagnosticsTest, DataDependenciesWithJumps) {
loadFromFile("diagnose-with-jumps");
auto* diagnostics = state->getDiagnostics(state);
const std::map<size_t, std::set<size_t>> expected = {
{1, {1}},
{2, {2, 13, 7, 5, 1}},
Expand Down Expand Up @@ -221,7 +220,6 @@ TEST_F(DiagnosticsTest, DataDependenciesWithJumps) {

TEST_F(DiagnosticsTest, InteractionsWithJumps) {
loadFromFile("diagnose-with-jumps");
auto* diagnostics = state->getDiagnostics(state);

const std::map<std::pair<size_t, size_t>, std::set<size_t>> expected = {
{{1, 0}, {0}}, {{1, 1}, {1}}, {{1, 2}, {2}},
Expand Down Expand Up @@ -259,7 +257,6 @@ TEST_F(DiagnosticsTest, RuntimeInteractions) {
ASSERT_TRUE(state->didAssertionFail(state));
ASSERT_EQ(state->getCurrentInstruction(state), 3);

auto* diagnostics = state->getDiagnostics(state);
std::array<ErrorCause, 10> errors{};
ASSERT_EQ(diagnostics->potentialErrorCauses(diagnostics, errors.data(), 10),
1);
Expand Down

0 comments on commit 3e727ce

Please sign in to comment.